6
6
7
7
use godot_ffi as sys;
8
8
9
- use crate :: builtin:: { inner, StringName , ToVariant , Variant , VariantArray } ;
9
+ use crate :: builtin:: { inner, GodotString , 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 } ;
@@ -51,30 +51,28 @@ impl Callable {
51
51
}
52
52
}
53
53
54
- /// Create a callable representing a Rust function.
55
- // #[cfg(since_api = "4.2")]
54
+ /// Create a highly configurable callable from Rust.
55
+ ///
56
+ /// See [`RustCallable`] for requirements on the type.
57
+ #[ cfg( since_api = "4.2" ) ]
56
58
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
- }
59
+ // Could theoretically use `dyn` but would need:
60
+ // - double boxing
61
+ // - a type-erased workaround for PartialEq supertrait (which has a `Self` type parameter and thus is not object-safe)
62
+ let wrapper = CallableUserdata { callable } ;
63
63
64
- // #[cfg(since_api = "4.2")]
65
- fn from_custom_inner ( callable : Box < CallableUserdata > ) -> Self {
66
64
let mut info = sys:: GDExtensionCallableCustomInfo {
67
- callable_userdata : Box :: into_raw ( callable ) as * mut std:: ffi:: c_void ,
65
+ callable_userdata : Box :: into_raw ( Box :: new ( wrapper ) ) as * mut std:: ffi:: c_void ,
68
66
token : ptr:: null_mut ( ) ,
69
67
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.
68
+ call_func : Some ( rust_callable_call :: < C > ) ,
69
+ is_valid_func : None , // could be customized, but no real use case yet.
70
+ free_func : Some ( rust_callable_destroy :: < C > ) ,
71
+ hash_func : Some ( rust_callable_hash :: < C > ) ,
72
+ equal_func : Some ( rust_callable_equal :: < C > ) ,
73
+ // Op < is only used in niche scenarios and default is usually good enough, see https://github.com/godotengine/godot/issues/81901.
76
74
less_than_func : None ,
77
- to_string_func : Some ( rust_callable_to_string) ,
75
+ to_string_func : Some ( rust_callable_to_string :: < C > ) ,
78
76
} ;
79
77
80
78
unsafe {
@@ -251,38 +249,46 @@ impl fmt::Display for Callable {
251
249
// ----------------------------------------------------------------------------------------------------------------------------------------------
252
250
// Callbacks for custom implementations
253
251
254
- // #[cfg(since_api = "4.2")]
252
+ #[ cfg( since_api = "4.2" ) ]
255
253
use custom_callable:: * ;
256
254
257
- // #[cfg(since_api = "4.2")]
255
+ #[ cfg( since_api = "4.2" ) ]
258
256
pub use custom_callable:: RustCallable ;
259
257
260
- // #[cfg(since_api = "4.2")]
258
+ #[ cfg( since_api = "4.2" ) ]
261
259
mod custom_callable {
262
260
use super :: * ;
263
- use crate :: builtin:: GodotString ;
264
261
use std:: hash:: Hash ;
265
262
266
- pub struct CallableUserdata {
267
- pub callable : Box < dyn RustCallable > ,
263
+ pub struct CallableUserdata < C : RustCallable > {
264
+ pub callable : C ,
268
265
}
269
266
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
267
+ impl < C : RustCallable > CallableUserdata < C > {
268
+ /// # Safety
269
+ /// Returns an unbounded reference. `void_ptr` must be a valid pointer to a `CallableUserdata`.
270
+ unsafe fn inner_from_raw < ' a > ( void_ptr : * mut std:: ffi:: c_void ) -> & ' a mut C {
271
+ let ptr = void_ptr as * mut CallableUserdata < C > ;
272
+ & mut ( * ptr) . callable
274
273
}
275
274
}
276
275
277
- pub trait RustCallable :
278
- ' static + Sized + PartialEq + Hash + fmt:: Display + Send + Sync
279
- where
280
- Self : Sized ,
281
- {
276
+ /// Represents a custom callable object defined in Rust.
277
+ ///
278
+ /// This trait has a single method, `invoke`, which is called upon invocation.
279
+ ///
280
+ /// Since callables can be invoked from anywhere, they must be self-contained (`'static`) and thread-safe (`Send + Sync`).
281
+ /// They also should implement `Display` for the Godot string representation.
282
+ /// Furthermore, `PartialEq` and `Hash` are required for equality checks and usage as a key in a `Dictionary`.
283
+ pub trait RustCallable : ' static + PartialEq + Hash + fmt:: Display + Send + Sync {
284
+ /// Invokes the callable with the given arguments as `Variant` references.
285
+ ///
286
+ /// Return `Ok(...)` if the call succeeded, and `Err(())` otherwise.
287
+ /// Error handling is mostly needed in case argument number or types mismatch.
282
288
fn invoke ( & mut self , args : & [ & Variant ] ) -> Result < Variant , ( ) > ;
283
289
}
284
290
285
- pub unsafe extern "C" fn rust_callable_call (
291
+ pub unsafe extern "C" fn rust_callable_call < C : RustCallable > (
286
292
callable_userdata : * mut std:: ffi:: c_void ,
287
293
p_args : * const sys:: GDExtensionConstVariantPtr ,
288
294
p_argument_count : sys:: GDExtensionInt ,
@@ -292,51 +298,55 @@ mod custom_callable {
292
298
let arg_refs: & [ & Variant ] =
293
299
Variant :: unbounded_refs_from_sys ( p_args, p_argument_count as usize ) ;
294
300
295
- let mut c = CallableUserdata :: inner_from_raw ( callable_userdata) ;
301
+ let c : & mut C = CallableUserdata :: inner_from_raw ( callable_userdata) ;
296
302
297
303
let result = c. invoke ( arg_refs) ;
298
304
crate :: builtin:: meta:: varcall_return_checked ( result, r_return, r_error) ;
299
305
}
300
306
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 ;
307
+ pub unsafe extern "C" fn rust_callable_destroy < C : RustCallable > (
308
+ callable_userdata : * mut std:: ffi:: c_void ,
309
+ ) {
310
+ let rust_ptr = callable_userdata as * mut CallableUserdata < C > ;
303
311
let _drop = Box :: from_raw ( rust_ptr) ;
304
312
}
305
313
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) ;
314
+ pub unsafe extern "C" fn rust_callable_hash < C : RustCallable > (
315
+ callable_userdata : * mut std:: ffi:: c_void ,
316
+ ) -> u32 {
317
+ let c: & C = CallableUserdata :: < C > :: inner_from_raw ( callable_userdata) ;
308
318
309
319
// Just cut off top bits, not best-possible hash.
310
320
sys:: hash_value ( c) as u32
311
321
}
312
322
313
- pub unsafe extern "C" fn rust_callable_equal (
323
+ pub unsafe extern "C" fn rust_callable_equal < C : RustCallable > (
314
324
callable_userdata_a : * mut std:: ffi:: c_void ,
315
325
callable_userdata_b : * mut std:: ffi:: c_void ,
316
326
) -> sys:: GDExtensionBool {
317
- let a = CallableUserdata :: inner_from_raw ( callable_userdata_a) ;
318
- let b = CallableUserdata :: inner_from_raw ( callable_userdata_b) ;
327
+ let a: & C = CallableUserdata :: inner_from_raw ( callable_userdata_a) ;
328
+ let b: & C = CallableUserdata :: inner_from_raw ( callable_userdata_b) ;
319
329
320
330
( a == b) as sys:: GDExtensionBool
321
331
}
322
332
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 (
333
+ // pub unsafe extern "C" fn rust_callable_less<C: RustCallable> (
334
+ // callable_userdata_a: *mut std::ffi::c_void,
335
+ // callable_userdata_b: *mut std::ffi::c_void,
336
+ // ) -> sys::GDExtensionBool {
337
+ // let a: &C = CallableUserdata::inner_from_raw(callable_userdata_a);
338
+ // let b: &C = CallableUserdata::inner_from_raw(callable_userdata_b);
339
+ //
340
+ // (a < b) as sys::GDExtensionBool
341
+ // }
342
+
343
+ pub unsafe extern "C" fn rust_callable_to_string < C : RustCallable > (
334
344
callable_userdata : * mut std:: ffi:: c_void ,
335
345
r_is_valid : * mut sys:: GDExtensionBool ,
336
346
r_out : sys:: GDExtensionStringPtr ,
337
347
) {
338
- let c = CallableUserdata :: inner_from_raw ( callable_userdata) ;
339
- let s = StringName :: from ( c. to_string ( ) ) ;
348
+ let c: & C = CallableUserdata :: inner_from_raw ( callable_userdata) ;
349
+ let s = GodotString :: from ( c. to_string ( ) ) ;
340
350
341
351
s. move_string_ptr ( r_out) ;
342
352
0 commit comments