6
6
7
7
use godot_ffi as sys;
8
8
9
- use crate :: builtin:: { inner, GodotString , StringName , ToVariant , Variant , VariantArray } ;
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 } ;
@@ -51,6 +51,51 @@ impl Callable {
51
51
}
52
52
}
53
53
54
+ /// Create a callable from a Rust function or closure.
55
+ ///
56
+ /// `name` is used for the string representation of the closure, which helps debugging.
57
+ ///
58
+ /// Callables created through multiple `from_fn()` calls are never equal, even if they refer to the same function. If you want to use
59
+ /// equality, either clone an existing `Callable` instance, or define your own `PartialEq` impl with [`Callable::from_custom`].
60
+ ///
61
+ /// # Example
62
+ /// ```no_run
63
+ /// # use godot::prelude::*;
64
+ /// let callable = Callable::from_fn("sum", |args: &[&Variant]| {
65
+ /// let sum: i32 = args.iter().map(|arg| arg.to::<i32>()).sum();
66
+ /// Ok(sum.to_variant())
67
+ /// });
68
+ /// ```
69
+ #[ cfg( since_api = "4.2" ) ]
70
+ pub fn from_fn < F , S > ( name : S , rust_function : F ) -> Self
71
+ where
72
+ F : ' static + Send + Sync + FnMut ( & [ & Variant ] ) -> Result < Variant , ( ) > ,
73
+ S : Into < crate :: builtin:: GodotString > ,
74
+ {
75
+ let userdata = CallableUserdata {
76
+ inner : FnWrapper {
77
+ rust_function,
78
+ name : name. into ( ) ,
79
+ } ,
80
+ } ;
81
+
82
+ let info = sys:: GDExtensionCallableCustomInfo {
83
+ callable_userdata : Box :: into_raw ( Box :: new ( userdata) ) as * mut std:: ffi:: c_void ,
84
+ token : ptr:: null_mut ( ) ,
85
+ object : ptr:: null_mut ( ) ,
86
+ call_func : Some ( rust_callable_call_fn :: < F > ) ,
87
+ is_valid_func : None , // could be customized, but no real use case yet.
88
+ free_func : Some ( rust_callable_destroy :: < FnWrapper < F > > ) ,
89
+ hash_func : None ,
90
+ equal_func : None ,
91
+ // Op < is only used in niche scenarios and default is usually good enough, see https://github.com/godotengine/godot/issues/81901.
92
+ less_than_func : None ,
93
+ to_string_func : Some ( rust_callable_to_string_named :: < F > ) ,
94
+ } ;
95
+
96
+ Self :: from_custom_info ( info)
97
+ }
98
+
54
99
/// Create a highly configurable callable from Rust.
55
100
///
56
101
/// See [`RustCallable`] for requirements on the type.
@@ -59,22 +104,28 @@ impl Callable {
59
104
// Could theoretically use `dyn` but would need:
60
105
// - double boxing
61
106
// - a type-erased workaround for PartialEq supertrait (which has a `Self` type parameter and thus is not object-safe)
62
- let wrapper = CallableUserdata { callable } ;
107
+ let userdata = CallableUserdata { inner : callable } ;
63
108
64
- let mut info = sys:: GDExtensionCallableCustomInfo {
65
- callable_userdata : Box :: into_raw ( Box :: new ( wrapper ) ) as * mut std:: ffi:: c_void ,
109
+ let info = sys:: GDExtensionCallableCustomInfo {
110
+ callable_userdata : Box :: into_raw ( Box :: new ( userdata ) ) as * mut std:: ffi:: c_void ,
66
111
token : ptr:: null_mut ( ) ,
67
112
object : ptr:: null_mut ( ) ,
68
- call_func : Some ( rust_callable_call :: < C > ) ,
113
+ call_func : Some ( rust_callable_call_custom :: < C > ) ,
69
114
is_valid_func : None , // could be customized, but no real use case yet.
70
115
free_func : Some ( rust_callable_destroy :: < C > ) ,
71
116
hash_func : Some ( rust_callable_hash :: < C > ) ,
72
117
equal_func : Some ( rust_callable_equal :: < C > ) ,
73
118
// Op < is only used in niche scenarios and default is usually good enough, see https://github.com/godotengine/godot/issues/81901.
74
119
less_than_func : None ,
75
- to_string_func : Some ( rust_callable_to_string :: < C > ) ,
120
+ to_string_func : Some ( rust_callable_to_string_display :: < C > ) ,
76
121
} ;
77
122
123
+ Self :: from_custom_info ( info)
124
+ }
125
+
126
+ #[ cfg( since_api = "4.2" ) ]
127
+ fn from_custom_info ( mut info : sys:: GDExtensionCallableCustomInfo ) -> Callable {
128
+ // SAFETY: callable_custom_create() is a valid way of creating callables.
78
129
unsafe {
79
130
Callable :: from_sys_init ( |type_ptr| {
80
131
sys:: interface_fn!( callable_custom_create) ( type_ptr, ptr:: addr_of_mut!( info) )
@@ -208,8 +259,8 @@ impl_builtin_traits! {
208
259
209
260
// Equality for custom callables depend on the equality implementation of that custom callable.
210
261
// So we cannot implement `Eq` here and be confident equality will be total for all future custom callables.
262
+ // Godot does not define a less-than operator, so there is no `PartialOrd`.
211
263
PartialEq => callable_operator_equal;
212
- // PartialOrd => callable_operator_less;
213
264
Clone => callable_construct_copy;
214
265
Drop => callable_destroy;
215
266
}
@@ -258,21 +309,27 @@ pub use custom_callable::RustCallable;
258
309
#[ cfg( since_api = "4.2" ) ]
259
310
mod custom_callable {
260
311
use super :: * ;
312
+ use crate :: builtin:: GodotString ;
261
313
use std:: hash:: Hash ;
262
314
263
- pub struct CallableUserdata < C : RustCallable > {
264
- pub callable : C ,
315
+ pub struct CallableUserdata < T > {
316
+ pub inner : T ,
265
317
}
266
318
267
- impl < C : RustCallable > CallableUserdata < C > {
319
+ impl < T > CallableUserdata < T > {
268
320
/// # Safety
269
321
/// 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
322
+ unsafe fn inner_from_raw < ' a > ( void_ptr : * mut std:: ffi:: c_void ) -> & ' a mut T {
323
+ let ptr = void_ptr as * mut CallableUserdata < T > ;
324
+ & mut ( * ptr) . inner
273
325
}
274
326
}
275
327
328
+ pub ( crate ) struct FnWrapper < F > {
329
+ pub ( crate ) rust_function : F ,
330
+ pub ( crate ) name : GodotString ,
331
+ }
332
+
276
333
/// Represents a custom callable object defined in Rust.
277
334
///
278
335
/// This trait has a single method, `invoke`, which is called upon invocation.
@@ -288,7 +345,7 @@ mod custom_callable {
288
345
fn invoke ( & mut self , args : & [ & Variant ] ) -> Result < Variant , ( ) > ;
289
346
}
290
347
291
- pub unsafe extern "C" fn rust_callable_call < C : RustCallable > (
348
+ pub unsafe extern "C" fn rust_callable_call_custom < C : RustCallable > (
292
349
callable_userdata : * mut std:: ffi:: c_void ,
293
350
p_args : * const sys:: GDExtensionConstVariantPtr ,
294
351
p_argument_count : sys:: GDExtensionInt ,
@@ -304,52 +361,73 @@ mod custom_callable {
304
361
crate :: builtin:: meta:: varcall_return_checked ( result, r_return, r_error) ;
305
362
}
306
363
307
- pub unsafe extern "C" fn rust_callable_destroy < C : RustCallable > (
364
+ pub unsafe extern "C" fn rust_callable_call_fn < F > (
308
365
callable_userdata : * mut std:: ffi:: c_void ,
309
- ) {
310
- let rust_ptr = callable_userdata as * mut CallableUserdata < C > ;
366
+ p_args : * const sys:: GDExtensionConstVariantPtr ,
367
+ p_argument_count : sys:: GDExtensionInt ,
368
+ r_return : sys:: GDExtensionVariantPtr ,
369
+ r_error : * mut sys:: GDExtensionCallError ,
370
+ ) where
371
+ F : FnMut ( & [ & Variant ] ) -> Result < Variant , ( ) > ,
372
+ {
373
+ let arg_refs: & [ & Variant ] =
374
+ Variant :: unbounded_refs_from_sys ( p_args, p_argument_count as usize ) ;
375
+
376
+ let w: & mut FnWrapper < F > = CallableUserdata :: inner_from_raw ( callable_userdata) ;
377
+
378
+ let result = ( w. rust_function ) ( arg_refs) ;
379
+ crate :: builtin:: meta:: varcall_return_checked ( result, r_return, r_error) ;
380
+ }
381
+
382
+ pub unsafe extern "C" fn rust_callable_destroy < T > ( callable_userdata : * mut std:: ffi:: c_void ) {
383
+ let rust_ptr = callable_userdata as * mut CallableUserdata < T > ;
311
384
let _drop = Box :: from_raw ( rust_ptr) ;
312
385
}
313
386
314
- pub unsafe extern "C" fn rust_callable_hash < C : RustCallable > (
387
+ pub unsafe extern "C" fn rust_callable_hash < T : Hash > (
315
388
callable_userdata : * mut std:: ffi:: c_void ,
316
389
) -> u32 {
317
- let c: & C = CallableUserdata :: < C > :: inner_from_raw ( callable_userdata) ;
390
+ let c: & T = CallableUserdata :: < T > :: inner_from_raw ( callable_userdata) ;
318
391
319
392
// Just cut off top bits, not best-possible hash.
320
393
sys:: hash_value ( c) as u32
321
394
}
322
395
323
- pub unsafe extern "C" fn rust_callable_equal < C : RustCallable > (
396
+ pub unsafe extern "C" fn rust_callable_equal < T : PartialEq > (
324
397
callable_userdata_a : * mut std:: ffi:: c_void ,
325
398
callable_userdata_b : * mut std:: ffi:: c_void ,
326
399
) -> sys:: GDExtensionBool {
327
- let a: & C = CallableUserdata :: inner_from_raw ( callable_userdata_a) ;
328
- let b: & C = CallableUserdata :: inner_from_raw ( callable_userdata_b) ;
400
+ let a: & T = CallableUserdata :: inner_from_raw ( callable_userdata_a) ;
401
+ let b: & T = CallableUserdata :: inner_from_raw ( callable_userdata_b) ;
329
402
330
403
( a == b) as sys:: GDExtensionBool
331
404
}
332
405
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 > (
406
+ pub unsafe extern "C" fn rust_callable_to_string_display < T : fmt:: Display > (
344
407
callable_userdata : * mut std:: ffi:: c_void ,
345
408
r_is_valid : * mut sys:: GDExtensionBool ,
346
409
r_out : sys:: GDExtensionStringPtr ,
347
410
) {
348
- let c: & C = CallableUserdata :: inner_from_raw ( callable_userdata) ;
349
- let s = GodotString :: from ( c. to_string ( ) ) ;
411
+ let c: & T = CallableUserdata :: inner_from_raw ( callable_userdata) ;
412
+ let s = crate :: builtin :: GodotString :: from ( c. to_string ( ) ) ;
350
413
351
414
s. move_string_ptr ( r_out) ;
415
+ * r_is_valid = true as sys:: GDExtensionBool ;
416
+ }
352
417
418
+ pub unsafe extern "C" fn rust_callable_to_string_named < F > (
419
+ callable_userdata : * mut std:: ffi:: c_void ,
420
+ r_is_valid : * mut sys:: GDExtensionBool ,
421
+ r_out : sys:: GDExtensionStringPtr ,
422
+ ) {
423
+ let w: & mut FnWrapper < F > = CallableUserdata :: inner_from_raw ( callable_userdata) ;
424
+
425
+ w. name . clone ( ) . move_string_ptr ( r_out) ;
353
426
* r_is_valid = true as sys:: GDExtensionBool ;
354
427
}
428
+
429
+ pub fn unqualified_type_name < T > ( ) -> & ' static str {
430
+ let type_name = std:: any:: type_name :: < T > ( ) ;
431
+ type_name. split ( "::" ) . last ( ) . unwrap ( )
432
+ }
355
433
}
0 commit comments