godot_core/builtin/
callable.rs

1/*
2 * Copyright (c) godot-rust; Bromeon and contributors.
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
6 */
7
8use std::{fmt, ptr};
9
10use godot_ffi as sys;
11use sys::{ffi_methods, ExtVariantType, GodotFfi};
12
13use crate::builtin::{inner, GString, StringName, Variant, VariantArray};
14use crate::meta::{GodotType, ToGodot};
15use crate::obj::bounds::DynMemory;
16use crate::obj::{Bounds, Gd, GodotClass, InstanceId, Singleton};
17use crate::{classes, meta};
18
19#[cfg(before_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(before_api = "4.3")))]
20type CallableCustomInfo = sys::GDExtensionCallableCustomInfo;
21#[cfg(since_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(since_api = "4.3")))]
22type CallableCustomInfo = sys::GDExtensionCallableCustomInfo2;
23
24/// A `Callable` represents a function in Godot.
25///
26/// Callables can be created in many ways:
27/// - From an `Object` and a (non-static) method name. This is a _standard_ callable.
28/// - From a GDScript class name and a static function name. (This typically works because classes are instances of `GDScript`).
29/// - From a GDScript lambda function.
30/// - By modifying an existing `Callable` with [`bind()`][Self::bind] or [`unbind()`][Self::unbind].
31/// - By creating a custom callable from Rust.
32///
33/// # Godot docs
34///
35/// [`Callable` (stable)](https://docs.godotengine.org/en/stable/classes/class_callable.html)
36pub struct Callable {
37    opaque: sys::types::OpaqueCallable,
38}
39
40impl Callable {
41    fn from_opaque(opaque: sys::types::OpaqueCallable) -> Self {
42        Self { opaque }
43    }
44
45    /// Create a callable for the non-static method `object.method_name`.
46    ///
47    /// See also [`Gd::callable()`].
48    ///
49    /// _Godot equivalent: `Callable(Object object, StringName method)`_
50    pub fn from_object_method<T, S>(object: &Gd<T>, method_name: S) -> Self
51    where
52        T: GodotClass, // + Inherits<Object>,
53        S: meta::AsArg<StringName>,
54    {
55        meta::arg_into_ref!(method_name);
56
57        unsafe {
58            Self::new_with_uninit(|self_ptr| {
59                let ctor = sys::builtin_fn!(callable_from_object_method);
60                let raw = object.to_ffi();
61                let args = [raw.as_arg_ptr(), method_name.sys()];
62                ctor(self_ptr, args.as_ptr());
63            })
64        }
65    }
66
67    /// Create a callable for a method on any [`Variant`].
68    ///
69    /// Allows to dynamically call methods on builtin types (e.g. `String.md5_text`). Note that Godot method names are used, not Rust ones.
70    /// If the variant type is `Object`, the behavior will match that of `from_object_method()`.
71    ///
72    /// If the builtin type does not have the method, the returned callable will be invalid.
73    ///
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_class_static()`][Self::from_class_static] instead.
76    ///
77    /// _Godot equivalent: `Callable.create(Variant variant, StringName method)`_
78    #[cfg(since_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(since_api = "4.3")))]
79    pub fn from_variant_method<S>(variant: &Variant, method_name: S) -> Self
80    where
81        S: meta::AsArg<StringName>,
82    {
83        meta::arg_into_ref!(method_name);
84        inner::InnerCallable::create(variant, method_name)
85    }
86
87    /// Create a callable for the static method `class_name::function`
88    ///
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.
91    ///
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.
94    #[cfg(since_api = "4.4")] #[cfg_attr(published_docs, doc(cfg(since_api = "4.4")))]
95    pub fn from_class_static(
96        class_name: impl meta::AsArg<StringName>,
97        function_name: impl meta::AsArg<StringName>,
98    ) -> Self {
99        meta::arg_into_owned!(class_name);
100        meta::arg_into_owned!(function_name);
101
102        let callable_name = format!("{class_name}.{function_name}");
103
104        let function = move |args: &[&Variant]| {
105            let args = args.iter().cloned().cloned().collect::<Vec<_>>();
106
107            let result: Variant = classes::ClassDb::singleton().class_call_static(
108                &class_name,
109                &function_name,
110                args.as_slice(),
111            );
112            result
113        };
114
115        #[cfg(feature = "experimental-threads")] #[cfg_attr(published_docs, doc(cfg(feature = "experimental-threads")))]
116        let callable = Self::from_sync_fn(&callable_name, function);
117
118        #[cfg(not(feature = "experimental-threads"))] #[cfg_attr(published_docs, doc(cfg(not(feature = "experimental-threads"))))]
119        let callable = Self::from_fn(&callable_name, function);
120
121        callable
122    }
123
124    #[deprecated = "Renamed to `from_class_static`."]
125    #[cfg(since_api = "4.4")] #[cfg_attr(published_docs, doc(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)
131    }
132
133    fn default_callable_custom_info() -> CallableCustomInfo {
134        CallableCustomInfo {
135            callable_userdata: ptr::null_mut(),
136            token: ptr::null_mut(),
137            object_id: 0,
138            call_func: None,
139            is_valid_func: None, // overwritten later.
140            free_func: None,
141            hash_func: None,
142            equal_func: None,
143            // Op < is only used in niche scenarios and default is usually good enough, see https://github.com/godotengine/godot/issues/81901.
144            less_than_func: None,
145            to_string_func: None,
146            #[cfg(since_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(since_api = "4.3")))]
147            get_argument_count_func: None,
148        }
149    }
150
151    /// Create callable from **single-threaded** Rust function or closure.
152    ///
153    /// `name` is used for the string representation of the closure, which helps debugging.
154    ///
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,
156    /// use [`from_sync_fn`][Self::from_sync_fn] instead (requires crate feature `experimental-threads`; only enable if really needed).
157    ///
158    /// You can also couple the callable to the lifetime of an object, see [`from_linked_fn()`][Self::from_linked_fn].
159    pub fn from_fn<R, F, S>(name: S, rust_function: F) -> Self
160    where
161        R: ToGodot,
162        F: 'static + FnMut(&[&Variant]) -> R,
163        S: meta::AsArg<GString>,
164    {
165        meta::arg_into_owned!(name);
166
167        Self::from_fn_wrapper::<F, R>(FnWrapper {
168            rust_function,
169            name,
170            thread_id: Some(std::thread::current().id()),
171            linked_obj_id: None,
172        })
173    }
174
175    /// Creates a new callable linked to the given object from **single-threaded** Rust function or closure.
176    ///
177    /// `name` is used for the string representation of the closure, which helps with debugging.
178    ///
179    /// Such a callable will be automatically invalidated by Godot when a linked object is freed.
180    /// Prefer using [`Gd::linked_callable()`] instead.
181    ///
182    /// If you need a callable which can live indefinitely, use [`Callable::from_fn()`].
183    pub fn from_linked_fn<R, F, T, S>(name: S, linked_object: &Gd<T>, rust_function: F) -> Self
184    where
185        R: ToGodot,
186        T: GodotClass,
187        F: 'static + FnMut(&[&Variant]) -> R,
188        S: meta::AsArg<GString>,
189    {
190        meta::arg_into_owned!(name);
191
192        Self::from_fn_wrapper::<F, R>(FnWrapper {
193            rust_function,
194            name,
195            thread_id: Some(std::thread::current().id()),
196            linked_obj_id: Some(linked_object.instance_id()),
197        })
198    }
199
200    /// This constructor is being phased out in favor of [`from_fn()`][Self::from_fn], but kept through v0.4 for smoother migration.
201    ///
202    /// `from_fn()` accepts any `R: ToGodot` return type directly instead of requiring `Result<Variant, ()>`.
203    #[deprecated = "Migrate to `from_fn()`, which returns `R: ToGodot` directly."]
204    pub fn from_local_fn<F, S>(name: S, mut rust_function: F) -> Self
205    where
206        F: 'static + FnMut(&[&Variant]) -> Result<Variant, ()>,
207        S: meta::AsArg<GString>,
208    {
209        meta::arg_into_owned!(name);
210
211        Self::from_fn(&name, move |args| {
212            // Ignore errors.
213            rust_function(args).unwrap_or_else(|()| Variant::nil())
214        })
215    }
216
217    /// Create callable from **single-threaded** Rust function or closure that can only be called once.
218    ///
219    /// `name` is used for the string representation of the closure, which helps debugging.
220    ///
221    /// After the first invocation, subsequent calls will panic with a message indicating the callable has already been consumed. This is
222    /// useful for deferred operations that should only execute once. For repeated execution, use [`from_fn()][Self::from_fn].
223    pub(crate) fn from_once_fn<R, F, S>(name: S, rust_function: F) -> Self
224    where
225        R: ToGodot,
226        F: 'static + FnOnce(&[&Variant]) -> R,
227        S: meta::AsArg<GString>,
228    {
229        meta::arg_into_owned!(name);
230
231        let mut rust_fn_once = Some(rust_function);
232        Self::from_fn(&name, move |args| {
233            let rust_fn_once = rust_fn_once
234                .take()
235                .expect("callable created with from_once_fn() has already been consumed");
236
237            rust_fn_once(args)
238        })
239    }
240
241    #[cfg(feature = "trace")] // Test only.
242    #[doc(hidden)]
243    pub fn __once_fn<F, S>(name: S, rust_function: F) -> Self
244    where
245        F: 'static + FnOnce(&[&Variant]) -> Variant,
246        S: meta::AsArg<GString>,
247    {
248        Self::from_once_fn(name, rust_function)
249    }
250
251    pub(crate) fn with_scoped_fn<S, F, Fc, R>(name: S, rust_function: F, callable_usage: Fc) -> R
252    where
253        S: meta::AsArg<GString>,
254        F: FnMut(&[&Variant]) -> Variant,
255        Fc: FnOnce(&Callable) -> R,
256    {
257        meta::arg_into_owned!(name);
258
259        let callable = Self::from_fn_wrapper::<F, Variant>(FnWrapper {
260            rust_function,
261            name,
262            thread_id: Some(std::thread::current().id()),
263            linked_obj_id: None,
264        });
265
266        callable_usage(&callable)
267    }
268
269    /// Create callable from **thread-safe** Rust function or closure.
270    ///
271    /// `name` is used for the string representation of the closure, which helps debugging.
272    ///
273    /// This constructor requires `Send` + `Sync` bound and allows the callable to be invoked from any thread. If you guarantee that you invoke
274    /// it from the same thread as creating it, use [`from_fn`][Self::from_fn] instead.
275    ///
276    /// Callables created through multiple `from_fn` or `from_sync_fn()` calls are never equal, even if they refer to the same function.
277    /// If you want to use equality, either clone an existing `Callable` instance, or define your own `PartialEq` impl with
278    /// [`Callable::from_custom`].
279    ///
280    /// # Example
281    /// ```no_run
282    /// # use godot::prelude::*;
283    /// let callable = Callable::from_sync_fn("sum", |args: &[&Variant]| {
284    ///     let sum: i32 = args.iter().map(|arg| arg.to::<i32>()).sum();
285    ///     sum
286    /// });
287    /// ```
288    #[cfg(feature = "experimental-threads")] #[cfg_attr(published_docs, doc(cfg(feature = "experimental-threads")))]
289    pub fn from_sync_fn<R, F, S>(name: S, rust_function: F) -> Self
290    where
291        R: ToGodot,
292        F: 'static + Send + Sync + FnMut(&[&Variant]) -> R,
293        S: meta::AsArg<GString>,
294    {
295        meta::arg_into_owned!(name);
296
297        Self::from_fn_wrapper::<F, R>(FnWrapper {
298            rust_function,
299            name,
300            thread_id: None,
301            linked_obj_id: None,
302        })
303    }
304
305    /// Create a highly configurable callable from Rust.
306    ///
307    /// See [`RustCallable`] for requirements on the type.
308    pub fn from_custom<C: RustCallable>(callable: C) -> Self {
309        // Could theoretically use `dyn` but would need:
310        // - double boxing
311        // - a type-erased workaround for PartialEq supertrait (which has a `Self` type parameter and thus is not object-safe)
312        let userdata = CallableUserdata { inner: callable };
313
314        let info = CallableCustomInfo {
315            // We could technically associate an object_id with the custom callable. is_valid_func would then check that for validity.
316            callable_userdata: Box::into_raw(Box::new(userdata)) as *mut std::ffi::c_void,
317            call_func: Some(rust_callable_call_custom::<C>),
318            free_func: Some(rust_callable_destroy::<C>),
319            hash_func: Some(rust_callable_hash::<C>),
320            equal_func: Some(rust_callable_equal::<C>),
321            to_string_func: Some(rust_callable_to_string_display::<C>),
322            is_valid_func: Some(rust_callable_is_valid_custom::<C>),
323            ..Self::default_callable_custom_info()
324        };
325
326        Self::from_custom_info(info)
327    }
328
329    fn from_fn_wrapper<F, R>(inner: FnWrapper<F>) -> Self
330    where
331        F: FnMut(&[&Variant]) -> R,
332        R: ToGodot,
333    {
334        let object_id = inner.linked_object_id();
335
336        let userdata = CallableUserdata { inner };
337
338        let info = CallableCustomInfo {
339            object_id,
340            callable_userdata: Box::into_raw(Box::new(userdata)) as *mut std::ffi::c_void,
341            call_func: Some(rust_callable_call_fn::<F, R>),
342            free_func: Some(rust_callable_destroy::<FnWrapper<F>>),
343            to_string_func: Some(rust_callable_to_string_named::<F>),
344            is_valid_func: Some(rust_callable_is_valid),
345            ..Self::default_callable_custom_info()
346        };
347
348        Self::from_custom_info(info)
349    }
350
351    fn from_custom_info(mut info: CallableCustomInfo) -> Callable {
352        // SAFETY: callable_custom_create() is a valid way of creating callables.
353        unsafe {
354            Callable::new_with_uninit(|type_ptr| {
355                #[cfg(before_api = "4.3")]
356                {
357                    sys::interface_fn!(callable_custom_create)(type_ptr, ptr::addr_of_mut!(info))
358                }
359                #[cfg(since_api = "4.3")]
360                {
361                    sys::interface_fn!(callable_custom_create2)(type_ptr, ptr::addr_of_mut!(info))
362                }
363            })
364        }
365    }
366
367    /// Creates an invalid/empty object that cannot be called.
368    ///
369    /// _Godot equivalent: `Callable()`_
370    pub fn invalid() -> Self {
371        unsafe {
372            Self::new_with_uninit(|self_ptr| {
373                let ctor = sys::builtin_fn!(callable_construct_default);
374                ctor(self_ptr, ptr::null_mut())
375            })
376        }
377    }
378
379    /// Calls the method represented by this callable.
380    ///
381    /// Arguments passed should match the method's signature.
382    ///
383    /// - If called with more arguments than expected by the method, the extra arguments will be ignored and
384    ///   the call continues as normal.
385    /// - If called with fewer arguments than expected it will crash Godot, without triggering UB.
386    /// - If called with arguments of the wrong type then an error will be printed and the call will return
387    ///   `NIL`.
388    /// - If called on an invalid Callable then no error is printed, and `NIL` is returned.
389    ///
390    /// _Godot equivalent: `callv`_
391    pub fn callv(&self, arguments: &VariantArray) -> Variant {
392        self.as_inner().callv(arguments)
393    }
394
395    /// Returns a copy of this Callable with one or more arguments bound, reading them from an array.
396    ///
397    /// _Godot equivalent: `bindv`_
398    pub fn bindv(&self, arguments: &VariantArray) -> Self {
399        self.as_inner().bindv(arguments)
400    }
401
402    /// Returns the name of the method represented by this callable. If the callable is a lambda function,
403    /// returns the surrounding function's name.
404    ///
405    /// ## Known Bugs
406    ///
407    /// Getting the name of a lambda errors instead of returning its name, see [godot#73052].
408    ///
409    /// _Godot equivalent: `get_method`_
410    ///
411    /// [godot#73052]: https://github.com/godotengine/godot/issues/73052
412    #[doc(alias = "get_method")]
413    pub fn method_name(&self) -> Option<StringName> {
414        let method_name = self.as_inner().get_method();
415        if method_name.is_empty() {
416            None
417        } else {
418            Some(method_name)
419        }
420    }
421
422    /// Returns the object on which this callable is called.
423    ///
424    /// Returns `None` when this callable doesn't have any target object to call a method on (regardless of whether the method exists for that
425    /// target or not). Also returns `None` if the object is dead. You can differentiate these two cases using [`object_id()`][Self::object_id].
426    ///
427    /// _Godot equivalent: `get_object`_
428    pub fn object(&self) -> Option<Gd<classes::Object>> {
429        // Increment refcount because we're getting a reference, and `InnerCallable::get_object` doesn't
430        // increment the refcount.
431        self.as_inner().get_object().map(|mut object| {
432            <classes::Object as Bounds>::DynMemory::maybe_inc_ref(&mut object.raw);
433            object
434        })
435    }
436
437    /// Returns the ID of this callable's object, see also [`Gd::instance_id`].
438    ///
439    /// Returns `None` when this callable doesn't have any target to call a method on.
440    ///
441    /// If the pointed-to object is dead, the ID will still be returned. Use [`object()`][Self::object] to check for liveness.
442    ///
443    /// _Godot equivalent: `get_object_id`_
444    pub fn object_id(&self) -> Option<InstanceId> {
445        let id = self.as_inner().get_object_id();
446        InstanceId::try_from_i64(id)
447    }
448
449    crate::declare_hash_u32_method! {
450        /// Returns the 32-bit hash value of this callable's object.
451        ///
452        /// _Godot equivalent: `hash`_
453    }
454
455    #[deprecated = "renamed to hash_u32"]
456    pub fn hash(&self) -> u32 {
457        self.as_inner().hash().try_into().unwrap()
458    }
459
460    /// Returns true if this callable is a custom callable.
461    ///
462    /// Custom callables are mainly created from bind or unbind. In GDScript, lambda functions are also
463    /// custom callables.
464    ///
465    /// If a callable is not a custom callable, then it is considered a standard callable, this function is
466    /// the opposite of [`Callable.is_standard`].
467    ///
468    /// _Godot equivalent: `is_custom`_
469    ///
470    /// [`Callable.is_standard`]: https://docs.godotengine.org/en/stable/classes/class_callable.html#class-callable-method-is-standard
471    #[doc(alias = "is_standard")]
472    pub fn is_custom(&self) -> bool {
473        self.as_inner().is_custom()
474    }
475
476    /// Returns true if this callable has no target to call the method on.
477    ///
478    /// This is not the negated form of [`is_valid`][Self::is_valid], as `is_valid` will return `false` if the callable has a
479    /// target but the method does not exist.
480    ///
481    /// _Godot equivalent: `is_null`_
482    pub fn is_null(&self) -> bool {
483        self.as_inner().is_null()
484    }
485
486    /// Returns true if the callable's object exists and has a valid method name assigned, or is a custom
487    /// callable.
488    ///
489    /// _Godot equivalent: `is_valid`_
490    pub fn is_valid(&self) -> bool {
491        self.as_inner().is_valid()
492    }
493
494    /// Returns a copy of the callable, ignoring `args` user arguments.
495    ///
496    /// Despite its name, this does **not** directly undo previous `bind()` calls. See
497    /// [Godot docs](https://docs.godotengine.org/en/latest/classes/class_callable.html#class-callable-method-unbind) for up-to-date semantics.
498    pub fn unbind(&self, args: usize) -> Callable {
499        self.as_inner().unbind(args as i64)
500    }
501
502    #[cfg(since_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(since_api = "4.3")))]
503    pub fn get_argument_count(&self) -> usize {
504        self.as_inner().get_argument_count() as usize
505    }
506
507    /// Get number of bound arguments.
508    ///
509    /// Note: for Godot < 4.4, this function returns incorrect results when applied on a callable that used `unbind()`.
510    /// See [#98713](https://github.com/godotengine/godot/pull/98713) for details.
511    pub fn get_bound_arguments_count(&self) -> usize {
512        // This does NOT fix the bug before Godot 4.4, just cap it at zero. unbind() will still erroneously decrease the bound arguments count.
513        let alleged_count = self.as_inner().get_bound_arguments_count();
514
515        alleged_count.max(0) as usize
516    }
517
518    #[doc(hidden)]
519    pub fn as_inner(&self) -> inner::InnerCallable<'_> {
520        inner::InnerCallable::from_outer(self)
521    }
522}
523
524impl_builtin_traits! {
525    for Callable {
526        // Default is absent by design, to encourage explicit valid initialization.
527
528        Clone => callable_construct_copy;
529        Drop => callable_destroy;
530
531        // Equality for custom callables depend on the equality implementation of that custom callable.
532        // So we cannot implement `Eq` here and be confident equality will be total for all future custom callables.
533        PartialEq => callable_operator_equal;
534        // Godot does not define a less-than operator, so there is no `PartialOrd`.
535        // Hash could be added, but without Eq it's not that useful; wait for actual use cases.
536    }
537}
538
539// SAFETY:
540// The `opaque` in `Callable` is just a pair of pointers, and requires no special initialization or cleanup
541// beyond what is done in `from_opaque` and `drop`. So using `*mut Opaque` is safe.
542unsafe impl GodotFfi for Callable {
543    const VARIANT_TYPE: ExtVariantType = ExtVariantType::Concrete(sys::VariantType::CALLABLE);
544
545    ffi_methods! { type sys::GDExtensionTypePtr = *mut Opaque;
546        fn new_from_sys;
547        fn new_with_uninit;
548        fn from_arg_ptr;
549        fn sys;
550        fn sys_mut;
551        fn move_return_ptr;
552    }
553
554    unsafe fn new_with_init(init_fn: impl FnOnce(sys::GDExtensionTypePtr)) -> Self {
555        let mut result = Self::invalid();
556        init_fn(result.sys_mut());
557        result
558    }
559}
560
561meta::impl_godot_as_self!(Callable: ByRef);
562
563impl fmt::Debug for Callable {
564    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
565        let method = self.method_name();
566        let object = self.object();
567
568        f.debug_struct("Callable")
569            .field("method", &method)
570            .field("object", &object)
571            .finish()
572    }
573}
574
575impl fmt::Display for Callable {
576    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
577        write!(f, "{}", self.to_variant())
578    }
579}
580
581// ----------------------------------------------------------------------------------------------------------------------------------------------
582// Callbacks for custom implementations
583
584pub use custom_callable::RustCallable;
585use custom_callable::*;
586
587mod custom_callable {
588    use std::hash::Hash;
589    use std::thread::ThreadId;
590
591    use godot_ffi::GDObjectInstanceID;
592
593    use super::*;
594    use crate::builtin::GString;
595
596    pub struct CallableUserdata<T> {
597        pub inner: T,
598    }
599
600    impl<T> CallableUserdata<T> {
601        /// # Safety
602        /// Returns an unbounded reference. `void_ptr` must be a valid pointer to a `CallableUserdata`.
603        unsafe fn inner_from_raw<'a>(void_ptr: *mut std::ffi::c_void) -> &'a mut T {
604            let ptr = void_ptr as *mut CallableUserdata<T>;
605            &mut (*ptr).inner
606        }
607    }
608
609    pub(crate) struct FnWrapper<F> {
610        pub(super) rust_function: F,
611        pub(super) name: GString,
612
613        /// `None` if the callable is multi-threaded ([`Callable::from_sync_fn`]).
614        pub(super) thread_id: Option<ThreadId>,
615        /// `None` if callable is not linked with any object.
616        pub(super) linked_obj_id: Option<InstanceId>,
617    }
618
619    impl<F> FnWrapper<F> {
620        pub(crate) fn linked_object_id(&self) -> GDObjectInstanceID {
621            self.linked_obj_id.map(InstanceId::to_u64).unwrap_or(0)
622        }
623    }
624
625    /// Represents a custom callable object defined in Rust.
626    ///
627    /// This trait has a single method, `invoke`, which is called upon invocation.
628    ///
629    /// Since callables can be invoked from anywhere, they must be self-contained (`'static`) and thread-safe (`Send + Sync`).
630    /// They also should implement `Display` for the Godot string representation.
631    /// Furthermore, `Hash` is required for usage as a key in a `Dictionary` and for checking signal connections –
632    /// Godot considers a custom callable to be connected to a signal if a callable with the same hash is already connected to that signal.
633    /// Finally, `PartialEq` is necessary for equality checks.
634    pub trait RustCallable: 'static + PartialEq + Hash + fmt::Display + Send + Sync {
635        /// Invokes the callable with the given arguments as `Variant` references.
636        ///
637        /// Errors are supported via panics.
638        fn invoke(&mut self, args: &[&Variant]) -> Variant;
639
640        // TODO(v0.5): add object_id().
641
642        /// Returns whether the callable is considered valid.
643        ///
644        /// True by default.
645        ///
646        /// If this Callable stores an object, this method should return whether that object is alive.
647        fn is_valid(&self) -> bool {
648            true
649        }
650    }
651
652    pub unsafe extern "C" fn rust_callable_call_custom<C: RustCallable>(
653        callable_userdata: *mut std::ffi::c_void,
654        p_args: *const sys::GDExtensionConstVariantPtr,
655        p_argument_count: sys::GDExtensionInt,
656        r_return: sys::GDExtensionVariantPtr,
657        r_error: *mut sys::GDExtensionCallError,
658    ) {
659        let arg_refs: &[&Variant] = Variant::borrow_ref_slice(p_args, p_argument_count as usize);
660
661        let name = {
662            let c: &C = CallableUserdata::inner_from_raw(callable_userdata);
663            c.to_string()
664        };
665        let ctx = meta::CallContext::custom_callable(name.as_str());
666
667        crate::private::handle_varcall_panic(&ctx, &mut *r_error, move || {
668            // Get the RustCallable again inside closure so it doesn't have to be UnwindSafe.
669            let c: &mut C = CallableUserdata::inner_from_raw(callable_userdata);
670            let result = c.invoke(arg_refs);
671            meta::varcall_return_checked(Ok(result), r_return, r_error);
672            Ok(())
673        });
674    }
675
676    pub unsafe extern "C" fn rust_callable_call_fn<F, R>(
677        callable_userdata: *mut std::ffi::c_void,
678        p_args: *const sys::GDExtensionConstVariantPtr,
679        p_argument_count: sys::GDExtensionInt,
680        r_return: sys::GDExtensionVariantPtr,
681        r_error: *mut sys::GDExtensionCallError,
682    ) where
683        F: FnMut(&[&Variant]) -> R,
684        R: ToGodot,
685    {
686        let arg_refs: &[&Variant] = Variant::borrow_ref_slice(p_args, p_argument_count as usize);
687
688        let name = {
689            let w: &FnWrapper<F> = CallableUserdata::inner_from_raw(callable_userdata);
690            w.name.to_string()
691        };
692        let ctx = meta::CallContext::custom_callable(name.as_str());
693
694        crate::private::handle_varcall_panic(&ctx, &mut *r_error, move || {
695            // Get the FnWrapper again inside closure so the FnMut doesn't have to be UnwindSafe.
696            let w: &mut FnWrapper<F> = CallableUserdata::inner_from_raw(callable_userdata);
697
698            if w.thread_id
699                .is_some_and(|tid| tid != std::thread::current().id())
700            {
701                // NOTE: this panic is currently not propagated to the caller, but results in an error message and Nil return.
702                // See comments in itest callable_call() for details.
703                panic!(
704                    "Callable '{}' created with from_fn() must be called from the same thread it was created in.\n\
705                    If you need to call it from any thread, use from_sync_fn() instead (requires `experimental-threads` feature).",
706                    w.name
707                );
708            }
709
710            let result = (w.rust_function)(arg_refs).to_variant();
711            meta::varcall_return_checked(Ok(result), r_return, r_error);
712            Ok(())
713        });
714    }
715
716    pub unsafe extern "C" fn rust_callable_destroy<T>(callable_userdata: *mut std::ffi::c_void) {
717        let rust_ptr = callable_userdata as *mut CallableUserdata<T>;
718        let _drop = Box::from_raw(rust_ptr);
719    }
720
721    pub unsafe extern "C" fn rust_callable_hash<T: Hash>(
722        callable_userdata: *mut std::ffi::c_void,
723    ) -> u32 {
724        let c: &T = CallableUserdata::<T>::inner_from_raw(callable_userdata);
725
726        // Just cut off top bits, not best-possible hash.
727        sys::hash_value(c) as u32
728    }
729
730    pub unsafe extern "C" fn rust_callable_equal<T: PartialEq>(
731        callable_userdata_a: *mut std::ffi::c_void,
732        callable_userdata_b: *mut std::ffi::c_void,
733    ) -> sys::GDExtensionBool {
734        let a: &T = CallableUserdata::inner_from_raw(callable_userdata_a);
735        let b: &T = CallableUserdata::inner_from_raw(callable_userdata_b);
736
737        sys::conv::bool_to_sys(a == b)
738    }
739
740    pub unsafe extern "C" fn rust_callable_to_string_display<T: fmt::Display>(
741        callable_userdata: *mut std::ffi::c_void,
742        r_is_valid: *mut sys::GDExtensionBool,
743        r_out: sys::GDExtensionStringPtr,
744    ) {
745        let c: &T = CallableUserdata::inner_from_raw(callable_userdata);
746        let s = GString::from(&c.to_string());
747
748        s.move_into_string_ptr(r_out);
749        *r_is_valid = sys::conv::SYS_TRUE;
750    }
751
752    pub unsafe extern "C" fn rust_callable_to_string_named<F>(
753        callable_userdata: *mut std::ffi::c_void,
754        r_is_valid: *mut sys::GDExtensionBool,
755        r_out: sys::GDExtensionStringPtr,
756    ) {
757        let w: &mut FnWrapper<F> = CallableUserdata::inner_from_raw(callable_userdata);
758
759        w.name.clone().move_into_string_ptr(r_out);
760        *r_is_valid = sys::conv::SYS_TRUE;
761    }
762
763    // Implementing this is necessary because the default (nullptr) may consider custom callables as invalid in some cases.
764    pub unsafe extern "C" fn rust_callable_is_valid_custom<C: RustCallable>(
765        callable_userdata: *mut std::ffi::c_void,
766    ) -> sys::GDExtensionBool {
767        let w: &mut C = CallableUserdata::inner_from_raw(callable_userdata);
768        let valid = w.is_valid();
769
770        sys::conv::bool_to_sys(valid)
771    }
772
773    // Implementing this is necessary because the default (nullptr) may consider custom callables as invalid in some cases.
774    pub unsafe extern "C" fn rust_callable_is_valid(
775        _callable_userdata: *mut std::ffi::c_void,
776    ) -> sys::GDExtensionBool {
777        // If we had an object (CallableCustomInfo::object_id field), we could check whether that object is alive.
778        // But since we just take a Rust function/closure, not knowing what happens inside, we assume always valid.
779        sys::conv::SYS_TRUE
780    }
781}