Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_reflect/src/func/dynamic_function_mut.rs
6599 views
1
use alloc::{borrow::Cow, boxed::Box};
2
use bevy_platform::sync::Arc;
3
use core::fmt::{Debug, Formatter};
4
5
use crate::func::{
6
args::{ArgCount, ArgList},
7
dynamic_function_internal::DynamicFunctionInternal,
8
DynamicFunction, FunctionInfo, FunctionOverloadError, FunctionResult, IntoFunctionMut,
9
};
10
11
/// A [`Box`] containing a callback to a reflected function.
12
type BoxFnMut<'env> = Box<dyn for<'a> FnMut(ArgList<'a>) -> FunctionResult<'a> + 'env>;
13
14
/// A dynamic representation of a function.
15
///
16
/// This type can be used to represent any callable that satisfies [`FnMut`]
17
/// (or the reflection-based equivalent, [`ReflectFnMut`]).
18
/// That is, any function or closure.
19
///
20
/// For functions that do not need to capture their environment mutably,
21
/// it's recommended to use [`DynamicFunction`] instead.
22
///
23
/// This type can be seen as a superset of [`DynamicFunction`].
24
///
25
/// See the [module-level documentation] for more information.
26
///
27
/// You will generally not need to construct this manually.
28
/// Instead, many functions and closures can be automatically converted using the [`IntoFunctionMut`] trait.
29
///
30
/// # Example
31
///
32
/// Most of the time, a [`DynamicFunctionMut`] can be created using the [`IntoFunctionMut`] trait:
33
///
34
/// ```
35
/// # use bevy_reflect::func::{ArgList, DynamicFunctionMut, FunctionInfo, IntoFunctionMut};
36
/// #
37
/// let mut list: Vec<i32> = vec![1, 2, 3];
38
///
39
/// // `replace` is a closure that captures a mutable reference to `list`
40
/// let mut replace = |index: usize, value: i32| -> i32 {
41
/// let old_value = list[index];
42
/// list[index] = value;
43
/// old_value
44
/// };
45
///
46
/// // Since this closure mutably borrows data, we can't convert it into a regular `DynamicFunction`,
47
/// // as doing so would result in a compile-time error:
48
/// // let mut func: DynamicFunction = replace.into_function();
49
///
50
/// // Instead, we convert it into a `DynamicFunctionMut` using `IntoFunctionMut::into_function_mut`:
51
/// let mut func: DynamicFunctionMut = replace.into_function_mut();
52
///
53
/// // Dynamically call it:
54
/// let args = ArgList::default().with_owned(1_usize).with_owned(-2_i32);
55
/// let value = func.call(args).unwrap().unwrap_owned();
56
///
57
/// // Check the result:
58
/// assert_eq!(value.try_take::<i32>().unwrap(), 2);
59
///
60
/// // Note that `func` still has a reference to `list`,
61
/// // so we need to drop it before we can access `list` again.
62
/// // Alternatively, we could have invoked `func` with
63
/// // `DynamicFunctionMut::call_once` to immediately consume it.
64
/// drop(func);
65
/// assert_eq!(list, vec![1, -2, 3]);
66
/// ```
67
///
68
/// [`ReflectFnMut`]: crate::func::ReflectFnMut
69
/// [module-level documentation]: crate::func
70
pub struct DynamicFunctionMut<'env> {
71
internal: DynamicFunctionInternal<BoxFnMut<'env>>,
72
}
73
74
impl<'env> DynamicFunctionMut<'env> {
75
/// Create a new [`DynamicFunctionMut`].
76
///
77
/// The given function can be used to call out to any other callable,
78
/// including functions, closures, or methods.
79
///
80
/// It's important that the function signature matches the provided [`FunctionInfo`].
81
/// as this will be used to validate arguments when [calling] the function.
82
/// This is also required in order for [function overloading] to work correctly.
83
///
84
/// # Panics
85
///
86
/// This function may panic for any of the following reasons:
87
/// - No [`SignatureInfo`] is provided.
88
/// - A provided [`SignatureInfo`] has more arguments than [`ArgCount::MAX_COUNT`].
89
/// - The conversion to [`FunctionInfo`] fails.
90
///
91
/// [calling]: crate::func::dynamic_function_mut::DynamicFunctionMut::call
92
/// [`SignatureInfo`]: crate::func::SignatureInfo
93
/// [function overloading]: Self::with_overload
94
pub fn new<F: for<'a> FnMut(ArgList<'a>) -> FunctionResult<'a> + 'env>(
95
func: F,
96
info: impl TryInto<FunctionInfo, Error: Debug>,
97
) -> Self {
98
Self {
99
internal: DynamicFunctionInternal::new(Box::new(func), info.try_into().unwrap()),
100
}
101
}
102
103
/// Set the name of the function.
104
///
105
/// For [`DynamicFunctionMuts`] created using [`IntoFunctionMut`],
106
/// the default name will always be the full path to the function as returned by [`core::any::type_name`],
107
/// unless the function is a closure, anonymous function, or function pointer,
108
/// in which case the name will be `None`.
109
///
110
/// [`DynamicFunctionMuts`]: DynamicFunctionMut
111
pub fn with_name(mut self, name: impl Into<Cow<'static, str>>) -> Self {
112
self.internal = self.internal.with_name(name);
113
self
114
}
115
116
/// Add an overload to this function.
117
///
118
/// Overloads allow a single [`DynamicFunctionMut`] to represent multiple functions of different signatures.
119
///
120
/// This can be used to handle multiple monomorphizations of a generic function
121
/// or to allow functions with a variable number of arguments.
122
///
123
/// Any functions with the same [argument signature] will be overwritten by the one from the new function, `F`.
124
/// For example, if the existing function had the signature `(i32, i32) -> i32`,
125
/// and the new function, `F`, also had the signature `(i32, i32) -> i32`,
126
/// the one from `F` would replace the one from the existing function.
127
///
128
/// Overloaded functions retain the [name] of the original function.
129
///
130
/// Note that it may be impossible to overload closures that mutably borrow from their environment
131
/// due to Rust's borrowing rules.
132
/// However, it's still possible to overload functions that do not capture their environment mutably,
133
/// or those that maintain mutually exclusive mutable references to their environment.
134
///
135
/// # Panics
136
///
137
/// Panics if the function, `F`, contains a signature already found in this function.
138
///
139
/// For a non-panicking version, see [`try_with_overload`].
140
///
141
/// # Example
142
///
143
/// ```
144
/// # use bevy_reflect::func::IntoFunctionMut;
145
/// let mut total_i32 = 0;
146
/// let mut add_i32 = |a: i32| total_i32 += a;
147
///
148
/// let mut total_f32 = 0.0;
149
/// let mut add_f32 = |a: f32| total_f32 += a;
150
///
151
/// // Currently, the only generic type `func` supports is `i32`.
152
/// let mut func = add_i32.into_function_mut();
153
///
154
/// // However, we can add an overload to handle `f32` as well:
155
/// func = func.with_overload(add_f32);
156
///
157
/// // Test `i32`:
158
/// let args = bevy_reflect::func::ArgList::new().with_owned(123_i32);
159
/// func.call(args).unwrap();
160
///
161
/// // Test `f32`:
162
/// let args = bevy_reflect::func::ArgList::new().with_owned(1.23_f32);
163
/// func.call(args).unwrap();
164
///
165
/// drop(func);
166
/// assert_eq!(total_i32, 123);
167
/// assert_eq!(total_f32, 1.23);
168
/// ```
169
///
170
/// [argument signature]: crate::func::signature::ArgumentSignature
171
/// [name]: Self::name
172
/// [`try_with_overload`]: Self::try_with_overload
173
pub fn with_overload<'a, F: IntoFunctionMut<'a, Marker>, Marker>(
174
self,
175
function: F,
176
) -> DynamicFunctionMut<'a>
177
where
178
'env: 'a,
179
{
180
self.try_with_overload(function).unwrap_or_else(|(_, err)| {
181
panic!("{}", err);
182
})
183
}
184
185
/// Attempt to add an overload to this function.
186
///
187
/// If the function, `F`, contains a signature already found in this function,
188
/// an error will be returned along with the original function.
189
///
190
/// For a panicking version, see [`with_overload`].
191
///
192
/// [`with_overload`]: Self::with_overload
193
pub fn try_with_overload<F: IntoFunctionMut<'env, Marker>, Marker>(
194
mut self,
195
function: F,
196
) -> Result<Self, (Box<Self>, FunctionOverloadError)> {
197
let function = function.into_function_mut();
198
199
match self.internal.merge(function.internal) {
200
Ok(_) => Ok(self),
201
Err(err) => Err((Box::new(self), err)),
202
}
203
}
204
205
/// Call the function with the given arguments.
206
///
207
/// Variables that are captured mutably by this function
208
/// won't be usable until this function is dropped.
209
/// Consider using [`call_once`] if you want to consume the function
210
/// immediately after calling it.
211
///
212
/// # Example
213
///
214
/// ```
215
/// # use bevy_reflect::func::{IntoFunctionMut, ArgList};
216
/// let mut total = 0;
217
/// let add = |a: i32, b: i32| -> i32 {
218
/// total = a + b;
219
/// total
220
/// };
221
///
222
/// let mut func = add.into_function_mut().with_name("add");
223
/// let args = ArgList::new().with_owned(25_i32).with_owned(75_i32);
224
/// let result = func.call(args).unwrap().unwrap_owned();
225
/// assert_eq!(result.try_take::<i32>().unwrap(), 100);
226
/// ```
227
///
228
/// # Errors
229
///
230
/// This method will return an error if the number of arguments provided does not match
231
/// the number of arguments expected by the function's [`FunctionInfo`].
232
///
233
/// The function itself may also return any errors it needs to.
234
///
235
/// [`call_once`]: DynamicFunctionMut::call_once
236
pub fn call<'a>(&mut self, args: ArgList<'a>) -> FunctionResult<'a> {
237
self.internal.validate_args(&args)?;
238
let func = self.internal.get_mut(&args)?;
239
func(args)
240
}
241
242
/// Call the function with the given arguments and consume it.
243
///
244
/// This is useful for functions that capture their environment mutably
245
/// because otherwise any captured variables would still be borrowed by it.
246
///
247
/// # Example
248
///
249
/// ```
250
/// # use bevy_reflect::func::{IntoFunctionMut, ArgList};
251
/// let mut count = 0;
252
/// let increment = |amount: i32| count += amount;
253
///
254
/// let increment_function = increment.into_function_mut();
255
/// let args = ArgList::new().with_owned(5_i32);
256
///
257
/// // We need to drop `increment_function` here so that we
258
/// // can regain access to `count`.
259
/// // `call_once` does this automatically for us.
260
/// increment_function.call_once(args).unwrap();
261
/// assert_eq!(count, 5);
262
/// ```
263
///
264
/// # Errors
265
///
266
/// This method will return an error if the number of arguments provided does not match
267
/// the number of arguments expected by the function's [`FunctionInfo`].
268
///
269
/// The function itself may also return any errors it needs to.
270
pub fn call_once(mut self, args: ArgList) -> FunctionResult {
271
self.call(args)
272
}
273
274
/// Returns the function info.
275
pub fn info(&self) -> &FunctionInfo {
276
self.internal.info()
277
}
278
279
/// The name of the function.
280
///
281
/// For [`DynamicFunctionMuts`] created using [`IntoFunctionMut`],
282
/// the default name will always be the full path to the function as returned by [`core::any::type_name`],
283
/// unless the function is a closure, anonymous function, or function pointer,
284
/// in which case the name will be `None`.
285
///
286
/// This can be overridden using [`with_name`].
287
///
288
/// [`DynamicFunctionMuts`]: DynamicFunctionMut
289
/// [`with_name`]: Self::with_name
290
pub fn name(&self) -> Option<&Cow<'static, str>> {
291
self.internal.name()
292
}
293
294
/// Returns `true` if the function is [overloaded].
295
///
296
/// # Example
297
///
298
/// ```
299
/// # use bevy_reflect::func::IntoFunctionMut;
300
/// let mut total_i32 = 0;
301
/// let increment = (|value: i32| total_i32 += value).into_function_mut();
302
/// assert!(!increment.is_overloaded());
303
///
304
/// let mut total_f32 = 0.0;
305
/// let increment = increment.with_overload(|value: f32| total_f32 += value);
306
/// assert!(increment.is_overloaded());
307
/// ```
308
///
309
/// [overloaded]: Self::with_overload
310
pub fn is_overloaded(&self) -> bool {
311
self.internal.is_overloaded()
312
}
313
314
/// Returns the number of arguments the function expects.
315
///
316
/// For [overloaded] functions that can have a variable number of arguments,
317
/// this will contain the full set of counts for all signatures.
318
///
319
/// # Example
320
///
321
/// ```
322
/// # use bevy_reflect::func::IntoFunctionMut;
323
/// let add = (|a: i32, b: i32| a + b).into_function_mut();
324
/// assert!(add.arg_count().contains(2));
325
///
326
/// let add = add.with_overload(|a: f32, b: f32, c: f32| a + b + c);
327
/// assert!(add.arg_count().contains(2));
328
/// assert!(add.arg_count().contains(3));
329
/// ```
330
///
331
/// [overloaded]: Self::with_overload
332
pub fn arg_count(&self) -> ArgCount {
333
self.internal.arg_count()
334
}
335
}
336
337
/// Outputs the function's signature.
338
///
339
/// This takes the format: `DynamicFunctionMut(fn {name}({arg1}: {type1}, {arg2}: {type2}, ...) -> {return_type})`.
340
///
341
/// Names for arguments and the function itself are optional and will default to `_` if not provided.
342
///
343
/// If the function is [overloaded], the output will include the signatures of all overloads as a set.
344
/// For example, `DynamicFunctionMut(fn add{(_: i32, _: i32) -> i32, (_: f32, _: f32) -> f32})`.
345
///
346
/// [overloaded]: DynamicFunctionMut::with_overload
347
impl<'env> Debug for DynamicFunctionMut<'env> {
348
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
349
write!(f, "DynamicFunctionMut({:?})", &self.internal)
350
}
351
}
352
353
impl<'env> From<DynamicFunction<'env>> for DynamicFunctionMut<'env> {
354
#[inline]
355
fn from(function: DynamicFunction<'env>) -> Self {
356
Self {
357
internal: function.internal.map_functions(arc_to_box),
358
}
359
}
360
}
361
362
/// Helper function from converting an [`Arc`] function to a [`Box`] function.
363
///
364
/// This is needed to help the compiler infer the correct types.
365
fn arc_to_box<'env>(
366
f: Arc<dyn for<'a> Fn(ArgList<'a>) -> FunctionResult<'a> + Send + Sync + 'env>,
367
) -> BoxFnMut<'env> {
368
Box::new(move |args| f(args))
369
}
370
371
impl<'env> IntoFunctionMut<'env, ()> for DynamicFunctionMut<'env> {
372
#[inline]
373
fn into_function_mut(self) -> DynamicFunctionMut<'env> {
374
self
375
}
376
}
377
378
#[cfg(test)]
379
mod tests {
380
use super::*;
381
use crate::func::{FunctionError, IntoReturn, SignatureInfo};
382
use alloc::vec;
383
use core::ops::Add;
384
385
#[test]
386
fn should_overwrite_function_name() {
387
let mut total = 0;
388
let func = (|a: i32, b: i32| total = a + b).into_function_mut();
389
assert!(func.name().is_none());
390
391
let func = func.with_name("my_function");
392
assert_eq!(func.name().unwrap(), "my_function");
393
}
394
395
#[test]
396
fn should_convert_dynamic_function_mut_with_into_function() {
397
fn make_closure<'env, F: IntoFunctionMut<'env, M>, M>(f: F) -> DynamicFunctionMut<'env> {
398
f.into_function_mut()
399
}
400
401
let mut total = 0;
402
let closure: DynamicFunctionMut = make_closure(|a: i32, b: i32| total = a + b);
403
let _: DynamicFunctionMut = make_closure(closure);
404
}
405
406
#[test]
407
fn should_return_error_on_arg_count_mismatch() {
408
let mut total = 0;
409
let mut func = (|a: i32, b: i32| total = a + b).into_function_mut();
410
411
let args = ArgList::default().with_owned(25_i32);
412
let error = func.call(args).unwrap_err();
413
assert_eq!(
414
error,
415
FunctionError::ArgCountMismatch {
416
expected: ArgCount::new(2).unwrap(),
417
received: 1
418
}
419
);
420
421
let args = ArgList::default().with_owned(25_i32);
422
let error = func.call_once(args).unwrap_err();
423
assert_eq!(
424
error,
425
FunctionError::ArgCountMismatch {
426
expected: ArgCount::new(2).unwrap(),
427
received: 1
428
}
429
);
430
}
431
432
#[test]
433
fn should_allow_creating_manual_generic_dynamic_function_mut() {
434
let mut total = 0_i32;
435
let func = DynamicFunctionMut::new(
436
|mut args| {
437
let value = args.take_arg()?;
438
439
if value.is::<i32>() {
440
let value = value.take::<i32>()?;
441
total += value;
442
} else {
443
let value = value.take::<i16>()?;
444
total += value as i32;
445
}
446
447
Ok(().into_return())
448
},
449
vec![
450
SignatureInfo::named("add::<i32>").with_arg::<i32>("value"),
451
SignatureInfo::named("add::<i16>").with_arg::<i16>("value"),
452
],
453
);
454
455
assert_eq!(func.name().unwrap(), "add::<i32>");
456
let mut func = func.with_name("add");
457
assert_eq!(func.name().unwrap(), "add");
458
459
let args = ArgList::default().with_owned(25_i32);
460
func.call(args).unwrap();
461
let args = ArgList::default().with_owned(75_i16);
462
func.call(args).unwrap();
463
464
drop(func);
465
assert_eq!(total, 100);
466
}
467
468
// Closures that mutably borrow from their environment cannot realistically
469
// be overloaded since that would break Rust's borrowing rules.
470
// However, we still need to verify overloaded functions work since a
471
// `DynamicFunctionMut` can also be made from a non-mutably borrowing closure/function.
472
#[test]
473
fn should_allow_function_overloading() {
474
fn add<T: Add<Output = T>>(a: T, b: T) -> T {
475
a + b
476
}
477
478
let mut func = add::<i32>.into_function_mut().with_overload(add::<f32>);
479
480
let args = ArgList::default().with_owned(25_i32).with_owned(75_i32);
481
let result = func.call(args).unwrap().unwrap_owned();
482
assert_eq!(result.try_take::<i32>().unwrap(), 100);
483
484
let args = ArgList::default().with_owned(25.0_f32).with_owned(75.0_f32);
485
let result = func.call(args).unwrap().unwrap_owned();
486
assert_eq!(result.try_take::<f32>().unwrap(), 100.0);
487
}
488
}
489
490