Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_reflect/src/func/dynamic_function_internal.rs
6599 views
1
use crate::func::args::ArgCount;
2
use crate::func::signature::{ArgListSignature, ArgumentSignature};
3
use crate::func::{ArgList, FunctionError, FunctionInfo, FunctionOverloadError};
4
use alloc::{borrow::Cow, vec, vec::Vec};
5
use bevy_platform::collections::HashMap;
6
use core::fmt::{Debug, Formatter};
7
8
/// An internal structure for storing a function and its corresponding [function information].
9
///
10
/// This is used to facilitate the sharing of functionality between [`DynamicFunction`]
11
/// and [`DynamicFunctionMut`].
12
///
13
/// [function information]: FunctionInfo
14
/// [`DynamicFunction`]: crate::func::DynamicFunction
15
/// [`DynamicFunctionMut`]: crate::func::DynamicFunctionMut
16
#[derive(Clone)]
17
pub(super) struct DynamicFunctionInternal<F> {
18
functions: Vec<F>,
19
info: FunctionInfo,
20
arg_map: HashMap<ArgumentSignature, usize>,
21
}
22
23
impl<F> DynamicFunctionInternal<F> {
24
/// Create a new instance of [`DynamicFunctionInternal`] with the given function
25
/// and its corresponding information.
26
pub fn new(func: F, info: FunctionInfo) -> Self {
27
let arg_map = info
28
.signatures()
29
.iter()
30
.map(|sig| (ArgumentSignature::from(sig), 0))
31
.collect();
32
33
Self {
34
functions: vec![func],
35
info,
36
arg_map,
37
}
38
}
39
pub fn with_name(mut self, name: impl Into<Cow<'static, str>>) -> Self {
40
self.info = self.info.with_name(Some(name.into()));
41
self
42
}
43
44
/// The name of the function.
45
pub fn name(&self) -> Option<&Cow<'static, str>> {
46
self.info.name()
47
}
48
49
/// Returns `true` if the function is overloaded.
50
pub fn is_overloaded(&self) -> bool {
51
self.info.is_overloaded()
52
}
53
54
/// Get an immutable reference to the function.
55
///
56
/// If the function is not overloaded, it will always be returned regardless of the arguments.
57
/// Otherwise, the function will be selected based on the arguments provided.
58
///
59
/// If no overload matches the provided arguments, returns [`FunctionError::NoOverload`].
60
pub fn get(&self, args: &ArgList) -> Result<&F, FunctionError> {
61
if !self.info.is_overloaded() {
62
return Ok(&self.functions[0]);
63
}
64
65
let signature = ArgListSignature::from(args);
66
self.arg_map
67
.get(&signature)
68
.map(|index| &self.functions[*index])
69
.ok_or_else(|| FunctionError::NoOverload {
70
expected: self.arg_map.keys().cloned().collect(),
71
received: ArgumentSignature::from(args),
72
})
73
}
74
75
/// Get a mutable reference to the function.
76
///
77
/// If the function is not overloaded, it will always be returned regardless of the arguments.
78
/// Otherwise, the function will be selected based on the arguments provided.
79
///
80
/// If no overload matches the provided arguments, returns [`FunctionError::NoOverload`].
81
pub fn get_mut(&mut self, args: &ArgList) -> Result<&mut F, FunctionError> {
82
if !self.info.is_overloaded() {
83
return Ok(&mut self.functions[0]);
84
}
85
86
let signature = ArgListSignature::from(args);
87
self.arg_map
88
.get(&signature)
89
.map(|index| &mut self.functions[*index])
90
.ok_or_else(|| FunctionError::NoOverload {
91
expected: self.arg_map.keys().cloned().collect(),
92
received: ArgumentSignature::from(args),
93
})
94
}
95
96
/// Returns the function information contained in the map.
97
#[inline]
98
pub fn info(&self) -> &FunctionInfo {
99
&self.info
100
}
101
102
/// Returns the number of arguments the function expects.
103
///
104
/// For overloaded functions that can have a variable number of arguments,
105
/// this will contain the full set of counts for all signatures.
106
pub fn arg_count(&self) -> ArgCount {
107
self.info.arg_count()
108
}
109
110
/// Helper method for validating that a given set of arguments are _potentially_ valid for this function.
111
///
112
/// Currently, this validates:
113
/// - The number of arguments is within the expected range
114
pub fn validate_args(&self, args: &ArgList) -> Result<(), FunctionError> {
115
let expected_arg_count = self.arg_count();
116
let received_arg_count = args.len();
117
118
if !expected_arg_count.contains(received_arg_count) {
119
Err(FunctionError::ArgCountMismatch {
120
expected: expected_arg_count,
121
received: received_arg_count,
122
})
123
} else {
124
Ok(())
125
}
126
}
127
128
/// Merge another [`DynamicFunctionInternal`] into this one.
129
///
130
/// If `other` contains any functions with the same signature as this one,
131
/// an error will be returned along with the original, unchanged instance.
132
///
133
/// Therefore, this method should always return an overloaded function if the merge is successful.
134
///
135
/// Additionally, if the merge succeeds, it should be guaranteed that the order
136
/// of the functions in the map will be preserved.
137
/// For example, merging `[func_a, func_b]` (self) with `[func_c, func_d]` (other) should result in
138
/// `[func_a, func_b, func_c, func_d]`.
139
/// And merging `[func_c, func_d]` (self) with `[func_a, func_b]` (other) should result in
140
/// `[func_c, func_d, func_a, func_b]`.
141
pub fn merge(&mut self, mut other: Self) -> Result<(), FunctionOverloadError> {
142
// Keep a separate map of the new indices to avoid mutating the existing one
143
// until we can be sure the merge will be successful.
144
let mut new_signatures = <HashMap<_, _>>::default();
145
146
for (sig, index) in other.arg_map {
147
if self.arg_map.contains_key(&sig) {
148
return Err(FunctionOverloadError::DuplicateSignature(sig));
149
}
150
151
new_signatures.insert(sig, self.functions.len() + index);
152
}
153
154
self.arg_map.reserve(new_signatures.len());
155
for (sig, index) in new_signatures {
156
self.arg_map.insert(sig, index);
157
}
158
159
self.functions.append(&mut other.functions);
160
self.info.extend_unchecked(other.info);
161
162
Ok(())
163
}
164
165
/// Maps the internally stored function(s) from type `F` to type `G`.
166
pub fn map_functions<G>(self, f: fn(F) -> G) -> DynamicFunctionInternal<G> {
167
DynamicFunctionInternal {
168
functions: self.functions.into_iter().map(f).collect(),
169
info: self.info,
170
arg_map: self.arg_map,
171
}
172
}
173
}
174
175
impl<F> Debug for DynamicFunctionInternal<F> {
176
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
177
self.info
178
.pretty_printer()
179
.include_fn_token()
180
.include_name()
181
.fmt(f)
182
}
183
}
184
185
#[cfg(test)]
186
mod tests {
187
use super::*;
188
use crate::func::{FunctionInfo, SignatureInfo};
189
use crate::Type;
190
191
#[test]
192
fn should_merge_single_into_single() {
193
let mut func_a = DynamicFunctionInternal::new(
194
'a',
195
FunctionInfo::new(SignatureInfo::anonymous().with_arg::<i8>("arg0")),
196
);
197
198
let func_b = DynamicFunctionInternal::new(
199
'b',
200
FunctionInfo::new(SignatureInfo::anonymous().with_arg::<u8>("arg0")),
201
);
202
203
func_a.merge(func_b).unwrap();
204
205
assert_eq!(func_a.functions, vec!['a', 'b']);
206
assert_eq!(func_a.info.signatures().len(), 2);
207
assert_eq!(
208
func_a.arg_map,
209
HashMap::from_iter([
210
(ArgumentSignature::from_iter([Type::of::<i8>()]), 0),
211
(ArgumentSignature::from_iter([Type::of::<u8>()]), 1),
212
])
213
);
214
}
215
216
#[test]
217
fn should_merge_single_into_overloaded() {
218
let mut func_a = DynamicFunctionInternal::new(
219
'a',
220
FunctionInfo::new(SignatureInfo::anonymous().with_arg::<i8>("arg0")),
221
);
222
223
let func_b = DynamicFunctionInternal {
224
functions: vec!['b', 'c'],
225
info: FunctionInfo::new(SignatureInfo::anonymous().with_arg::<u8>("arg0"))
226
.with_overload(SignatureInfo::anonymous().with_arg::<u16>("arg0"))
227
.unwrap(),
228
arg_map: HashMap::from_iter([
229
(ArgumentSignature::from_iter([Type::of::<u8>()]), 0),
230
(ArgumentSignature::from_iter([Type::of::<u16>()]), 1),
231
]),
232
};
233
234
func_a.merge(func_b).unwrap();
235
236
assert_eq!(func_a.functions, vec!['a', 'b', 'c']);
237
assert_eq!(func_a.info.signatures().len(), 3);
238
assert_eq!(
239
func_a.arg_map,
240
HashMap::from_iter([
241
(ArgumentSignature::from_iter([Type::of::<i8>()]), 0),
242
(ArgumentSignature::from_iter([Type::of::<u8>()]), 1),
243
(ArgumentSignature::from_iter([Type::of::<u16>()]), 2),
244
])
245
);
246
}
247
248
#[test]
249
fn should_merge_overload_into_single() {
250
let mut func_a = DynamicFunctionInternal {
251
functions: vec!['a', 'b'],
252
info: FunctionInfo::new(SignatureInfo::anonymous().with_arg::<i8>("arg0"))
253
.with_overload(SignatureInfo::anonymous().with_arg::<i16>("arg0"))
254
.unwrap(),
255
arg_map: HashMap::from_iter([
256
(ArgumentSignature::from_iter([Type::of::<i8>()]), 0),
257
(ArgumentSignature::from_iter([Type::of::<i16>()]), 1),
258
]),
259
};
260
261
let func_b = DynamicFunctionInternal::new(
262
'c',
263
FunctionInfo::new(SignatureInfo::anonymous().with_arg::<u8>("arg0")),
264
);
265
266
func_a.merge(func_b).unwrap();
267
268
assert_eq!(func_a.functions, vec!['a', 'b', 'c']);
269
assert_eq!(func_a.info.signatures().len(), 3);
270
assert_eq!(
271
func_a.arg_map,
272
HashMap::from_iter([
273
(ArgumentSignature::from_iter([Type::of::<i8>()]), 0),
274
(ArgumentSignature::from_iter([Type::of::<i16>()]), 1),
275
(ArgumentSignature::from_iter([Type::of::<u8>()]), 2),
276
])
277
);
278
}
279
280
#[test]
281
fn should_merge_overloaded_into_overloaded() {
282
let mut func_a = DynamicFunctionInternal {
283
functions: vec!['a', 'b'],
284
info: FunctionInfo::new(SignatureInfo::anonymous().with_arg::<i8>("arg0"))
285
.with_overload(SignatureInfo::anonymous().with_arg::<i16>("arg0"))
286
.unwrap(),
287
arg_map: HashMap::from_iter([
288
(ArgumentSignature::from_iter([Type::of::<i8>()]), 0),
289
(ArgumentSignature::from_iter([Type::of::<i16>()]), 1),
290
]),
291
};
292
293
let func_b = DynamicFunctionInternal {
294
functions: vec!['c', 'd'],
295
info: FunctionInfo::new(SignatureInfo::anonymous().with_arg::<u8>("arg0"))
296
.with_overload(SignatureInfo::anonymous().with_arg::<u16>("arg0"))
297
.unwrap(),
298
arg_map: HashMap::from_iter([
299
(ArgumentSignature::from_iter([Type::of::<u8>()]), 0),
300
(ArgumentSignature::from_iter([Type::of::<u16>()]), 1),
301
]),
302
};
303
304
func_a.merge(func_b).unwrap();
305
306
assert_eq!(func_a.functions, vec!['a', 'b', 'c', 'd']);
307
assert_eq!(func_a.info.signatures().len(), 4);
308
assert_eq!(
309
func_a.arg_map,
310
HashMap::from_iter([
311
(ArgumentSignature::from_iter([Type::of::<i8>()]), 0),
312
(ArgumentSignature::from_iter([Type::of::<i16>()]), 1),
313
(ArgumentSignature::from_iter([Type::of::<u8>()]), 2),
314
(ArgumentSignature::from_iter([Type::of::<u16>()]), 3),
315
])
316
);
317
}
318
319
#[test]
320
fn should_return_error_on_duplicate_signature() {
321
let mut func_a = DynamicFunctionInternal::new(
322
'a',
323
FunctionInfo::new(
324
SignatureInfo::anonymous()
325
.with_arg::<i8>("arg0")
326
.with_arg::<i16>("arg1"),
327
),
328
);
329
330
let func_b = DynamicFunctionInternal {
331
functions: vec!['b', 'c'],
332
info: FunctionInfo::new(
333
SignatureInfo::anonymous()
334
.with_arg::<u8>("arg0")
335
.with_arg::<u16>("arg1"),
336
)
337
.with_overload(
338
SignatureInfo::anonymous()
339
.with_arg::<i8>("arg0")
340
.with_arg::<i16>("arg1"),
341
)
342
.unwrap(),
343
arg_map: HashMap::from_iter([
344
(
345
ArgumentSignature::from_iter([Type::of::<u8>(), Type::of::<u16>()]),
346
0,
347
),
348
(
349
ArgumentSignature::from_iter([Type::of::<i8>(), Type::of::<i16>()]),
350
1,
351
),
352
]),
353
};
354
355
let FunctionOverloadError::DuplicateSignature(duplicate) =
356
func_a.merge(func_b).unwrap_err()
357
else {
358
panic!("Expected `FunctionOverloadError::DuplicateSignature`");
359
};
360
361
assert_eq!(
362
duplicate,
363
ArgumentSignature::from_iter([Type::of::<i8>(), Type::of::<i16>()])
364
);
365
366
// Assert the original remains unchanged:
367
assert!(!func_a.is_overloaded());
368
assert_eq!(func_a.functions, vec!['a']);
369
assert_eq!(func_a.info.signatures().len(), 1);
370
assert_eq!(
371
func_a.arg_map,
372
HashMap::from_iter([(
373
ArgumentSignature::from_iter([Type::of::<i8>(), Type::of::<i16>()]),
374
0
375
),])
376
);
377
}
378
}
379
380