Skip to main content

bevy_reflect/func/
into_function.rs

1use crate::func::{DynamicFunction, ReflectFn, TypedFunction};
2
3/// A trait for types that can be converted into a [`DynamicFunction`].
4///
5/// This trait is automatically implemented for any type that implements
6/// [`ReflectFn`] and [`TypedFunction`].
7///
8/// See the [module-level documentation] for more information.
9///
10/// # Trait Parameters
11///
12/// This trait has a `Marker` type parameter that is used to get around issues with
13/// [unconstrained type parameters] when defining impls with generic arguments or return types.
14/// This `Marker` can be any type, provided it doesn't conflict with other implementations.
15///
16/// Additionally, it has a lifetime parameter, `'env`, that is used to bound the lifetime of the function.
17/// For named functions and some closures, this will end up just being `'static`,
18/// however, closures that borrow from their environment will have a lifetime bound to that environment.
19///
20/// [module-level documentation]: crate::func
21/// [unconstrained type parameters]: https://doc.rust-lang.org/error_codes/E0207.html
22pub trait IntoFunction<'env, Marker> {
23    /// Converts [`Self`] into a [`DynamicFunction`].
24    fn into_function(self) -> DynamicFunction<'env>;
25}
26
27impl<'env, F, Marker1, Marker2> IntoFunction<'env, (Marker1, Marker2)> for F
28where
29    F: ReflectFn<'env, Marker1> + TypedFunction<Marker2> + Send + Sync + 'env,
30{
31    fn into_function(self) -> DynamicFunction<'env> {
32        DynamicFunction::new(move |args| self.reflect_call(args), Self::function_info())
33    }
34}
35
36#[cfg(test)]
37mod tests {
38    use super::*;
39    use crate::func::ArgList;
40
41    #[test]
42    fn should_create_dynamic_function_from_closure() {
43        let c = 23;
44        let func = (|a: i32, b: i32| a + b + c).into_function();
45        let args = ArgList::new().with_owned(25_i32).with_owned(75_i32);
46        let result = func.call(args).unwrap().unwrap_owned();
47        assert_eq!(result.try_downcast_ref::<i32>(), Some(&123));
48    }
49
50    #[test]
51    fn should_create_dynamic_function_from_function() {
52        fn add(a: i32, b: i32) -> i32 {
53            a + b
54        }
55
56        let func = add.into_function();
57        let args = ArgList::new().with_owned(25_i32).with_owned(75_i32);
58        let result = func.call(args).unwrap().unwrap_owned();
59        assert_eq!(result.try_downcast_ref::<i32>(), Some(&100));
60    }
61
62    #[test]
63    fn should_default_closure_name_to_none() {
64        let c = 23;
65        let func = (|a: i32, b: i32| a + b + c).into_function();
66        assert!(func.name().is_none());
67    }
68}