1- use std:: { borrow:: Cow , sync:: Arc } ;
2-
3- use bevy:: reflect:: func:: {
4- args:: { Arg , ArgInfo , Ownership } ,
5- ArgList , ArgValue , DynamicFunction , FunctionResult , Return ,
1+ use std:: { borrow:: Cow , ops:: Deref , sync:: Arc } ;
2+
3+ use bevy:: reflect:: {
4+ func:: {
5+ args:: { Arg , ArgInfo , Ownership } ,
6+ ArgList , ArgValue , DynamicFunction , FunctionResult , Return ,
7+ } ,
8+ PartialReflect ,
69} ;
710
8- use crate :: error:: { ScriptError , ScriptResult } ;
11+ use crate :: error:: { ScriptError , ScriptResult , ValueConversionError } ;
912
1013use super :: {
11- access_map:: ReflectAccessId , pretty_print:: DisplayWithWorld , script_val:: ScriptValue ,
14+ access_map:: ReflectAccessId ,
15+ pretty_print:: DisplayWithWorld ,
16+ script_val:: { FromScriptValue , IntoScriptValue , ScriptValue } ,
1217 ReflectBase , ReflectReference , WorldAccessGuard , WorldCallbackAccess , WorldGuard ,
1318} ;
1419
@@ -22,6 +27,18 @@ pub trait CallableWithAccess {
2227 world : Arc < WorldAccessGuard > ,
2328 f : F ,
2429 ) -> ScriptResult < O > ;
30+
31+ fn dynamic_call < I : IntoIterator < Item = ScriptValue > > (
32+ & self ,
33+ args : I ,
34+ world : Arc < WorldAccessGuard > ,
35+ ) -> ScriptResult < ScriptValue > {
36+ self . with_call ( args, world. clone ( ) , |r| match r {
37+ Return :: Owned ( partial_reflect) => partial_reflect. as_ref ( ) . into_script_value ( world) ,
38+ Return :: Ref ( ref_) => ref_. into_script_value ( world) ,
39+ Return :: Mut ( mut_ref) => mut_ref. into_script_value ( world) ,
40+ } ) ?
41+ }
2542}
2643
2744impl CallableWithAccess for DynamicFunction < ' _ > {
@@ -33,14 +50,6 @@ impl CallableWithAccess for DynamicFunction<'_> {
3350 ) -> ScriptResult < O > {
3451 let info = self . info ( ) . args ( ) ;
3552
36- // if info.len() != args.len() {
37- // return Err(ScriptError::new_reflection_error(format!(
38- // "Expected {} arguments, got {}",
39- // info.len(),
40- // args.len()
41- // )));
42- // }
43-
4453 // We need to:
4554 // 1. Claim the correct access for each argument
4655 // 2. Convert to ArgsList for the function call
@@ -50,10 +59,28 @@ impl CallableWithAccess for DynamicFunction<'_> {
5059 // 6. Return the result
5160 let arg_iter = args. into_iter ( ) ;
5261
53- let ( args_list, mut accesses) = arg_iter . into_args_list_with_access ( info , world . clone ( ) ) ? ;
54- // let arc_world = &arc_world ;
62+ let ( mut args_list, mut accesses) =
63+ arg_iter . into_args_list_with_access ( info , world . clone ( ) ) ? ;
5564
56- let return_val = match self . call ( args_list) {
65+ let mut final_args_list = ArgList :: default ( ) ;
66+ // we sometimes want to use the boxed value in the arg instead of allocating and refing to it.
67+ // for this reason let's be lenient in calling functions. Allow passing owned values as refs
68+ for ( arg, info) in args_list. iter_mut ( ) . zip ( info. iter ( ) ) {
69+ let next_arg = match ( arg, info. ownership ( ) ) {
70+ ( ArgValue :: Owned ( r) , Ownership :: Ref ) => {
71+ ArgValue :: Ref ( ( r as & Box < dyn PartialReflect > ) . as_ref ( ) )
72+ }
73+ ( ArgValue :: Owned ( r) , Ownership :: Mut ) => ArgValue :: Mut ( r. as_mut ( ) ) ,
74+ ( v, _) => {
75+ // muahaha, shouldn't allocate due to ZST
76+ let a = std:: mem:: replace ( v, ArgValue :: Owned ( Box :: new ( ( ) ) ) ) ;
77+ a
78+ }
79+ } ;
80+ final_args_list = final_args_list. push_arg ( next_arg) ;
81+ }
82+
83+ let return_val = match self . call ( final_args_list) {
5784 Ok ( return_val) => return_val,
5885 Err ( e) => {
5986 // Safety: we have not generated any unsafe aliases
@@ -85,7 +112,7 @@ pub trait IntoArgsListWithAccess {
85112 self ,
86113 arg_info : & [ ArgInfo ] ,
87114 world : WorldGuard < ' w > ,
88- ) -> ScriptResult < ( ArgList < ' w > , Vec < ( ReflectAccessId , Ownership ) > ) > ;
115+ ) -> ScriptResult < ( Vec < ArgValue < ' w > > , Vec < ( ReflectAccessId , Ownership ) > ) > ;
89116}
90117
91118impl < I : Iterator < Item = ScriptValue > > IntoArgsListWithAccess for I {
@@ -97,17 +124,16 @@ impl<I: Iterator<Item = ScriptValue>> IntoArgsListWithAccess for I {
97124 self ,
98125 arg_info : & [ ArgInfo ] ,
99126 world : WorldGuard < ' w > ,
100- ) -> ScriptResult < ( ArgList < ' w > , Vec < ( ReflectAccessId , Ownership ) > ) > {
101- // if self.len() != arg_info.len() {
102- // return Err(ScriptError::new_reflection_error(format!(
103- // "Expected {} arguments, got {}",
104- // arg_info.len(),
105- // self.len()
106- // )));
107- // }
108-
127+ ) -> ScriptResult < ( Vec < ArgValue < ' w > > , Vec < ( ReflectAccessId , Ownership ) > ) > {
109128 let mut accesses = Vec :: default ( ) ;
110- let mut arg_list = ArgList :: new ( ) ;
129+ let mut arg_list = Vec :: default ( ) ;
130+
131+ let release_accesses = |accesses : & mut Vec < ( ReflectAccessId , Ownership ) > | {
132+ accesses. iter ( ) . for_each ( |( id, _) | {
133+ // Safety: we have not generated any unsafe aliases
134+ unsafe { world. release_access ( * id) } ;
135+ } ) ;
136+ } ;
111137
112138 for ( value, arg_info) in self . zip ( arg_info. iter ( ) ) {
113139 match value {
@@ -116,7 +142,7 @@ impl<I: Iterator<Item = ScriptValue>> IntoArgsListWithAccess for I {
116142 ReflectAccessId :: for_reference ( arg_ref. base . base_id . clone ( ) ) . ok_or_else ( || {
117143 ScriptError :: new_reflection_error ( format ! (
118144 "Could not call function, argument: {:?}, with type: {} is not a valid reference. Have you registered the type?" ,
119- arg_info. name( ) ,
145+ arg_info. name( ) . map ( str :: to_owned ) . unwrap_or_else ( || arg_info . index ( ) . to_string ( ) ) ,
120146 arg_ref. display_with_world( world. clone( ) )
121147 ) )
122148 } ) ?;
@@ -130,10 +156,7 @@ impl<I: Iterator<Item = ScriptValue>> IntoArgsListWithAccess for I {
130156 } ;
131157
132158 if !success {
133- accesses. drain ( ..) . for_each ( |( id, _) | {
134- // Safety: we have not generated any unsafe aliases
135- unsafe { world. release_access ( id) } ;
136- } ) ;
159+ release_accesses ( & mut accesses) ;
137160 return Err ( ScriptError :: new_reflection_error ( format ! (
138161 "Could not claim access for argument {}" ,
139162 arg_ref. display_with_world( world. clone( ) )
@@ -146,22 +169,43 @@ impl<I: Iterator<Item = ScriptValue>> IntoArgsListWithAccess for I {
146169 let val = match val {
147170 Ok ( v) => v,
148171 Err ( e) => {
172+ release_accesses ( & mut accesses) ;
173+ return Err ( e) ;
174+ }
175+ } ;
176+ arg_list. push ( val) ;
177+ }
178+ ScriptValue :: World => {
179+ arg_list. push ( ArgValue :: Owned ( Box :: new ( WorldCallbackAccess :: from_guard (
180+ world. clone ( ) ,
181+ ) ) ) ) ;
182+ }
183+ value => {
184+ let value = match <dyn PartialReflect >:: from_script_value (
185+ value,
186+ world. clone ( ) ,
187+ arg_info. type_id ( ) ,
188+ ) {
189+ Some ( Ok ( v) ) => v,
190+ Some ( Err ( e) ) => {
149191 // Safety: Same as above
150-
151192 accesses. iter ( ) . for_each ( |( id, _) | {
152193 unsafe { world. release_access ( * id) } ;
153194 } ) ;
154195 return Err ( e) ;
155196 }
197+ None => {
198+ release_accesses ( & mut accesses) ;
199+ return Err ( ValueConversionError :: TypeMismatch {
200+ expected_type : arg_info. type_path ( ) . into ( ) ,
201+ actual_type : None ,
202+ }
203+ . into ( ) ) ;
204+ }
156205 } ;
157- arg_list = arg_list. push_arg ( val) ;
158- }
159- ScriptValue :: World => {
160- arg_list = arg_list. push_arg ( ArgValue :: Owned ( Box :: new (
161- WorldCallbackAccess :: from_guard ( world. clone ( ) ) ,
162- ) ) ) ;
206+
207+ arg_list. push ( ArgValue :: Owned ( value) ) ;
163208 }
164- v => todo ! ( ) ,
165209 }
166210 }
167211
0 commit comments