Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_reflect/src/func/reflect_fn.rs
6599 views
1
use variadics_please::all_tuples;
2
3
use 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
67
pub 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`
79
macro_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
208
all_tuples!(impl_reflect_fn, 0, 15, Arg, arg);
209
210