@@ -13,7 +13,7 @@ use sys::{ffi_methods, ExtVariantType, GodotFfi};
13
13
use crate :: builtin:: { inner, GString , StringName , Variant , VariantArray } ;
14
14
use crate :: meta:: { GodotType , ToGodot } ;
15
15
use crate :: obj:: bounds:: DynMemory ;
16
- use crate :: obj:: { Bounds , Gd , GodotClass , InstanceId } ;
16
+ use crate :: obj:: { Bounds , Gd , GodotClass , InstanceId , Singleton } ;
17
17
use crate :: { classes, meta} ;
18
18
19
19
#[ cfg( before_api = "4.3" ) ]
@@ -72,7 +72,7 @@ impl Callable {
72
72
/// If the builtin type does not have the method, the returned callable will be invalid.
73
73
///
74
74
/// 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.
76
76
///
77
77
/// _Godot equivalent: `Callable.create(Variant variant, StringName method)`_
78
78
#[ cfg( since_api = "4.3" ) ]
@@ -84,17 +84,15 @@ impl Callable {
84
84
inner:: InnerCallable :: create ( variant, method_name)
85
85
}
86
86
87
- /// Create a callable for the static method `class_name::function` (single-threaded).
87
+ /// Create a callable for the static method `class_name::function`
88
88
///
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.
90
91
///
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.
96
94
#[ cfg( since_api = "4.4" ) ]
97
- pub fn from_local_static (
95
+ pub fn from_class_static (
98
96
class_name : impl meta:: AsArg < StringName > ,
99
97
function_name : impl meta:: AsArg < StringName > ,
100
98
) -> Self {
@@ -103,16 +101,33 @@ impl Callable {
103
101
104
102
let callable_name = format ! ( "{class_name}.{function_name}" ) ;
105
103
106
- Self :: from_local_fn ( & callable_name , move |args| {
104
+ let function = move |args : & [ & Variant ] | {
107
105
let args = args. iter ( ) . cloned ( ) . cloned ( ) . collect :: < Vec < _ > > ( ) ;
108
106
109
107
let result: Variant = classes:: ClassDb :: singleton ( ) . class_call_static (
110
108
& class_name,
111
109
& function_name,
112
110
args. as_slice ( ) ,
113
111
) ;
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)
116
131
}
117
132
118
133
fn default_callable_custom_info ( ) -> CallableCustomInfo {
@@ -139,14 +154,15 @@ impl Callable {
139
154
///
140
155
/// 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,
141
156
/// 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
143
158
where
144
- F : ' static + FnMut ( & [ & Variant ] ) -> Result < Variant , ( ) > ,
159
+ R : ToGodot ,
160
+ F : ' static + FnMut ( & [ & Variant ] ) -> R ,
145
161
S : meta:: AsArg < GString > ,
146
162
{
147
163
meta:: arg_into_owned!( name) ;
148
164
149
- Self :: from_fn_wrapper ( FnWrapper {
165
+ Self :: from_fn_wrapper :: < F , R > ( FnWrapper {
150
166
rust_function,
151
167
name,
152
168
thread_id : Some ( std:: thread:: current ( ) . id ( ) ) ,
@@ -165,12 +181,12 @@ impl Callable {
165
181
pub fn from_linked_fn < F , T , S > ( name : S , linked_object : & Gd < T > , rust_function : F ) -> Self
166
182
where
167
183
T : GodotClass ,
168
- F : ' static + FnMut ( & [ & Variant ] ) -> Result < Variant , ( ) > ,
184
+ F : ' static + FnMut ( & [ & Variant ] ) -> Variant ,
169
185
S : meta:: AsArg < GString > ,
170
186
{
171
187
meta:: arg_into_owned!( name) ;
172
188
173
- Self :: from_fn_wrapper ( FnWrapper {
189
+ Self :: from_fn_wrapper :: < F , Variant > ( FnWrapper {
174
190
rust_function,
175
191
name,
176
192
thread_id : Some ( std:: thread:: current ( ) . id ( ) ) ,
@@ -184,9 +200,10 @@ impl Callable {
184
200
///
185
201
/// After the first invocation, subsequent calls will panic with a message indicating the callable has already been consumed. This is
186
202
/// 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
188
204
where
189
- F : ' static + FnOnce ( & [ & Variant ] ) -> Result < Variant , ( ) > ,
205
+ R : ToGodot ,
206
+ F : ' static + FnOnce ( & [ & Variant ] ) -> R ,
190
207
S : meta:: AsArg < GString > ,
191
208
{
192
209
meta:: arg_into_owned!( name) ;
@@ -196,6 +213,7 @@ impl Callable {
196
213
let rust_fn_once = rust_fn_once
197
214
. take ( )
198
215
. expect ( "callable created with from_once_fn() has already been consumed" ) ;
216
+
199
217
rust_fn_once ( args)
200
218
} )
201
219
}
@@ -204,7 +222,7 @@ impl Callable {
204
222
#[ doc( hidden) ]
205
223
pub fn __once_fn < F , S > ( name : S , rust_function : F ) -> Self
206
224
where
207
- F : ' static + FnOnce ( & [ & Variant ] ) -> Result < Variant , ( ) > ,
225
+ F : ' static + FnOnce ( & [ & Variant ] ) -> Variant ,
208
226
S : meta:: AsArg < GString > ,
209
227
{
210
228
Self :: from_once_fn ( name, rust_function)
@@ -213,12 +231,12 @@ impl Callable {
213
231
pub ( crate ) fn with_scoped_fn < S , F , Fc , R > ( name : S , rust_function : F , callable_usage : Fc ) -> R
214
232
where
215
233
S : meta:: AsArg < GString > ,
216
- F : FnMut ( & [ & Variant ] ) -> Result < Variant , ( ) > ,
234
+ F : FnMut ( & [ & Variant ] ) -> Variant ,
217
235
Fc : FnOnce ( & Callable ) -> R ,
218
236
{
219
237
meta:: arg_into_owned!( name) ;
220
238
221
- let callable = Self :: from_fn_wrapper ( FnWrapper {
239
+ let callable = Self :: from_fn_wrapper :: < F , Variant > ( FnWrapper {
222
240
rust_function,
223
241
name,
224
242
thread_id : Some ( std:: thread:: current ( ) . id ( ) ) ,
@@ -248,14 +266,15 @@ impl Callable {
248
266
/// });
249
267
/// ```
250
268
#[ 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
252
270
where
253
- F : ' static + Send + Sync + FnMut ( & [ & Variant ] ) -> Result < Variant , ( ) > ,
271
+ R : ToGodot ,
272
+ F : ' static + Send + Sync + FnMut ( & [ & Variant ] ) -> R ,
254
273
S : meta:: AsArg < GString > ,
255
274
{
256
275
meta:: arg_into_owned!( name) ;
257
276
258
- Self :: from_fn_wrapper ( FnWrapper {
277
+ Self :: from_fn_wrapper :: < F , R > ( FnWrapper {
259
278
rust_function,
260
279
name,
261
280
thread_id : None ,
@@ -287,9 +306,10 @@ impl Callable {
287
306
Self :: from_custom_info ( info)
288
307
}
289
308
290
- fn from_fn_wrapper < F > ( inner : FnWrapper < F > ) -> Self
309
+ fn from_fn_wrapper < F , R > ( inner : FnWrapper < F > ) -> Self
291
310
where
292
- F : FnMut ( & [ & Variant ] ) -> Result < Variant , ( ) > ,
311
+ F : FnMut ( & [ & Variant ] ) -> R ,
312
+ R : ToGodot ,
293
313
{
294
314
let object_id = inner. linked_object_id ( ) ;
295
315
@@ -298,7 +318,7 @@ impl Callable {
298
318
let info = CallableCustomInfo {
299
319
object_id,
300
320
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 > ) ,
302
322
free_func : Some ( rust_callable_destroy :: < FnWrapper < F > > ) ,
303
323
to_string_func : Some ( rust_callable_to_string_named :: < F > ) ,
304
324
is_valid_func : Some ( rust_callable_is_valid) ,
@@ -593,7 +613,7 @@ mod custom_callable {
593
613
/// Return `Ok(...)` if the call succeeded, and `Err(())` otherwise.
594
614
/// Error handling is mostly needed in case argument number or types mismatch.
595
615
#[ 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 ;
597
617
598
618
// TODO(v0.3): add object_id().
599
619
@@ -616,37 +636,44 @@ mod custom_callable {
616
636
) {
617
637
let arg_refs: & [ & Variant ] = Variant :: borrow_ref_slice ( p_args, p_argument_count as usize ) ;
618
638
619
- let name = {
639
+ #[ cfg( debug_assertions) ]
640
+ let name = & {
620
641
let c: & C = CallableUserdata :: inner_from_raw ( callable_userdata) ;
621
642
c. to_string ( )
622
643
} ;
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) ;
624
647
625
648
crate :: private:: handle_varcall_panic ( & ctx, & mut * r_error, move || {
626
649
// Get the RustCallable again inside closure so it doesn't have to be UnwindSafe.
627
650
let c: & mut C = CallableUserdata :: inner_from_raw ( callable_userdata) ;
628
651
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) ;
630
653
Ok ( ( ) )
631
654
} ) ;
632
655
}
633
656
634
- pub unsafe extern "C" fn rust_callable_call_fn < F > (
657
+ pub unsafe extern "C" fn rust_callable_call_fn < F , R > (
635
658
callable_userdata : * mut std:: ffi:: c_void ,
636
659
p_args : * const sys:: GDExtensionConstVariantPtr ,
637
660
p_argument_count : sys:: GDExtensionInt ,
638
661
r_return : sys:: GDExtensionVariantPtr ,
639
662
r_error : * mut sys:: GDExtensionCallError ,
640
663
) where
641
- F : FnMut ( & [ & Variant ] ) -> Result < Variant , ( ) > ,
664
+ F : FnMut ( & [ & Variant ] ) -> R ,
665
+ R : ToGodot ,
642
666
{
643
667
let arg_refs: & [ & Variant ] = Variant :: borrow_ref_slice ( p_args, p_argument_count as usize ) ;
644
668
645
- let name = {
669
+ #[ cfg( debug_assertions) ]
670
+ let name = & {
646
671
let w: & FnWrapper < F > = CallableUserdata :: inner_from_raw ( callable_userdata) ;
647
672
w. name . to_string ( )
648
673
} ;
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) ;
650
677
651
678
crate :: private:: handle_varcall_panic ( & ctx, & mut * r_error, move || {
652
679
// Get the FnWrapper again inside closure so the FnMut doesn't have to be UnwindSafe.
@@ -664,8 +691,8 @@ mod custom_callable {
664
691
) ;
665
692
}
666
693
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) ;
669
696
Ok ( ( ) )
670
697
} ) ;
671
698
}
0 commit comments