Skip to main content

bevy_reflect/func/
into_function_mut.rs

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