Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_reflect/src/func/mod.rs
6599 views
1
//! Reflection-based dynamic functions.
2
//!
3
//! This module provides a way to pass around and call functions dynamically
4
//! using the [`DynamicFunction`] and [`DynamicFunctionMut`] types.
5
//!
6
//! Many simple functions and closures can be automatically converted to these types
7
//! using the [`IntoFunction`] and [`IntoFunctionMut`] traits, respectively.
8
//!
9
//! Once this dynamic representation is created, it can be called with a set of arguments provided
10
//! via an [`ArgList`].
11
//!
12
//! This returns a [`FunctionResult`] containing the [`Return`] value,
13
//! which can be used to extract a [`PartialReflect`] trait object.
14
//!
15
//! # Example
16
//!
17
//! ```
18
//! # use bevy_reflect::PartialReflect;
19
//! # use bevy_reflect::func::args::ArgList;
20
//! # use bevy_reflect::func::{DynamicFunction, FunctionResult, IntoFunction, Return};
21
//! fn add(a: i32, b: i32) -> i32 {
22
//! a + b
23
//! }
24
//!
25
//! let mut func: DynamicFunction = add.into_function();
26
//! let args: ArgList = ArgList::default()
27
//! // Pushing a known type with owned ownership
28
//! .with_owned(25_i32)
29
//! // Pushing a reflected type with owned ownership
30
//! .with_boxed(Box::new(75_i32) as Box<dyn PartialReflect>);
31
//! let result: FunctionResult = func.call(args);
32
//! let value: Return = result.unwrap();
33
//! assert_eq!(value.unwrap_owned().try_downcast_ref::<i32>(), Some(&100));
34
//! ```
35
//!
36
//! # Types of Functions
37
//!
38
//! For simplicity, this module uses the umbrella term "function" to refer to any Rust callable:
39
//! code that can be invoked with a set of arguments to perform some action.
40
//!
41
//! In Rust, there are two main categories of callables: functions and closures.
42
//!
43
//! A "function" is a callable that does not capture its environment.
44
//! These are typically defined with the `fn` keyword, which are referred to as _named_ functions.
45
//! But there are also _anonymous_ functions, which are unnamed and defined with anonymous function syntax.
46
//!
47
//! ```rust
48
//! // This is a named function:
49
//! fn add(a: i32, b: i32) -> i32 {
50
//! a + b
51
//! }
52
//!
53
//! // This is an anonymous function:
54
//! let add = |a: i32, b: i32| a + b;
55
//! ```
56
//!
57
//! Closures, on the other hand, are special functions that do capture their environment.
58
//! These are always defined with anonymous function syntax.
59
//!
60
//! ```
61
//! // A closure that captures an immutable reference to a variable
62
//! let c = 123;
63
//! let add = |a: i32, b: i32| a + b + c;
64
//!
65
//! // A closure that captures a mutable reference to a variable
66
//! let mut total = 0;
67
//! let add = |a: i32, b: i32| total += a + b;
68
//!
69
//! // A closure that takes ownership of its captured variables by moving them
70
//! let c = 123;
71
//! let add = move |a: i32, b: i32| a + b + c;
72
//! ```
73
//!
74
//! # Valid Signatures
75
//!
76
//! Many of the traits in this module have default blanket implementations over a specific set of function signatures.
77
//!
78
//! These signatures are:
79
//! - `(...) -> R`
80
//! - `for<'a> (&'a arg, ...) -> &'a R`
81
//! - `for<'a> (&'a mut arg, ...) -> &'a R`
82
//! - `for<'a> (&'a mut arg, ...) -> &'a mut R`
83
//!
84
//! Where `...` represents 0 to 15 arguments (inclusive) of the form `T`, `&T`, or `&mut T`.
85
//! The lifetime of any reference to the return type `R`, must be tied to a "receiver" argument
86
//! (i.e. the first argument in the signature, normally `self`).
87
//!
88
//! Each trait will also have its own requirements for what traits are required for both arguments and return types,
89
//! but a good rule-of-thumb is that all types should derive [`Reflect`].
90
//!
91
//! The reason for such a small subset of valid signatures is due to limitations in Rust—
92
//! namely the [lack of variadic generics] and certain [coherence issues].
93
//!
94
//! For other functions that don't conform to one of the above signatures,
95
//! [`DynamicFunction`] and [`DynamicFunctionMut`] can instead be created manually.
96
//!
97
//! # Generic Functions
98
//!
99
//! In Rust, generic functions are [monomorphized] by the compiler,
100
//! which means that a separate copy of the function is generated for each concrete set of type parameters.
101
//!
102
//! When converting a generic function to a [`DynamicFunction`] or [`DynamicFunctionMut`],
103
//! the function must be manually monomorphized with concrete types.
104
//! In other words, you cannot write `add<T>.into_function()`.
105
//! Instead, you will need to write `add::<i32>.into_function()`.
106
//!
107
//! This means that reflected functions cannot be generic themselves.
108
//! To get around this limitation, you can consider [overloading] your function with multiple concrete types.
109
//!
110
//! # Overloading Functions
111
//!
112
//! Both [`DynamicFunction`] and [`DynamicFunctionMut`] support [function overloading].
113
//!
114
//! Function overloading allows one function to handle multiple types of arguments.
115
//! This is useful for simulating generic functions by having an overload for each known concrete type.
116
//! Additionally, it can also simulate [variadic functions]: functions that can be called with a variable number of arguments.
117
//!
118
//! Internally, this works by storing multiple functions in a map,
119
//! where each function is associated with a specific argument signature.
120
//!
121
//! To learn more, see the docs on [`DynamicFunction::with_overload`].
122
//!
123
//! # Function Registration
124
//!
125
//! This module also provides a [`FunctionRegistry`] that can be used to register functions and closures
126
//! by name so that they may be retrieved and called dynamically.
127
//!
128
//! ```
129
//! # use bevy_reflect::func::{ArgList, FunctionRegistry};
130
//! fn add(a: i32, b: i32) -> i32 {
131
//! a + b
132
//! }
133
//!
134
//! let mut registry = FunctionRegistry::default();
135
//!
136
//! // You can register functions and methods by their `core::any::type_name`:
137
//! registry.register(add).unwrap();
138
//!
139
//! // Or you can register them by a custom name:
140
//! registry.register_with_name("mul", |a: i32, b: i32| a * b).unwrap();
141
//!
142
//! // You can then retrieve and call these functions by name:
143
//! let reflect_add = registry.get(core::any::type_name_of_val(&add)).unwrap();
144
//! let value = reflect_add.call(ArgList::default().with_owned(10_i32).with_owned(5_i32)).unwrap();
145
//! assert_eq!(value.unwrap_owned().try_downcast_ref::<i32>(), Some(&15));
146
//!
147
//! let reflect_mul = registry.get("mul").unwrap();
148
//! let value = reflect_mul.call(ArgList::default().with_owned(10_i32).with_owned(5_i32)).unwrap();
149
//! assert_eq!(value.unwrap_owned().try_downcast_ref::<i32>(), Some(&50));
150
//! ```
151
//!
152
//! [`PartialReflect`]: crate::PartialReflect
153
//! [`Reflect`]: crate::Reflect
154
//! [lack of variadic generics]: https://poignardazur.github.io/2024/05/25/report-on-rustnl-variadics/
155
//! [coherence issues]: https://doc.rust-lang.org/rustc/lints/listing/warn-by-default.html#coherence-leak-check
156
//! [monomorphized]: https://en.wikipedia.org/wiki/Monomorphization
157
//! [overloading]: #overloading-functions
158
//! [function overloading]: https://en.wikipedia.org/wiki/Function_overloading
159
//! [variadic functions]: https://en.wikipedia.org/wiki/Variadic_function
160
161
pub use args::{ArgError, ArgList, ArgValue};
162
pub use dynamic_function::*;
163
pub use dynamic_function_mut::*;
164
pub use error::*;
165
pub use function::*;
166
pub use info::*;
167
pub use into_function::*;
168
pub use into_function_mut::*;
169
pub use reflect_fn::*;
170
pub use reflect_fn_mut::*;
171
pub use registry::*;
172
pub use return_type::*;
173
174
pub mod args;
175
mod dynamic_function;
176
mod dynamic_function_internal;
177
mod dynamic_function_mut;
178
mod error;
179
mod function;
180
mod info;
181
mod into_function;
182
mod into_function_mut;
183
pub(crate) mod macros;
184
mod reflect_fn;
185
mod reflect_fn_mut;
186
mod registry;
187
mod return_type;
188
pub mod signature;
189
190
#[cfg(test)]
191
mod tests {
192
use alloc::borrow::Cow;
193
194
use super::*;
195
use crate::func::args::ArgCount;
196
use crate::{
197
func::args::{ArgError, ArgList, Ownership},
198
TypePath,
199
};
200
201
#[test]
202
fn should_error_on_missing_args() {
203
fn foo(_: i32) {}
204
205
let func = foo.into_function();
206
let args = ArgList::new();
207
let result = func.call(args);
208
assert_eq!(
209
result.unwrap_err(),
210
FunctionError::ArgCountMismatch {
211
expected: ArgCount::new(1).unwrap(),
212
received: 0
213
}
214
);
215
}
216
217
#[test]
218
fn should_error_on_too_many_args() {
219
fn foo() {}
220
221
let func = foo.into_function();
222
let args = ArgList::new().with_owned(123_i32);
223
let result = func.call(args);
224
assert_eq!(
225
result.unwrap_err(),
226
FunctionError::ArgCountMismatch {
227
expected: ArgCount::new(0).unwrap(),
228
received: 1
229
}
230
);
231
}
232
233
#[test]
234
fn should_error_on_invalid_arg_type() {
235
fn foo(_: i32) {}
236
237
let func = foo.into_function();
238
let args = ArgList::new().with_owned(123_u32);
239
let result = func.call(args);
240
assert_eq!(
241
result.unwrap_err(),
242
FunctionError::ArgError(ArgError::UnexpectedType {
243
index: 0,
244
expected: Cow::Borrowed(i32::type_path()),
245
received: Cow::Borrowed(u32::type_path())
246
})
247
);
248
}
249
250
#[test]
251
fn should_error_on_invalid_arg_ownership() {
252
fn foo(_: &i32) {}
253
254
let func = foo.into_function();
255
let args = ArgList::new().with_owned(123_i32);
256
let result = func.call(args);
257
assert_eq!(
258
result.unwrap_err(),
259
FunctionError::ArgError(ArgError::InvalidOwnership {
260
index: 0,
261
expected: Ownership::Ref,
262
received: Ownership::Owned
263
})
264
);
265
}
266
}
267
268