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);