@@ -13,7 +13,7 @@ use sys::{ffi_methods, ExtVariantType, GodotFfi};
1313use crate :: builtin:: { inner, GString , StringName , Variant , VariantArray } ;
1414use crate :: meta:: { GodotType , ToGodot } ;
1515use crate :: obj:: bounds:: DynMemory ;
16- use crate :: obj:: { Bounds , Gd , GodotClass , InstanceId } ;
16+ use crate :: obj:: { Bounds , Gd , GodotClass , InstanceId , Singleton } ;
1717use crate :: { classes, meta} ;
1818
1919#[ cfg( before_api = "4.3" ) ]
@@ -72,7 +72,7 @@ impl Callable {
7272 /// If the builtin type does not have the method, the returned callable will be invalid.
7373 ///
7474 /// Static builtin methods (e.g. `String.humanize_size`) are not supported in reflection as of Godot 4.4. For static _class_ functions,
75- /// use [`from_local_static ()`][Self::from_local_static ] instead.
75+ /// use [`from_class_static ()`][Self::from_class_static ] instead.
7676 ///
7777 /// _Godot equivalent: `Callable.create(Variant variant, StringName method)`_
7878 #[ cfg( since_api = "4.3" ) ]
@@ -84,17 +84,15 @@ impl Callable {
8484 inner:: InnerCallable :: create ( variant, method_name)
8585 }
8686
87- /// Create a callable for the static method `class_name::function` (single-threaded).
87+ /// Create a callable for the static method `class_name::function`
8888 ///
89- /// Allows you to call static functions through `Callable`.
89+ /// Allows you to call static functions through `Callable`. Allows both single- and multi-threaded calls; what happens on Godot side
90+ /// is your responsibility.
9091 ///
91- /// Does not support built-in types (such as `String`), only classes.
92- ///
93- /// # Compatibility
94- /// Not available before Godot 4.4. Library versions <0.3 used to provide this, however the polyfill used to emulate it was half-broken
95- /// (not supporting signals, bind(), method_name(), is_valid(), etc).
92+ /// Does not support built-in types (such as `String`), only classes. Static functions on built-in types are not supported in Godot's
93+ /// reflection APIs at the moment.
9694 #[ cfg( since_api = "4.4" ) ]
97- pub fn from_local_static (
95+ pub fn from_class_static (
9896 class_name : impl meta:: AsArg < StringName > ,
9997 function_name : impl meta:: AsArg < StringName > ,
10098 ) -> Self {
@@ -103,16 +101,33 @@ impl Callable {
103101
104102 let callable_name = format ! ( "{class_name}.{function_name}" ) ;
105103
106- Self :: from_local_fn ( & callable_name , move |args| {
104+ let function = move |args : & [ & Variant ] | {
107105 let args = args. iter ( ) . cloned ( ) . cloned ( ) . collect :: < Vec < _ > > ( ) ;
108106
109107 let result: Variant = classes:: ClassDb :: singleton ( ) . class_call_static (
110108 & class_name,
111109 & function_name,
112110 args. as_slice ( ) ,
113111 ) ;
114- Ok ( result)
115- } )
112+ result
113+ } ;
114+
115+ #[ cfg( feature = "experimental-threads" ) ]
116+ let callable = Self :: from_sync_fn ( & callable_name, function) ;
117+
118+ #[ cfg( not( feature = "experimental-threads" ) ) ]
119+ let callable = Self :: from_local_fn ( & callable_name, function) ;
120+
121+ callable
122+ }
123+
124+ #[ deprecated = "Renamed to `from_class_static`." ]
125+ #[ cfg( since_api = "4.4" ) ]
126+ pub fn from_local_static (
127+ class_name : impl meta:: AsArg < StringName > ,
128+ function_name : impl meta:: AsArg < StringName > ,
129+ ) -> Self {
130+ Self :: from_class_static ( class_name, function_name)
116131 }
117132
118133 fn default_callable_custom_info ( ) -> CallableCustomInfo {
@@ -139,14 +154,15 @@ impl Callable {
139154 ///
140155 /// This constructor only allows the callable to be invoked from the same thread as creating it. If you need to invoke it from any thread,
141156 /// use [`from_sync_fn`][Self::from_sync_fn] instead (requires crate feature `experimental-threads`; only enable if really needed).
142- pub fn from_local_fn < F , S > ( name : S , rust_function : F ) -> Self
157+ pub fn from_local_fn < R , F , S > ( name : S , rust_function : F ) -> Self
143158 where
144- F : ' static + FnMut ( & [ & Variant ] ) -> Result < Variant , ( ) > ,
159+ R : ToGodot ,
160+ F : ' static + FnMut ( & [ & Variant ] ) -> R ,
145161 S : meta:: AsArg < GString > ,
146162 {
147163 meta:: arg_into_owned!( name) ;
148164
149- Self :: from_fn_wrapper ( FnWrapper {
165+ Self :: from_fn_wrapper :: < F , R > ( FnWrapper {
150166 rust_function,
151167 name,
152168 thread_id : Some ( std:: thread:: current ( ) . id ( ) ) ,
@@ -165,12 +181,12 @@ impl Callable {
165181 pub fn from_linked_fn < F , T , S > ( name : S , linked_object : & Gd < T > , rust_function : F ) -> Self
166182 where
167183 T : GodotClass ,
168- F : ' static + FnMut ( & [ & Variant ] ) -> Result < Variant , ( ) > ,
184+ F : ' static + FnMut ( & [ & Variant ] ) -> Variant ,
169185 S : meta:: AsArg < GString > ,
170186 {
171187 meta:: arg_into_owned!( name) ;
172188
173- Self :: from_fn_wrapper ( FnWrapper {
189+ Self :: from_fn_wrapper :: < F , Variant > ( FnWrapper {
174190 rust_function,
175191 name,
176192 thread_id : Some ( std:: thread:: current ( ) . id ( ) ) ,
@@ -184,9 +200,10 @@ impl Callable {
184200 ///
185201 /// After the first invocation, subsequent calls will panic with a message indicating the callable has already been consumed. This is
186202 /// useful for deferred operations that should only execute once. For repeated execution, use [`from_local_fn()][Self::from_local_fn].
187- pub ( crate ) fn from_once_fn < F , S > ( name : S , rust_function : F ) -> Self
203+ pub ( crate ) fn from_once_fn < R , F , S > ( name : S , rust_function : F ) -> Self
188204 where
189- F : ' static + FnOnce ( & [ & Variant ] ) -> Result < Variant , ( ) > ,
205+ R : ToGodot ,
206+ F : ' static + FnOnce ( & [ & Variant ] ) -> R ,
190207 S : meta:: AsArg < GString > ,
191208 {
192209 meta:: arg_into_owned!( name) ;
@@ -196,6 +213,7 @@ impl Callable {
196213 let rust_fn_once = rust_fn_once
197214 . take ( )
198215 . expect ( "callable created with from_once_fn() has already been consumed" ) ;
216+
199217 rust_fn_once ( args)
200218 } )
201219 }
@@ -204,7 +222,7 @@ impl Callable {
204222 #[ doc( hidden) ]
205223 pub fn __once_fn < F , S > ( name : S , rust_function : F ) -> Self
206224 where
207- F : ' static + FnOnce ( & [ & Variant ] ) -> Result < Variant , ( ) > ,
225+ F : ' static + FnOnce ( & [ & Variant ] ) -> Variant ,
208226 S : meta:: AsArg < GString > ,
209227 {
210228 Self :: from_once_fn ( name, rust_function)
@@ -213,12 +231,12 @@ impl Callable {
213231 pub ( crate ) fn with_scoped_fn < S , F , Fc , R > ( name : S , rust_function : F , callable_usage : Fc ) -> R
214232 where
215233 S : meta:: AsArg < GString > ,
216- F : FnMut ( & [ & Variant ] ) -> Result < Variant , ( ) > ,
234+ F : FnMut ( & [ & Variant ] ) -> Variant ,
217235 Fc : FnOnce ( & Callable ) -> R ,
218236 {
219237 meta:: arg_into_owned!( name) ;
220238
221- let callable = Self :: from_fn_wrapper ( FnWrapper {
239+ let callable = Self :: from_fn_wrapper :: < F , Variant > ( FnWrapper {
222240 rust_function,
223241 name,
224242 thread_id : Some ( std:: thread:: current ( ) . id ( ) ) ,
@@ -248,14 +266,15 @@ impl Callable {
248266 /// });
249267 /// ```
250268 #[ cfg( feature = "experimental-threads" ) ]
251- pub fn from_sync_fn < F , S > ( name : S , rust_function : F ) -> Self
269+ pub fn from_sync_fn < R , F , S > ( name : S , rust_function : F ) -> Self
252270 where
253- F : ' static + Send + Sync + FnMut ( & [ & Variant ] ) -> Result < Variant , ( ) > ,
271+ R : ToGodot ,
272+ F : ' static + Send + Sync + FnMut ( & [ & Variant ] ) -> R ,
254273 S : meta:: AsArg < GString > ,
255274 {
256275 meta:: arg_into_owned!( name) ;
257276
258- Self :: from_fn_wrapper ( FnWrapper {
277+ Self :: from_fn_wrapper :: < F , R > ( FnWrapper {
259278 rust_function,
260279 name,
261280 thread_id : None ,
@@ -287,9 +306,10 @@ impl Callable {
287306 Self :: from_custom_info ( info)
288307 }
289308
290- fn from_fn_wrapper < F > ( inner : FnWrapper < F > ) -> Self
309+ fn from_fn_wrapper < F , R > ( inner : FnWrapper < F > ) -> Self
291310 where
292- F : FnMut ( & [ & Variant ] ) -> Result < Variant , ( ) > ,
311+ F : FnMut ( & [ & Variant ] ) -> R ,
312+ R : ToGodot ,
293313 {
294314 let object_id = inner. linked_object_id ( ) ;
295315
@@ -298,7 +318,7 @@ impl Callable {
298318 let info = CallableCustomInfo {
299319 object_id,
300320 callable_userdata : Box :: into_raw ( Box :: new ( userdata) ) as * mut std:: ffi:: c_void ,
301- call_func : Some ( rust_callable_call_fn :: < F > ) ,
321+ call_func : Some ( rust_callable_call_fn :: < F , R > ) ,
302322 free_func : Some ( rust_callable_destroy :: < FnWrapper < F > > ) ,
303323 to_string_func : Some ( rust_callable_to_string_named :: < F > ) ,
304324 is_valid_func : Some ( rust_callable_is_valid) ,
@@ -593,7 +613,7 @@ mod custom_callable {
593613 /// Return `Ok(...)` if the call succeeded, and `Err(())` otherwise.
594614 /// Error handling is mostly needed in case argument number or types mismatch.
595615 #[ allow( clippy:: result_unit_err) ] // TODO remove once there's a clear error type here.
596- fn invoke ( & mut self , args : & [ & Variant ] ) -> Result < Variant , ( ) > ;
616+ fn invoke ( & mut self , args : & [ & Variant ] ) -> Variant ;
597617
598618 // TODO(v0.3): add object_id().
599619
@@ -616,37 +636,44 @@ mod custom_callable {
616636 ) {
617637 let arg_refs: & [ & Variant ] = Variant :: borrow_ref_slice ( p_args, p_argument_count as usize ) ;
618638
619- let name = {
639+ #[ cfg( debug_assertions) ]
640+ let name = & {
620641 let c: & C = CallableUserdata :: inner_from_raw ( callable_userdata) ;
621642 c. to_string ( )
622643 } ;
623- let ctx = meta:: CallContext :: custom_callable ( name. as_str ( ) ) ;
644+ #[ cfg( not( debug_assertions) ) ]
645+ let name = "<optimized out>" ;
646+ let ctx = meta:: CallContext :: custom_callable ( name) ;
624647
625648 crate :: private:: handle_varcall_panic ( & ctx, & mut * r_error, move || {
626649 // Get the RustCallable again inside closure so it doesn't have to be UnwindSafe.
627650 let c: & mut C = CallableUserdata :: inner_from_raw ( callable_userdata) ;
628651 let result = c. invoke ( arg_refs) ;
629- meta:: varcall_return_checked ( result, r_return, r_error) ;
652+ meta:: varcall_return_checked ( Ok ( result) , r_return, r_error) ;
630653 Ok ( ( ) )
631654 } ) ;
632655 }
633656
634- pub unsafe extern "C" fn rust_callable_call_fn < F > (
657+ pub unsafe extern "C" fn rust_callable_call_fn < F , R > (
635658 callable_userdata : * mut std:: ffi:: c_void ,
636659 p_args : * const sys:: GDExtensionConstVariantPtr ,
637660 p_argument_count : sys:: GDExtensionInt ,
638661 r_return : sys:: GDExtensionVariantPtr ,
639662 r_error : * mut sys:: GDExtensionCallError ,
640663 ) where
641- F : FnMut ( & [ & Variant ] ) -> Result < Variant , ( ) > ,
664+ F : FnMut ( & [ & Variant ] ) -> R ,
665+ R : ToGodot ,
642666 {
643667 let arg_refs: & [ & Variant ] = Variant :: borrow_ref_slice ( p_args, p_argument_count as usize ) ;
644668
645- let name = {
669+ #[ cfg( debug_assertions) ]
670+ let name = & {
646671 let w: & FnWrapper < F > = CallableUserdata :: inner_from_raw ( callable_userdata) ;
647672 w. name . to_string ( )
648673 } ;
649- let ctx = meta:: CallContext :: custom_callable ( name. as_str ( ) ) ;
674+ #[ cfg( not( debug_assertions) ) ]
675+ let name = "<optimized out>" ;
676+ let ctx = meta:: CallContext :: custom_callable ( name) ;
650677
651678 crate :: private:: handle_varcall_panic ( & ctx, & mut * r_error, move || {
652679 // Get the FnWrapper again inside closure so the FnMut doesn't have to be UnwindSafe.
@@ -664,8 +691,8 @@ mod custom_callable {
664691 ) ;
665692 }
666693
667- let result = ( w. rust_function ) ( arg_refs) ;
668- meta:: varcall_return_checked ( result, r_return, r_error) ;
694+ let result = ( w. rust_function ) ( arg_refs) . to_variant ( ) ;
695+ meta:: varcall_return_checked ( Ok ( result) , r_return, r_error) ;
669696 Ok ( ( ) )
670697 } ) ;
671698 }
0 commit comments