8
8
9
9
use bevy:: reflect:: func:: args:: ArgInfo ;
10
10
use bevy:: reflect:: func:: {
11
- ArgList , DynamicFunction , FunctionInfo , IntoFunction , Return , ReturnInfo ,
11
+ ArgList , DynamicClosure , DynamicFunction , FunctionInfo , IntoClosure , IntoFunction , Return ,
12
+ ReturnInfo ,
12
13
} ;
13
14
use bevy:: reflect:: Reflect ;
14
15
@@ -37,7 +38,7 @@ fn main() {
37
38
// Luckily, Bevy's reflection crate comes with a set of tools for doing just that!
38
39
// We do this by first converting our function into the reflection-based `DynamicFunction` type
39
40
// using the `IntoFunction` trait.
40
- let mut function: DynamicFunction = dbg ! ( add. into_function( ) ) ;
41
+ let function: DynamicFunction = dbg ! ( add. into_function( ) ) ;
41
42
42
43
// This time, you'll notice that `DynamicFunction` doesn't take any information about the function's arguments or return value.
43
44
// This is because `DynamicFunction` checks the types of the arguments and return value at runtime.
@@ -55,22 +56,34 @@ fn main() {
55
56
let value: Box < dyn Reflect > = return_value. unwrap_owned ( ) ;
56
57
assert_eq ! ( value. take:: <i32 >( ) . unwrap( ) , 4 ) ;
57
58
58
- // The same can also be done for closures.
59
+ // The same can also be done for closures that capture references to their environment
60
+ // using the `IntoClosure` trait.
59
61
let mut count = 0 ;
60
- let increment = |amount : i32 | {
61
- count += amount;
62
- } ;
63
- let increment_function: DynamicFunction = dbg ! ( increment. into_function( ) ) ;
62
+ let increment = |amount : i32 | count += amount;
63
+
64
+ let closure: DynamicClosure = dbg ! ( increment. into_closure( ) ) ;
64
65
let args = dbg ! ( ArgList :: new( ) . push_owned( 5_i32 ) ) ;
65
- // `DynamicFunction `s containing closures that capture their environment like this one
66
+ // `DynamicClosure `s that mutably capture their environment like this one
66
67
// may need to be dropped before those captured variables may be used again.
67
- // This can be done manually with `drop` or by using the `Function ::call_once` method.
68
- dbg ! ( increment_function . call_once( args) . unwrap( ) ) ;
68
+ // This can be done manually with `drop(closure) ` or by using the `DynamicClosure ::call_once` method.
69
+ dbg ! ( closure . call_once( args) . unwrap( ) ) ;
69
70
assert_eq ! ( count, 5 ) ;
70
71
72
+ // Note that `DynamicFunction` just requires a `'static` lifetime.
73
+ // This means that closures that capture variables by taking ownership of them
74
+ // can still be converted to a `DynamicFunction`.
75
+ let minimum = 5 ;
76
+ let clamp = move |value : i32 | value. max ( minimum) ;
77
+
78
+ let function: DynamicFunction = dbg ! ( clamp. into_function( ) ) ;
79
+ let args = dbg ! ( ArgList :: new( ) . push_owned( 2_i32 ) ) ;
80
+ let return_value = dbg ! ( function. call( args) . unwrap( ) ) ;
81
+ let value: Box < dyn Reflect > = return_value. unwrap_owned ( ) ;
82
+ assert_eq ! ( value. take:: <i32 >( ) . unwrap( ) , 5 ) ;
83
+
71
84
// As stated before, this works for many kinds of simple functions.
72
85
// Functions with non-reflectable arguments or return values may not be able to be converted.
73
- // Generic functions are also not supported.
86
+ // Generic functions are also not supported (unless manually monomorphized like `foo::<i32>.into_function()`) .
74
87
// Additionally, the lifetime of the return value is tied to the lifetime of the first argument.
75
88
// However, this means that many methods (i.e. functions with a `self` parameter) are also supported:
76
89
#[ derive( Reflect , Default ) ]
@@ -92,12 +105,12 @@ fn main() {
92
105
93
106
let mut data = Data :: default ( ) ;
94
107
95
- let mut set_value = dbg ! ( Data :: set_value. into_function( ) ) ;
108
+ let set_value = dbg ! ( Data :: set_value. into_function( ) ) ;
96
109
let args = dbg ! ( ArgList :: new( ) . push_mut( & mut data) ) . push_owned ( String :: from ( "Hello, world!" ) ) ;
97
110
dbg ! ( set_value. call( args) . unwrap( ) ) ;
98
111
assert_eq ! ( data. value, "Hello, world!" ) ;
99
112
100
- let mut get_value = dbg ! ( Data :: get_value. into_function( ) ) ;
113
+ let get_value = dbg ! ( Data :: get_value. into_function( ) ) ;
101
114
let args = dbg ! ( ArgList :: new( ) . push_ref( & data) ) ;
102
115
let return_value = dbg ! ( get_value. call( args) . unwrap( ) ) ;
103
116
let value: & dyn Reflect = return_value. unwrap_ref ( ) ;
@@ -115,7 +128,7 @@ fn main() {
115
128
container. as_ref ( ) . unwrap ( )
116
129
}
117
130
118
- let mut get_or_insert_function = dbg ! ( DynamicFunction :: new(
131
+ let get_or_insert_function = dbg ! ( DynamicFunction :: new(
119
132
|mut args, info| {
120
133
let container_info = & info. args( ) [ 1 ] ;
121
134
let value_info = & info. args( ) [ 0 ] ;
0 commit comments