8
8
use godot_ffi as sys;
9
9
10
10
use crate :: builtin:: { inner, GString , StringName , Variant , VariantArray } ;
11
- use crate :: classes:: Object ;
12
- use crate :: meta:: { AsArg , CallContext , GodotType , ToGodot } ;
11
+ use crate :: classes;
12
+ use crate :: meta:: { GodotType , ToGodot } ;
13
13
use crate :: obj:: bounds:: DynMemory ;
14
14
use crate :: obj:: Bounds ;
15
15
use crate :: obj:: { Gd , GodotClass , InstanceId } ;
@@ -43,7 +43,7 @@ impl Callable {
43
43
Self { opaque }
44
44
}
45
45
46
- /// Create a callable for the method `object:: method_name`.
46
+ /// Create a callable for the non-static method `object. method_name`.
47
47
///
48
48
/// See also [`Gd::callable()`].
49
49
///
@@ -65,6 +65,55 @@ impl Callable {
65
65
}
66
66
}
67
67
68
+ /// Create a callable for the static method `class_name::function` (single-threaded).
69
+ ///
70
+ /// Allows you to call static functions through `Callable`.
71
+ ///
72
+ /// Note that due to varying support across different engine versions, the resulting `Callable` has unspecified behavior for
73
+ /// methods such as [`method_name()`][Self::method_name], [`object()`][Self::object], [`object_id()`][Self::object_id] or
74
+ /// [`get_argument_count()`][Self::arg_len] among others. It is recommended to only use this for calling the function.
75
+ pub fn from_local_static (
76
+ class_name : impl meta:: AsArg < StringName > ,
77
+ function_name : impl meta:: AsArg < StringName > ,
78
+ ) -> Self {
79
+ meta:: arg_into_owned!( class_name) ;
80
+ meta:: arg_into_owned!( function_name) ;
81
+
82
+ // Modern implementation: use ClassDb::class_call_static().
83
+ #[ cfg( since_api = "4.4" ) ]
84
+ {
85
+ let callable_name = format ! ( "{class_name}.{function_name}" ) ;
86
+
87
+ Self :: from_local_fn ( & callable_name, move |args| {
88
+ let args = args. iter ( ) . cloned ( ) . cloned ( ) . collect :: < Vec < _ > > ( ) ;
89
+
90
+ let result: Variant = classes:: ClassDb :: singleton ( ) . class_call_static (
91
+ & class_name,
92
+ & function_name,
93
+ args. as_slice ( ) ,
94
+ ) ;
95
+ Ok ( result)
96
+ } )
97
+ }
98
+
99
+ // Polyfill for <= Godot 4.3: use GDScript expressions.
100
+ #[ cfg( before_api = "4.4" ) ]
101
+ {
102
+ use crate :: obj:: NewGd ;
103
+
104
+ let code = format ! (
105
+ "static func __callable():\n \t return Callable({class_name}, \" {function_name}\" )"
106
+ ) ;
107
+
108
+ let mut script = classes:: GDScript :: new_gd ( ) ;
109
+ script. set_source_code ( & code) ;
110
+ script. reload ( ) ;
111
+
112
+ let callable = script. call ( "__callable" , & [ ] ) ;
113
+ callable. to ( )
114
+ }
115
+ }
116
+
68
117
#[ cfg( since_api = "4.2" ) ]
69
118
fn default_callable_custom_info ( ) -> CallableCustomInfo {
70
119
CallableCustomInfo {
@@ -94,7 +143,7 @@ impl Callable {
94
143
pub fn from_local_fn < F , S > ( name : S , rust_function : F ) -> Self
95
144
where
96
145
F : ' static + FnMut ( & [ & Variant ] ) -> Result < Variant , ( ) > ,
97
- S : AsArg < GString > ,
146
+ S : meta :: AsArg < GString > ,
98
147
{
99
148
meta:: arg_into_owned!( name) ;
100
149
@@ -129,7 +178,7 @@ impl Callable {
129
178
pub fn from_sync_fn < F , S > ( name : S , rust_function : F ) -> Self
130
179
where
131
180
F : ' static + Send + Sync + FnMut ( & [ & Variant ] ) -> Result < Variant , ( ) > ,
132
- S : AsArg < GString > ,
181
+ S : meta :: AsArg < GString > ,
133
182
{
134
183
meta:: arg_into_owned!( name) ;
135
184
@@ -273,11 +322,11 @@ impl Callable {
273
322
/// target or not). Also returns `None` if the object is dead. You can differentiate these two cases using [`object_id()`][Self::object_id].
274
323
///
275
324
/// _Godot equivalent: `get_object`_
276
- pub fn object ( & self ) -> Option < Gd < Object > > {
325
+ pub fn object ( & self ) -> Option < Gd < classes :: Object > > {
277
326
// Increment refcount because we're getting a reference, and `InnerCallable::get_object` doesn't
278
327
// increment the refcount.
279
328
self . as_inner ( ) . get_object ( ) . map ( |mut object| {
280
- <Object as Bounds >:: DynMemory :: maybe_inc_ref ( & mut object. raw ) ;
329
+ <classes :: Object as Bounds >:: DynMemory :: maybe_inc_ref ( & mut object. raw ) ;
281
330
object
282
331
} )
283
332
}
@@ -482,7 +531,7 @@ mod custom_callable {
482
531
let c: & C = CallableUserdata :: inner_from_raw ( callable_userdata) ;
483
532
c. to_string ( )
484
533
} ;
485
- let ctx = CallContext :: custom_callable ( name. as_str ( ) ) ;
534
+ let ctx = meta :: CallContext :: custom_callable ( name. as_str ( ) ) ;
486
535
487
536
crate :: private:: handle_varcall_panic ( & ctx, & mut * r_error, move || {
488
537
// Get the RustCallable again inside closure so it doesn't have to be UnwindSafe.
@@ -508,7 +557,7 @@ mod custom_callable {
508
557
let w: & FnWrapper < F > = CallableUserdata :: inner_from_raw ( callable_userdata) ;
509
558
w. name . to_string ( )
510
559
} ;
511
- let ctx = CallContext :: custom_callable ( name. as_str ( ) ) ;
560
+ let ctx = meta :: CallContext :: custom_callable ( name. as_str ( ) ) ;
512
561
513
562
crate :: private:: handle_varcall_panic ( & ctx, & mut * r_error, move || {
514
563
// Get the FnWrapper again inside closure so the FnMut doesn't have to be UnwindSafe.
0 commit comments