Skip to main content

bevy_reflect/func/
reflect_fn.rs

1use variadics_please::all_tuples;
2
3use crate::{
4    func::{
5        args::{ArgCount, FromArg},
6        macros::count_tokens,
7        ArgList, FunctionError, FunctionResult, IntoReturn, ReflectFnMut,
8    },
9    Reflect, TypePath,
10};
11
12/// A reflection-based version of the [`Fn`] trait.
13///
14/// This allows functions to be called dynamically through [reflection].
15///
16/// # Blanket Implementation
17///
18/// This trait has a blanket implementation that covers:
19/// - Functions and methods defined with the `fn` keyword
20/// - Anonymous functions
21/// - Function pointers
22/// - Closures that capture immutable references to their environment
23/// - Closures that take ownership of captured variables
24///
25/// For each of the above cases, the function signature may only have up to 15 arguments,
26/// not including an optional receiver argument (often `&self` or `&mut self`).
27/// This optional receiver argument may be either a mutable or immutable reference to a type.
28/// If the return type is also a reference, its lifetime will be bound to the lifetime of this receiver.
29///
30/// See the [module-level documentation] for more information on valid signatures.
31///
32/// To handle functions that capture mutable references to their environment,
33/// see the [`ReflectFnMut`] trait instead.
34///
35/// Arguments are expected to implement [`FromArg`], and the return type is expected to implement [`IntoReturn`].
36/// Both of these traits are automatically implemented when using the `Reflect` [derive macro].
37///
38/// # Example
39///
40/// ```
41/// # use bevy_reflect::func::{ArgList, FunctionInfo, ReflectFn};
42/// #
43/// fn add(a: i32, b: i32) -> i32 {
44///   a + b
45/// }
46///
47/// let args = ArgList::new().with_owned(25_i32).with_owned(75_i32);
48///
49/// let value = add.reflect_call(args).unwrap().unwrap_owned();
50/// assert_eq!(value.try_take::<i32>().unwrap(), 100);
51/// ```
52///
53/// # Trait Parameters
54///
55/// This trait has a `Marker` type parameter that is used to get around issues with
56/// [unconstrained type parameters] when defining impls with generic arguments or return types.
57/// This `Marker` can be any type, provided it doesn't conflict with other implementations.
58///
59/// Additionally, it has a lifetime parameter, `'env`, that is used to bound the lifetime of the function.
60/// For named functions and some closures, this will end up just being `'static`,
61/// however, closures that borrow from their environment will have a lifetime bound to that environment.
62///
63/// [reflection]: crate
64/// [module-level documentation]: crate::func
65/// [derive macro]: derive@crate::Reflect
66/// [unconstrained type parameters]: https://doc.rust-lang.org/error_codes/E0207.html
67pub trait ReflectFn<'env, Marker>: ReflectFnMut<'env, Marker> {
68    /// Call the function with the given arguments and return the result.
69    fn reflect_call<'a>(&self, args: ArgList<'a>) -> FunctionResult<'a>;
70}
71
72/// Helper macro for implementing [`ReflectFn`] on Rust functions.
73///
74/// This currently implements it for the following signatures (where `argX` may be any of `T`, `&T`, or `&mut T`):
75/// - `Fn(arg0, arg1, ..., argN) -> R`
76/// - `Fn(&Receiver, arg0, arg1, ..., argN) -> &R`
77/// - `Fn(&mut Receiver, arg0, arg1, ..., argN) -> &mut R`
78/// - `Fn(&mut Receiver, arg0, arg1, ..., argN) -> &R`
79macro_rules! impl_reflect_fn {
80    ($(($Arg:ident, $arg:ident)),*) => {
81        // === (...) -> ReturnType === //
82        impl<'env, $($Arg,)* ReturnType, Function> ReflectFn<'env, fn($($Arg),*) -> [ReturnType]> for Function
83        where
84            $($Arg: FromArg,)*
85            // This clause allows us to convert `ReturnType` into `Return`
86            ReturnType: IntoReturn + Reflect,
87            Function: Fn($($Arg),*) -> ReturnType + 'env,
88            // This clause essentially asserts that `Arg::This` is the same type as `Arg`
89            Function: for<'a> Fn($($Arg::This<'a>),*) -> ReturnType + 'env,
90        {
91            #[expect(
92                clippy::allow_attributes,
93                reason = "This lint is part of a macro, which may not always trigger the `unused_mut` lint."
94            )]
95            #[allow(
96                unused_mut,
97                reason = "Some invocations of this macro may trigger the `unused_mut` lint, where others won't."
98            )]
99            fn reflect_call<'a>(&self, mut args: ArgList<'a>) -> FunctionResult<'a> {
100                const COUNT: usize = count_tokens!($($Arg)*);
101
102                if args.len() != COUNT {
103                    return Err(FunctionError::ArgCountMismatch {
104                        expected: ArgCount::new(COUNT).unwrap(),
105                        received: args.len(),
106                    });
107                }
108
109                // Extract all arguments (in order)
110                $(let $arg = args.take::<$Arg>()?;)*
111
112                Ok((self)($($arg,)*).into_return())
113            }
114        }
115
116        // === (&self, ...) -> &ReturnType === //
117        impl<'env, Receiver, $($Arg,)* ReturnType, Function> ReflectFn<'env, fn(&Receiver, $($Arg),*) -> &ReturnType> for Function
118        where
119            Receiver: Reflect + TypePath,
120            $($Arg: FromArg,)*
121            ReturnType: Reflect,
122            // This clause allows us to convert `&ReturnType` into `Return`
123            for<'a> &'a ReturnType: IntoReturn,
124            Function: for<'a> Fn(&'a Receiver, $($Arg),*) -> &'a ReturnType + 'env,
125            // This clause essentially asserts that `Arg::This` is the same type as `Arg`
126            Function: for<'a> Fn(&'a Receiver, $($Arg::This<'a>),*) -> &'a ReturnType + 'env,
127        {
128            fn reflect_call<'a>(&self, mut args: ArgList<'a>) -> FunctionResult<'a> {
129                const COUNT: usize = count_tokens!(Receiver $($Arg)*);
130
131                if args.len() != COUNT {
132                    return Err(FunctionError::ArgCountMismatch {
133                        expected: ArgCount::new(COUNT).unwrap(),
134                        received: args.len(),
135                    });
136                }
137
138                // Extract all arguments (in order)
139                let receiver = args.take_ref::<Receiver>()?;
140                $(let $arg = args.take::<$Arg>()?;)*
141
142                Ok((self)(receiver, $($arg,)*).into_return())
143            }
144        }
145
146        // === (&mut self, ...) -> &mut ReturnType === //
147        impl<'env, Receiver, $($Arg,)* ReturnType, Function> ReflectFn<'env, fn(&mut Receiver, $($Arg),*) -> &mut ReturnType> for Function
148        where
149            Receiver: Reflect + TypePath,
150            $($Arg: FromArg,)*
151            ReturnType: Reflect,
152            // This clause allows us to convert `&mut ReturnType` into `Return`
153            for<'a> &'a mut ReturnType: IntoReturn,
154            Function: for<'a> Fn(&'a mut Receiver, $($Arg),*) -> &'a mut ReturnType + 'env,
155            // This clause essentially asserts that `Arg::This` is the same type as `Arg`
156            Function: for<'a> Fn(&'a mut Receiver, $($Arg::This<'a>),*) -> &'a mut ReturnType + 'env,
157        {
158            fn reflect_call<'a>(&self, mut args: ArgList<'a>) -> FunctionResult<'a> {
159                const COUNT: usize = count_tokens!(Receiver $($Arg)*);
160
161                if args.len() != COUNT {
162                    return Err(FunctionError::ArgCountMismatch {
163                        expected: ArgCount::new(COUNT).unwrap(),
164                        received: args.len(),
165                    });
166                }
167
168                // Extract all arguments (in order)
169                let receiver = args.take_mut::<Receiver>()?;
170                $(let $arg = args.take::<$Arg>()?;)*
171
172                Ok((self)(receiver, $($arg,)*).into_return())
173            }
174        }
175
176        // === (&mut self, ...) -> &ReturnType === //
177        impl<'env, Receiver, $($Arg,)* ReturnType, Function> ReflectFn<'env, fn(&mut Receiver, $($Arg),*) -> &ReturnType> for Function
178        where
179            Receiver: Reflect + TypePath,
180            $($Arg: FromArg,)*
181            ReturnType: Reflect,
182            // This clause allows us to convert `&ReturnType` into `Return`
183            for<'a> &'a ReturnType: IntoReturn,
184            Function: for<'a> Fn(&'a mut Receiver, $($Arg),*) -> &'a ReturnType + 'env,
185            // This clause essentially asserts that `Arg::This` is the same type as `Arg`
186            Function: for<'a> Fn(&'a mut Receiver, $($Arg::This<'a>),*) -> &'a ReturnType + 'env,
187        {
188            fn reflect_call<'a>(&self, mut args: ArgList<'a>) -> FunctionResult<'a> {
189                const COUNT: usize = count_tokens!(Receiver $($Arg)*);
190
191                if args.len() != COUNT {
192                    return Err(FunctionError::ArgCountMismatch {
193                        expected: ArgCount::new(COUNT).unwrap(),
194                        received: args.len(),
195                    });
196                }
197
198                // Extract all arguments (in order)
199                let receiver = args.take_mut::<Receiver>()?;
200                $(let $arg = args.take::<$Arg>()?;)*
201
202                Ok((self)(receiver, $($arg,)*).into_return())
203            }
204        }
205    };
206}
207
208all_tuples!(impl_reflect_fn, 0, 15, Arg, arg);