6
6
7
7
use godot_ffi as sys;
8
8
9
- use crate :: builtin:: { inner, ToVariant , Variant } ;
9
+ use crate :: builtin:: { inner, StringName , ToVariant , Variant , VariantArray } ;
10
10
use crate :: engine:: Object ;
11
11
use crate :: obj:: mem:: Memory ;
12
12
use crate :: obj:: { Gd , GodotClass , InstanceId } ;
13
- use std:: fmt;
13
+ use std:: { fmt, ptr } ;
14
14
use sys:: { ffi_methods, GodotFfi } ;
15
15
16
- use super :: { StringName , VariantArray } ;
17
-
18
16
/// A `Callable` represents a function in Godot.
19
17
///
20
18
/// Usually a callable is a reference to an `Object` and a method name, this is a standard callable. But can
@@ -53,14 +51,47 @@ impl Callable {
53
51
}
54
52
}
55
53
54
+ /// Create a callable representing a Rust function.
55
+ // #[cfg(since_api = "4.2")]
56
+ pub fn from_custom < C : RustCallable > ( callable : C ) -> Self {
57
+ // Double box could be avoided if we propagate C through all functions.
58
+ let wrapper = CallableUserdata {
59
+ callable : Box :: new ( callable) ,
60
+ } ;
61
+ Self :: from_custom_inner ( Box :: new ( wrapper) )
62
+ }
63
+
64
+ // #[cfg(since_api = "4.2")]
65
+ fn from_custom_inner ( callable : Box < CallableUserdata > ) -> Self {
66
+ let mut info = sys:: GDExtensionCallableCustomInfo {
67
+ callable_userdata : Box :: into_raw ( callable) as * mut std:: ffi:: c_void ,
68
+ token : ptr:: null_mut ( ) ,
69
+ object : ptr:: null_mut ( ) ,
70
+ call_func : Some ( rust_callable_call) ,
71
+ is_valid_func : None ,
72
+ free_func : Some ( rust_callable_destroy) ,
73
+ hash_func : Some ( rust_callable_hash) ,
74
+ equal_func : Some ( rust_callable_equal) ,
75
+ // < is only used in niche scenarios and default is usually good enough, see https://github.com/godotengine/godot/issues/81901.
76
+ less_than_func : None ,
77
+ to_string_func : Some ( rust_callable_to_string) ,
78
+ } ;
79
+
80
+ unsafe {
81
+ Callable :: from_sys_init ( |type_ptr| {
82
+ sys:: interface_fn!( callable_custom_create) ( type_ptr, ptr:: addr_of_mut!( info) )
83
+ } )
84
+ }
85
+ }
86
+
56
87
/// Creates an invalid/empty object that is not able to be called.
57
88
///
58
89
/// _Godot equivalent: `Callable()`_
59
90
pub fn invalid ( ) -> Self {
60
91
unsafe {
61
92
Self :: from_sys_init ( |self_ptr| {
62
- let ctor = :: godot_ffi :: builtin_fn!( callable_construct_default) ;
63
- ctor ( self_ptr, std :: ptr:: null_mut ( ) )
93
+ let ctor = sys :: builtin_fn!( callable_construct_default) ;
94
+ ctor ( self_ptr, ptr:: null_mut ( ) )
64
95
} )
65
96
}
66
97
}
@@ -177,13 +208,10 @@ impl_builtin_traits! {
177
208
// Currently no Default::default() to encourage explicit valid initialization.
178
209
//Default => callable_construct_default;
179
210
180
- // Equality for custom callables depend on the equality implementation of that custom callable. This
181
- // is from what i can tell currently implemented as total equality in all cases, but i dont believe
182
- // there are any guarantees that all implementations of equality for custom callables will be.
183
- //
184
- // So we cannot implement `Eq` here and be confident equality will be total for all future custom
185
- // callables.
211
+ // Equality for custom callables depend on the equality implementation of that custom callable.
212
+ // So we cannot implement `Eq` here and be confident equality will be total for all future custom callables.
186
213
PartialEq => callable_operator_equal;
214
+ // PartialOrd => callable_operator_less;
187
215
Clone => callable_construct_copy;
188
216
Drop => callable_destroy;
189
217
}
@@ -202,7 +230,7 @@ unsafe impl GodotFfi for Callable {
202
230
}
203
231
}
204
232
205
- impl std :: fmt:: Debug for Callable {
233
+ impl fmt:: Debug for Callable {
206
234
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
207
235
let method = self . method_name ( ) ;
208
236
let object = self . object ( ) ;
@@ -214,8 +242,104 @@ impl std::fmt::Debug for Callable {
214
242
}
215
243
}
216
244
217
- impl std :: fmt:: Display for Callable {
245
+ impl fmt:: Display for Callable {
218
246
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
219
247
write ! ( f, "{}" , self . to_variant( ) )
220
248
}
221
249
}
250
+
251
+ // ----------------------------------------------------------------------------------------------------------------------------------------------
252
+ // Callbacks for custom implementations
253
+
254
+ // #[cfg(since_api = "4.2")]
255
+ use custom_callable:: * ;
256
+
257
+ // #[cfg(since_api = "4.2")]
258
+ pub use custom_callable:: RustCallable ;
259
+
260
+ // #[cfg(since_api = "4.2")]
261
+ mod custom_callable {
262
+ use super :: * ;
263
+ use crate :: builtin:: GodotString ;
264
+ use std:: hash:: Hash ;
265
+
266
+ pub struct CallableUserdata {
267
+ pub callable : Box < dyn RustCallable > ,
268
+ }
269
+
270
+ impl CallableUserdata {
271
+ unsafe fn inner_from_raw < ' a > ( void_ptr : * mut std:: ffi:: c_void ) -> & ' a dyn RustCallable {
272
+ let ptr = void_ptr as * mut CallableUserdata ;
273
+ & ( * ptr) . callable
274
+ }
275
+ }
276
+
277
+ pub trait RustCallable :
278
+ ' static + Sized + PartialEq + Hash + fmt:: Display + Send + Sync
279
+ where
280
+ Self : Sized ,
281
+ {
282
+ fn invoke ( & mut self , args : & [ & Variant ] ) -> Result < Variant , ( ) > ;
283
+ }
284
+
285
+ pub unsafe extern "C" fn rust_callable_call (
286
+ callable_userdata : * mut std:: ffi:: c_void ,
287
+ p_args : * const sys:: GDExtensionConstVariantPtr ,
288
+ p_argument_count : sys:: GDExtensionInt ,
289
+ r_return : sys:: GDExtensionVariantPtr ,
290
+ r_error : * mut sys:: GDExtensionCallError ,
291
+ ) {
292
+ let arg_refs: & [ & Variant ] =
293
+ Variant :: unbounded_refs_from_sys ( p_args, p_argument_count as usize ) ;
294
+
295
+ let mut c = CallableUserdata :: inner_from_raw ( callable_userdata) ;
296
+
297
+ let result = c. invoke ( arg_refs) ;
298
+ crate :: builtin:: meta:: varcall_return_checked ( result, r_return, r_error) ;
299
+ }
300
+
301
+ pub unsafe extern "C" fn rust_callable_destroy ( callable_userdata : * mut std:: ffi:: c_void ) {
302
+ let rust_ptr = callable_userdata as * mut CallableUserdata ;
303
+ let _drop = Box :: from_raw ( rust_ptr) ;
304
+ }
305
+
306
+ pub unsafe extern "C" fn rust_callable_hash ( callable_userdata : * mut std:: ffi:: c_void ) -> u32 {
307
+ let c = CallableUserdata :: inner_from_raw ( callable_userdata) ;
308
+
309
+ // Just cut off top bits, not best-possible hash.
310
+ sys:: hash_value ( c) as u32
311
+ }
312
+
313
+ pub unsafe extern "C" fn rust_callable_equal (
314
+ callable_userdata_a : * mut std:: ffi:: c_void ,
315
+ callable_userdata_b : * mut std:: ffi:: c_void ,
316
+ ) -> sys:: GDExtensionBool {
317
+ let a = CallableUserdata :: inner_from_raw ( callable_userdata_a) ;
318
+ let b = CallableUserdata :: inner_from_raw ( callable_userdata_b) ;
319
+
320
+ ( a == b) as sys:: GDExtensionBool
321
+ }
322
+
323
+ pub unsafe extern "C" fn rust_callable_less (
324
+ callable_userdata_a : * mut std:: ffi:: c_void ,
325
+ callable_userdata_b : * mut std:: ffi:: c_void ,
326
+ ) -> sys:: GDExtensionBool {
327
+ let a = CallableUserdata :: inner_from_raw ( callable_userdata_a) ;
328
+ let b = CallableUserdata :: inner_from_raw ( callable_userdata_b) ;
329
+
330
+ ( a < b) as sys:: GDExtensionBool
331
+ }
332
+
333
+ pub unsafe extern "C" fn rust_callable_to_string (
334
+ callable_userdata : * mut std:: ffi:: c_void ,
335
+ r_is_valid : * mut sys:: GDExtensionBool ,
336
+ r_out : sys:: GDExtensionStringPtr ,
337
+ ) {
338
+ let c = CallableUserdata :: inner_from_raw ( callable_userdata) ;
339
+ let s = StringName :: from ( c. to_string ( ) ) ;
340
+
341
+ s. move_string_ptr ( r_out) ;
342
+
343
+ * r_is_valid = true as sys:: GDExtensionBool ;
344
+ }
345
+ }
0 commit comments