Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_reflect/src/func/dynamic_function.rs
6599 views
1
use crate::{
2
__macro_exports::RegisterForReflection,
3
func::{
4
args::{ArgCount, ArgList},
5
dynamic_function_internal::DynamicFunctionInternal,
6
info::FunctionInfo,
7
DynamicFunctionMut, Function, FunctionOverloadError, FunctionResult, IntoFunction,
8
IntoFunctionMut,
9
},
10
ApplyError, MaybeTyped, PartialReflect, Reflect, ReflectKind, ReflectMut, ReflectOwned,
11
ReflectRef, TypeInfo, TypePath,
12
};
13
use alloc::{borrow::Cow, boxed::Box};
14
use bevy_platform::sync::Arc;
15
use bevy_reflect_derive::impl_type_path;
16
use core::fmt::{Debug, Formatter};
17
18
/// An [`Arc`] containing a callback to a reflected function.
19
///
20
/// The `Arc` is used to both ensure that it is `Send + Sync`
21
/// and to allow for the callback to be cloned.
22
///
23
/// Note that cloning is okay since we only ever need an immutable reference
24
/// to call a `dyn Fn` function.
25
/// If we were to contain a `dyn FnMut` instead, cloning would be a lot more complicated.
26
type ArcFn<'env> = Arc<dyn for<'a> Fn(ArgList<'a>) -> FunctionResult<'a> + Send + Sync + 'env>;
27
28
/// A dynamic representation of a function.
29
///
30
/// This type can be used to represent any callable that satisfies [`Fn`]
31
/// (or the reflection-based equivalent, [`ReflectFn`]).
32
/// That is, any function or closure that does not mutably borrow data from its environment.
33
///
34
/// For functions that do need to capture their environment mutably (i.e. mutable closures),
35
/// see [`DynamicFunctionMut`].
36
///
37
/// See the [module-level documentation] for more information.
38
///
39
/// You will generally not need to construct this manually.
40
/// Instead, many functions and closures can be automatically converted using the [`IntoFunction`] trait.
41
///
42
/// # Example
43
///
44
/// Most of the time, a [`DynamicFunction`] can be created using the [`IntoFunction`] trait:
45
///
46
/// ```
47
/// # use bevy_reflect::func::{ArgList, DynamicFunction, IntoFunction};
48
/// #
49
/// fn add(a: i32, b: i32) -> i32 {
50
/// a + b
51
/// }
52
///
53
/// // Convert the function into a dynamic function using `IntoFunction::into_function`:
54
/// let mut func: DynamicFunction = add.into_function();
55
///
56
/// // Dynamically call it:
57
/// let args = ArgList::default().with_owned(25_i32).with_owned(75_i32);
58
/// let value = func.call(args).unwrap().unwrap_owned();
59
///
60
/// // Check the result:
61
/// assert_eq!(value.try_downcast_ref::<i32>(), Some(&100));
62
/// ```
63
///
64
/// [`ReflectFn`]: crate::func::ReflectFn
65
/// [module-level documentation]: crate::func
66
#[derive(Clone)]
67
pub struct DynamicFunction<'env> {
68
pub(super) internal: DynamicFunctionInternal<ArcFn<'env>>,
69
}
70
71
impl<'env> DynamicFunction<'env> {
72
/// Create a new [`DynamicFunction`].
73
///
74
/// The given function can be used to call out to any other callable,
75
/// including functions, closures, or methods.
76
///
77
/// It's important that the function signature matches the provided [`FunctionInfo`].
78
/// as this will be used to validate arguments when [calling] the function.
79
/// This is also required in order for [function overloading] to work correctly.
80
///
81
/// # Panics
82
///
83
/// This function may panic for any of the following reasons:
84
/// - No [`SignatureInfo`] is provided.
85
/// - A provided [`SignatureInfo`] has more arguments than [`ArgCount::MAX_COUNT`].
86
/// - The conversion to [`FunctionInfo`] fails.
87
///
88
/// [calling]: crate::func::dynamic_function::DynamicFunction::call
89
/// [`SignatureInfo`]: crate::func::SignatureInfo
90
/// [function overloading]: Self::with_overload
91
pub fn new<F: for<'a> Fn(ArgList<'a>) -> FunctionResult<'a> + Send + Sync + 'env>(
92
func: F,
93
info: impl TryInto<FunctionInfo, Error: Debug>,
94
) -> Self {
95
let arc = Arc::new(func);
96
97
#[cfg(not(target_has_atomic = "ptr"))]
98
#[expect(
99
unsafe_code,
100
reason = "unsized coercion is an unstable feature for non-std types"
101
)]
102
// SAFETY:
103
// - Coercion from `T` to `dyn for<'a> Fn(ArgList<'a>) -> FunctionResult<'a> + Send + Sync + 'env`
104
// is valid as `T: for<'a> Fn(ArgList<'a>) -> FunctionResult<'a> + Send + Sync + 'env`
105
// - `Arc::from_raw` receives a valid pointer from a previous call to `Arc::into_raw`
106
let arc = unsafe { ArcFn::<'env>::from_raw(Arc::into_raw(arc) as *const _) };
107
108
Self {
109
internal: DynamicFunctionInternal::new(arc, info.try_into().unwrap()),
110
}
111
}
112
113
/// Set the name of the function.
114
///
115
/// For [`DynamicFunctions`] created using [`IntoFunction`],
116
/// the default name will always be the full path to the function as returned by [`core::any::type_name`],
117
/// unless the function is a closure, anonymous function, or function pointer,
118
/// in which case the name will be `None`.
119
///
120
/// [`DynamicFunctions`]: DynamicFunction
121
pub fn with_name(mut self, name: impl Into<Cow<'static, str>>) -> Self {
122
self.internal = self.internal.with_name(name);
123
self
124
}
125
126
/// Add an overload to this function.
127
///
128
/// Overloads allow a single [`DynamicFunction`] to represent multiple functions of different signatures.
129
///
130
/// This can be used to handle multiple monomorphizations of a generic function
131
/// or to allow functions with a variable number of arguments.
132
///
133
/// Any functions with the same [argument signature] will be overwritten by the one from the new function, `F`.
134
/// For example, if the existing function had the signature `(i32, i32) -> i32`,
135
/// and the new function, `F`, also had the signature `(i32, i32) -> i32`,
136
/// the one from `F` would replace the one from the existing function.
137
///
138
/// Overloaded functions retain the [name] of the original function.
139
///
140
/// # Panics
141
///
142
/// Panics if the function, `F`, contains a signature already found in this function.
143
///
144
/// For a non-panicking version, see [`try_with_overload`].
145
///
146
/// # Examples
147
///
148
/// ```
149
/// # use std::ops::Add;
150
/// # use bevy_reflect::func::{ArgList, IntoFunction};
151
/// #
152
/// fn add<T: Add<Output = T>>(a: T, b: T) -> T {
153
/// a + b
154
/// }
155
///
156
/// // Currently, the only generic type `func` supports is `i32`:
157
/// let mut func = add::<i32>.into_function();
158
///
159
/// // However, we can add an overload to handle `f32` as well:
160
/// func = func.with_overload(add::<f32>);
161
///
162
/// // Test `i32`:
163
/// let args = ArgList::default().with_owned(25_i32).with_owned(75_i32);
164
/// let result = func.call(args).unwrap().unwrap_owned();
165
/// assert_eq!(result.try_take::<i32>().unwrap(), 100);
166
///
167
/// // Test `f32`:
168
/// let args = ArgList::default().with_owned(25.0_f32).with_owned(75.0_f32);
169
/// let result = func.call(args).unwrap().unwrap_owned();
170
/// assert_eq!(result.try_take::<f32>().unwrap(), 100.0);
171
///```
172
///
173
/// ```
174
/// # use bevy_reflect::func::{ArgList, IntoFunction};
175
/// #
176
/// fn add_2(a: i32, b: i32) -> i32 {
177
/// a + b
178
/// }
179
///
180
/// fn add_3(a: i32, b: i32, c: i32) -> i32 {
181
/// a + b + c
182
/// }
183
///
184
/// // Currently, `func` only supports two arguments.
185
/// let mut func = add_2.into_function();
186
///
187
/// // However, we can add an overload to handle three arguments as well.
188
/// func = func.with_overload(add_3);
189
///
190
/// // Test two arguments:
191
/// let args = ArgList::default().with_owned(25_i32).with_owned(75_i32);
192
/// let result = func.call(args).unwrap().unwrap_owned();
193
/// assert_eq!(result.try_take::<i32>().unwrap(), 100);
194
///
195
/// // Test three arguments:
196
/// let args = ArgList::default()
197
/// .with_owned(25_i32)
198
/// .with_owned(75_i32)
199
/// .with_owned(100_i32);
200
/// let result = func.call(args).unwrap().unwrap_owned();
201
/// assert_eq!(result.try_take::<i32>().unwrap(), 200);
202
/// ```
203
///
204
///```should_panic
205
/// # use bevy_reflect::func::IntoFunction;
206
///
207
/// fn add(a: i32, b: i32) -> i32 {
208
/// a + b
209
/// }
210
///
211
/// fn sub(a: i32, b: i32) -> i32 {
212
/// a - b
213
/// }
214
///
215
/// let mut func = add.into_function();
216
///
217
/// // This will panic because the function already has an argument signature for `(i32, i32)`:
218
/// func = func.with_overload(sub);
219
/// ```
220
///
221
/// [argument signature]: crate::func::signature::ArgumentSignature
222
/// [name]: Self::name
223
/// [`try_with_overload`]: Self::try_with_overload
224
pub fn with_overload<'a, F: IntoFunction<'a, Marker>, Marker>(
225
self,
226
function: F,
227
) -> DynamicFunction<'a>
228
where
229
'env: 'a,
230
{
231
self.try_with_overload(function).unwrap_or_else(|(_, err)| {
232
panic!("{}", err);
233
})
234
}
235
236
/// Attempt to add an overload to this function.
237
///
238
/// If the function, `F`, contains a signature already found in this function,
239
/// an error will be returned along with the original function.
240
///
241
/// For a panicking version, see [`with_overload`].
242
///
243
/// [`with_overload`]: Self::with_overload
244
pub fn try_with_overload<F: IntoFunction<'env, Marker>, Marker>(
245
mut self,
246
function: F,
247
) -> Result<Self, (Box<Self>, FunctionOverloadError)> {
248
let function = function.into_function();
249
250
match self.internal.merge(function.internal) {
251
Ok(_) => Ok(self),
252
Err(err) => Err((Box::new(self), err)),
253
}
254
}
255
256
/// Call the function with the given arguments.
257
///
258
/// # Example
259
///
260
/// ```
261
/// # use bevy_reflect::func::{IntoFunction, ArgList};
262
/// let c = 23;
263
/// let add = |a: i32, b: i32| -> i32 {
264
/// a + b + c
265
/// };
266
///
267
/// let mut func = add.into_function().with_name("add");
268
/// let args = ArgList::new().with_owned(25_i32).with_owned(75_i32);
269
/// let result = func.call(args).unwrap().unwrap_owned();
270
/// assert_eq!(result.try_take::<i32>().unwrap(), 123);
271
/// ```
272
///
273
/// # Errors
274
///
275
/// This method will return an error if the number of arguments provided does not match
276
/// the number of arguments expected by the function's [`FunctionInfo`].
277
///
278
/// The function itself may also return any errors it needs to.
279
pub fn call<'a>(&self, args: ArgList<'a>) -> FunctionResult<'a> {
280
self.internal.validate_args(&args)?;
281
let func = self.internal.get(&args)?;
282
func(args)
283
}
284
285
/// Returns the function info.
286
pub fn info(&self) -> &FunctionInfo {
287
self.internal.info()
288
}
289
290
/// The name of the function.
291
///
292
/// For [`DynamicFunctions`] created using [`IntoFunction`],
293
/// the default name will always be the full path to the function as returned by [`core::any::type_name`],
294
/// unless the function is a closure, anonymous function, or function pointer,
295
/// in which case the name will be `None`.
296
///
297
/// This can be overridden using [`with_name`].
298
///
299
/// If the function was [overloaded], it will retain its original name if it had one.
300
///
301
/// [`DynamicFunctions`]: DynamicFunction
302
/// [`with_name`]: Self::with_name
303
/// [overloaded]: Self::with_overload
304
pub fn name(&self) -> Option<&Cow<'static, str>> {
305
self.internal.name()
306
}
307
308
/// Returns `true` if the function is [overloaded].
309
///
310
/// # Example
311
///
312
/// ```
313
/// # use bevy_reflect::func::IntoFunction;
314
/// let add = (|a: i32, b: i32| a + b).into_function();
315
/// assert!(!add.is_overloaded());
316
///
317
/// let add = add.with_overload(|a: f32, b: f32| a + b);
318
/// assert!(add.is_overloaded());
319
/// ```
320
///
321
/// [overloaded]: Self::with_overload
322
pub fn is_overloaded(&self) -> bool {
323
self.internal.is_overloaded()
324
}
325
/// Returns the number of arguments the function expects.
326
///
327
/// For [overloaded] functions that can have a variable number of arguments,
328
/// this will contain the full set of counts for all signatures.
329
///
330
/// # Example
331
///
332
/// ```
333
/// # use bevy_reflect::func::IntoFunction;
334
/// let add = (|a: i32, b: i32| a + b).into_function();
335
/// assert!(add.arg_count().contains(2));
336
///
337
/// let add = add.with_overload(|a: f32, b: f32, c: f32| a + b + c);
338
/// assert!(add.arg_count().contains(2));
339
/// assert!(add.arg_count().contains(3));
340
/// ```
341
///
342
/// [overloaded]: Self::with_overload
343
pub fn arg_count(&self) -> ArgCount {
344
self.internal.arg_count()
345
}
346
}
347
348
impl Function for DynamicFunction<'static> {
349
fn name(&self) -> Option<&Cow<'static, str>> {
350
self.internal.name()
351
}
352
353
fn info(&self) -> &FunctionInfo {
354
self.internal.info()
355
}
356
357
fn reflect_call<'a>(&self, args: ArgList<'a>) -> FunctionResult<'a> {
358
self.call(args)
359
}
360
361
fn to_dynamic_function(&self) -> DynamicFunction<'static> {
362
self.clone()
363
}
364
}
365
366
impl PartialReflect for DynamicFunction<'static> {
367
fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {
368
None
369
}
370
371
fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect> {
372
self
373
}
374
375
fn as_partial_reflect(&self) -> &dyn PartialReflect {
376
self
377
}
378
379
fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect {
380
self
381
}
382
383
fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>> {
384
Err(self)
385
}
386
387
fn try_as_reflect(&self) -> Option<&dyn Reflect> {
388
None
389
}
390
391
fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect> {
392
None
393
}
394
395
fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {
396
match value.reflect_ref() {
397
ReflectRef::Function(func) => {
398
*self = func.to_dynamic_function();
399
Ok(())
400
}
401
_ => Err(ApplyError::MismatchedTypes {
402
from_type: value.reflect_type_path().into(),
403
to_type: Self::type_path().into(),
404
}),
405
}
406
}
407
408
fn reflect_kind(&self) -> ReflectKind {
409
ReflectKind::Function
410
}
411
412
fn reflect_ref(&self) -> ReflectRef<'_> {
413
ReflectRef::Function(self)
414
}
415
416
fn reflect_mut(&mut self) -> ReflectMut<'_> {
417
ReflectMut::Function(self)
418
}
419
420
fn reflect_owned(self: Box<Self>) -> ReflectOwned {
421
ReflectOwned::Function(self)
422
}
423
424
fn reflect_hash(&self) -> Option<u64> {
425
None
426
}
427
428
fn reflect_partial_eq(&self, _value: &dyn PartialReflect) -> Option<bool> {
429
None
430
}
431
432
fn debug(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
433
Debug::fmt(self, f)
434
}
435
436
fn is_dynamic(&self) -> bool {
437
true
438
}
439
}
440
441
impl MaybeTyped for DynamicFunction<'static> {}
442
443
impl RegisterForReflection for DynamicFunction<'static> {}
444
445
impl_type_path!((in bevy_reflect) DynamicFunction<'env>);
446
447
/// Outputs the function's signature.
448
///
449
/// This takes the format: `DynamicFunction(fn {name}({arg1}: {type1}, {arg2}: {type2}, ...) -> {return_type})`.
450
///
451
/// Names for arguments and the function itself are optional and will default to `_` if not provided.
452
///
453
/// If the function is [overloaded], the output will include the signatures of all overloads as a set.
454
/// For example, `DynamicFunction(fn add{(_: i32, _: i32) -> i32, (_: f32, _: f32) -> f32})`.
455
///
456
/// [overloaded]: DynamicFunction::with_overload
457
impl<'env> Debug for DynamicFunction<'env> {
458
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
459
write!(f, "DynamicFunction({:?})", &self.internal)
460
}
461
}
462
463
impl<'env> IntoFunction<'env, ()> for DynamicFunction<'env> {
464
#[inline]
465
fn into_function(self) -> DynamicFunction<'env> {
466
self
467
}
468
}
469
470
impl<'env> IntoFunctionMut<'env, ()> for DynamicFunction<'env> {
471
#[inline]
472
fn into_function_mut(self) -> DynamicFunctionMut<'env> {
473
DynamicFunctionMut::from(self)
474
}
475
}
476
477
#[cfg(test)]
478
mod tests {
479
use super::*;
480
use crate::func::signature::ArgumentSignature;
481
use crate::func::{FunctionError, IntoReturn, SignatureInfo};
482
use crate::Type;
483
use alloc::{format, string::String, vec, vec::Vec};
484
use bevy_platform::collections::HashSet;
485
use core::ops::Add;
486
487
#[test]
488
fn should_overwrite_function_name() {
489
let c = 23;
490
let func = (|a: i32, b: i32| a + b + c).into_function();
491
assert!(func.name().is_none());
492
493
let func = func.with_name("my_function");
494
assert_eq!(func.name().unwrap(), "my_function");
495
}
496
497
#[test]
498
fn should_convert_dynamic_function_with_into_function() {
499
fn make_closure<'env, F: IntoFunction<'env, M>, M>(f: F) -> DynamicFunction<'env> {
500
f.into_function()
501
}
502
503
let c = 23;
504
let function: DynamicFunction = make_closure(|a: i32, b: i32| a + b + c);
505
let _: DynamicFunction = make_closure(function);
506
}
507
508
#[test]
509
fn should_return_error_on_arg_count_mismatch() {
510
let func = (|a: i32, b: i32| a + b).into_function();
511
512
let args = ArgList::default().with_owned(25_i32);
513
let error = func.call(args).unwrap_err();
514
515
assert_eq!(
516
error,
517
FunctionError::ArgCountMismatch {
518
expected: ArgCount::new(2).unwrap(),
519
received: 1
520
}
521
);
522
}
523
524
#[test]
525
fn should_return_error_on_arg_count_mismatch_overloaded() {
526
let func = (|a: i32, b: i32| a + b)
527
.into_function()
528
.with_overload(|a: i32, b: i32, c: i32| a + b + c);
529
530
let args = ArgList::default()
531
.with_owned(1_i32)
532
.with_owned(2_i32)
533
.with_owned(3_i32)
534
.with_owned(4_i32);
535
536
let error = func.call(args).unwrap_err();
537
538
let mut expected_count = ArgCount::new(2).unwrap();
539
expected_count.add(3);
540
541
assert_eq!(
542
error,
543
FunctionError::ArgCountMismatch {
544
expected: expected_count,
545
received: 4
546
}
547
);
548
}
549
550
#[test]
551
fn should_clone_dynamic_function() {
552
let hello = String::from("Hello");
553
554
let greet = |name: &String| -> String { format!("{hello}, {name}!") };
555
556
let greet = greet.into_function().with_name("greet");
557
let clone = greet.clone();
558
559
assert_eq!(greet.name().unwrap(), "greet");
560
assert_eq!(clone.name().unwrap(), "greet");
561
562
let cloned_value = clone
563
.call(ArgList::default().with_ref(&String::from("world")))
564
.unwrap()
565
.unwrap_owned()
566
.try_take::<String>()
567
.unwrap();
568
569
assert_eq!(cloned_value, "Hello, world!");
570
}
571
572
#[test]
573
fn should_apply_function() {
574
let mut func: Box<dyn Function> = Box::new((|a: i32, b: i32| a + b).into_function());
575
func.apply(&((|a: i32, b: i32| a * b).into_function()));
576
577
let args = ArgList::new().with_owned(5_i32).with_owned(5_i32);
578
let result = func.reflect_call(args).unwrap().unwrap_owned();
579
assert_eq!(result.try_take::<i32>().unwrap(), 25);
580
}
581
582
#[test]
583
fn should_allow_recursive_dynamic_function() {
584
let factorial = DynamicFunction::new(
585
|mut args| {
586
let curr = args.pop::<i32>()?;
587
if curr == 0 {
588
return Ok(1_i32.into_return());
589
}
590
591
let arg = args.pop_arg()?;
592
let this = arg.value();
593
594
match this.reflect_ref() {
595
ReflectRef::Function(func) => {
596
let result = func.reflect_call(
597
ArgList::new()
598
.with_ref(this.as_partial_reflect())
599
.with_owned(curr - 1),
600
);
601
let value = result.unwrap().unwrap_owned().try_take::<i32>().unwrap();
602
Ok((curr * value).into_return())
603
}
604
_ => panic!("expected function"),
605
}
606
},
607
// The `FunctionInfo` doesn't really matter for this test
608
// so we can just give it dummy information.
609
SignatureInfo::anonymous()
610
.with_arg::<i32>("curr")
611
.with_arg::<()>("this"),
612
);
613
614
let args = ArgList::new().with_ref(&factorial).with_owned(5_i32);
615
let value = factorial.call(args).unwrap().unwrap_owned();
616
assert_eq!(value.try_take::<i32>().unwrap(), 120);
617
}
618
619
#[test]
620
fn should_allow_creating_manual_generic_dynamic_function() {
621
let func = DynamicFunction::new(
622
|mut args| {
623
let a = args.take_arg()?;
624
let b = args.take_arg()?;
625
626
if a.is::<i32>() {
627
let a = a.take::<i32>()?;
628
let b = b.take::<i32>()?;
629
Ok((a + b).into_return())
630
} else {
631
let a = a.take::<f32>()?;
632
let b = b.take::<f32>()?;
633
Ok((a + b).into_return())
634
}
635
},
636
vec![
637
SignatureInfo::named("add::<i32>")
638
.with_arg::<i32>("a")
639
.with_arg::<i32>("b")
640
.with_return::<i32>(),
641
SignatureInfo::named("add::<f32>")
642
.with_arg::<f32>("a")
643
.with_arg::<f32>("b")
644
.with_return::<f32>(),
645
],
646
);
647
648
assert_eq!(func.name().unwrap(), "add::<i32>");
649
let func = func.with_name("add");
650
assert_eq!(func.name().unwrap(), "add");
651
652
let args = ArgList::default().with_owned(25_i32).with_owned(75_i32);
653
let result = func.call(args).unwrap().unwrap_owned();
654
assert_eq!(result.try_take::<i32>().unwrap(), 100);
655
656
let args = ArgList::default().with_owned(25.0_f32).with_owned(75.0_f32);
657
let result = func.call(args).unwrap().unwrap_owned();
658
assert_eq!(result.try_take::<f32>().unwrap(), 100.0);
659
}
660
661
#[test]
662
#[should_panic(expected = "called `Result::unwrap()` on an `Err` value: MissingSignature")]
663
fn should_panic_on_missing_function_info() {
664
let _ = DynamicFunction::new(|_| Ok(().into_return()), Vec::new());
665
}
666
667
#[test]
668
fn should_allow_function_overloading() {
669
fn add<T: Add<Output = T>>(a: T, b: T) -> T {
670
a + b
671
}
672
673
let func = add::<i32>.into_function().with_overload(add::<f32>);
674
675
let args = ArgList::default().with_owned(25_i32).with_owned(75_i32);
676
let result = func.call(args).unwrap().unwrap_owned();
677
assert_eq!(result.try_take::<i32>().unwrap(), 100);
678
679
let args = ArgList::default().with_owned(25.0_f32).with_owned(75.0_f32);
680
let result = func.call(args).unwrap().unwrap_owned();
681
assert_eq!(result.try_take::<f32>().unwrap(), 100.0);
682
}
683
684
#[test]
685
fn should_allow_variable_arguments_via_overloading() {
686
fn add_2(a: i32, b: i32) -> i32 {
687
a + b
688
}
689
690
fn add_3(a: i32, b: i32, c: i32) -> i32 {
691
a + b + c
692
}
693
694
let func = add_2.into_function().with_overload(add_3);
695
696
let args = ArgList::default().with_owned(25_i32).with_owned(75_i32);
697
let result = func.call(args).unwrap().unwrap_owned();
698
assert_eq!(result.try_take::<i32>().unwrap(), 100);
699
700
let args = ArgList::default()
701
.with_owned(25_i32)
702
.with_owned(75_i32)
703
.with_owned(100_i32);
704
let result = func.call(args).unwrap().unwrap_owned();
705
assert_eq!(result.try_take::<i32>().unwrap(), 200);
706
}
707
708
#[test]
709
fn should_allow_function_overloading_with_manual_overload() {
710
let manual = DynamicFunction::new(
711
|mut args| {
712
let a = args.take_arg()?;
713
let b = args.take_arg()?;
714
715
if a.is::<i32>() {
716
let a = a.take::<i32>()?;
717
let b = b.take::<i32>()?;
718
Ok((a + b).into_return())
719
} else {
720
let a = a.take::<f32>()?;
721
let b = b.take::<f32>()?;
722
Ok((a + b).into_return())
723
}
724
},
725
vec![
726
SignatureInfo::named("add::<i32>")
727
.with_arg::<i32>("a")
728
.with_arg::<i32>("b")
729
.with_return::<i32>(),
730
SignatureInfo::named("add::<f32>")
731
.with_arg::<f32>("a")
732
.with_arg::<f32>("b")
733
.with_return::<f32>(),
734
],
735
);
736
737
let func = manual.with_overload(|a: u32, b: u32| a + b);
738
739
let args = ArgList::default().with_owned(25_i32).with_owned(75_i32);
740
let result = func.call(args).unwrap().unwrap_owned();
741
assert_eq!(result.try_take::<i32>().unwrap(), 100);
742
743
let args = ArgList::default().with_owned(25_u32).with_owned(75_u32);
744
let result = func.call(args).unwrap().unwrap_owned();
745
assert_eq!(result.try_take::<u32>().unwrap(), 100);
746
}
747
748
#[test]
749
fn should_return_error_on_unknown_overload() {
750
fn add<T: Add<Output = T>>(a: T, b: T) -> T {
751
a + b
752
}
753
754
let func = add::<i32>.into_function().with_overload(add::<f32>);
755
756
let args = ArgList::default().with_owned(25_u32).with_owned(75_u32);
757
let result = func.call(args);
758
assert_eq!(
759
result.unwrap_err(),
760
FunctionError::NoOverload {
761
expected: [
762
ArgumentSignature::from_iter(vec![Type::of::<i32>(), Type::of::<i32>()]),
763
ArgumentSignature::from_iter(vec![Type::of::<f32>(), Type::of::<f32>()])
764
]
765
.into_iter()
766
.collect::<HashSet<_>>(),
767
received: ArgumentSignature::from_iter(vec![Type::of::<u32>(), Type::of::<u32>()]),
768
}
769
);
770
}
771
772
#[test]
773
fn should_debug_dynamic_function() {
774
fn greet(name: &String) -> String {
775
format!("Hello, {name}!")
776
}
777
778
let function = greet.into_function();
779
let debug = format!("{function:?}");
780
assert_eq!(debug, "DynamicFunction(fn bevy_reflect::func::dynamic_function::tests::should_debug_dynamic_function::greet(_: &alloc::string::String) -> alloc::string::String)");
781
}
782
783
#[test]
784
fn should_debug_anonymous_dynamic_function() {
785
let function = (|a: i32, b: i32| a + b).into_function();
786
let debug = format!("{function:?}");
787
assert_eq!(debug, "DynamicFunction(fn _(_: i32, _: i32) -> i32)");
788
}
789
790
#[test]
791
fn should_debug_overloaded_dynamic_function() {
792
fn add<T: Add<Output = T>>(a: T, b: T) -> T {
793
a + b
794
}
795
796
let function = add::<i32>
797
.into_function()
798
.with_overload(add::<f32>)
799
.with_name("add");
800
let debug = format!("{function:?}");
801
assert_eq!(
802
debug,
803
"DynamicFunction(fn add{(_: i32, _: i32) -> i32, (_: f32, _: f32) -> f32})"
804
);
805
}
806
}
807
808