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}