godot_core/obj/
script.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
8//! Functionality related to script instances (Rust code that can be attached as node scripts).
9//!
10//! The features in this module are complemented by the [`ScriptExtension` class][crate::classes::ScriptExtension] and
11//! the [`IScriptExtension` trait][crate::classes::IScriptExtension].
12//!
13//! See [`ScriptInstance`](trait.ScriptInstance.html) for usage.
14
15use std::ffi::c_void;
16use std::ops::{Deref, DerefMut};
17
18#[cfg(feature = "experimental-threads")] #[cfg_attr(published_docs, doc(cfg(feature = "experimental-threads")))]
19use godot_cell::blocking::{GdCell, MutGuard, RefGuard};
20#[cfg(not(feature = "experimental-threads"))] #[cfg_attr(published_docs, doc(cfg(not(feature = "experimental-threads"))))]
21use godot_cell::panicking::{GdCell, MutGuard, RefGuard};
22
23use crate::builtin::{GString, StringName, Variant, VariantType};
24use crate::classes::{Object, Script, ScriptLanguage};
25use crate::meta::error::CallErrorType;
26use crate::meta::{MethodInfo, PropertyInfo};
27use crate::obj::{Base, Gd, GodotClass};
28use crate::sys;
29
30// ----------------------------------------------------------------------------------------------------------------------------------------------
31// Public re-exports.
32
33mod reexport_pub {
34    pub use crate::classes::IScriptExtension;
35    pub use crate::obj::Inherits;
36}
37pub use reexport_pub::*;
38
39// Re-export guards.
40pub use crate::obj::guards::{ScriptBaseMut, ScriptBaseRef};
41
42/// Implement custom scripts that can be attached to objects in Godot.
43///
44/// To use script instances, implement this trait for your own type.
45///
46/// You can use the [`create_script_instance()`] function to create a low-level pointer to your script instance. This pointer should then be
47/// returned from [`IScriptExtension::instance_create_rawptr()`](crate::classes::IScriptExtension::instance_create_rawptr).
48///
49/// # Example
50///
51/// ```no_run
52/// # // Trick 17 to avoid listing all the methods. Needs also a method.
53/// # mod godot {
54/// #     pub use ::godot::*;
55/// #     pub mod extras { pub trait ScriptInstance {} pub trait IScriptExtension {} }
56/// # }
57/// # fn create_script_instance(_: MyInstance) -> *mut std::ffi::c_void { std::ptr::null_mut() }
58/// use godot::prelude::*;
59/// use godot::classes::{Script, ScriptExtension};
60/// use godot::extras::{IScriptExtension, ScriptInstance};
61///
62/// // 1) Define the script.
63/// // This needs #[class(tool)] since the script extension runs in the editor.
64/// #[derive(GodotClass)]
65/// #[class(init, base=ScriptExtension, tool)]
66/// struct MyScript {
67///    base: Base<ScriptExtension>,
68///    // ... other fields
69/// }
70///
71/// // 2) Define the script _instance_, and implement the trait for it.
72/// struct MyInstance;
73/// impl MyInstance {
74///     fn from_gd(script: Gd<Script>) -> Self {
75///         Self { /* ... */ }
76///     }
77/// }
78///
79/// impl ScriptInstance for MyInstance {
80///     // Implement all the methods...
81/// }
82///
83/// // 3) Implement the script's virtual interface to wire up 1) and 2).
84/// #[godot_api]
85/// impl IScriptExtension for MyScript {
86///     // Implement all the methods...
87/// }
88/// ```
89pub trait ScriptInstance: Sized {
90    type Base: GodotClass;
91
92    /// Name of the new class the script implements.
93    fn class_name(&self) -> GString;
94
95    /// Property setter for Godot's virtual dispatch system.
96    ///
97    /// The engine will call this function when it wants to change a property on the script.
98    fn set_property(this: SiMut<Self>, name: StringName, value: &Variant) -> bool;
99
100    /// Property getter for Godot's virtual dispatch system.
101    ///
102    /// The engine will call this function when it wants to read a property on the script.
103    fn get_property(&self, name: StringName) -> Option<Variant>;
104
105    /// A list of all the properties a script exposes to the engine.
106    fn get_property_list(&self) -> Vec<PropertyInfo>;
107
108    /// A list of all the methods a script exposes to the engine.
109    fn get_method_list(&self) -> Vec<MethodInfo>;
110
111    /// Method invoker for Godot's virtual dispatch system. The engine will call this function when it wants to call a method on the script.
112    ///
113    /// All method calls are taking a mutable reference of the script instance, as the engine does not differentiate between immutable and
114    /// mutable method calls like rust.
115    ///
116    /// It's important that the script does not cause a second call to this function while executing a method call. This would result in a panic.
117    fn call(
118        this: SiMut<Self>,
119        method: StringName,
120        args: &[&Variant],
121    ) -> Result<Variant, CallErrorType>;
122
123    /// Identifies the script instance as a placeholder, routing property writes to a fallback if applicable.
124    ///
125    /// If this function and [IScriptExtension::is_placeholder_fallback_enabled] return true, Godot will call [`Self::property_set_fallback`]
126    /// instead of [`Self::set_property`].
127    fn is_placeholder(&self) -> bool;
128
129    /// Validation function for the engine to verify if the script exposes a certain method.
130    fn has_method(&self, method: StringName) -> bool;
131
132    /// Lets the engine get a reference to the script this instance was created for.
133    ///
134    /// This function has to return a reference, because scripts are reference-counted in Godot, and it must be guaranteed that the object is
135    /// not freed before the engine increased the reference count. (Every time a ref-counted `Gd<T>` is dropped, the reference count is
136    /// decremented.)
137    fn get_script(&self) -> &Gd<Script>;
138
139    /// Lets the engine fetch the type of a particular property.
140    fn get_property_type(&self, name: StringName) -> VariantType;
141
142    /// String representation of the script instance.
143    fn to_string(&self) -> GString;
144
145    /// A dump of all property names and values that are exposed to the engine.
146    fn get_property_state(&self) -> Vec<(StringName, Variant)>;
147
148    /// Lets the engine get a reference to the [`ScriptLanguage`] this instance belongs to.
149    fn get_language(&self) -> Gd<ScriptLanguage>;
150
151    /// Callback from the engine when the reference count of the base object has been decreased. When this method returns `true` the engine will
152    /// not free the object the script is attached to.
153    fn on_refcount_decremented(&self) -> bool;
154
155    /// Callback from the engine when the reference count of the base object has been increased.
156    fn on_refcount_incremented(&self);
157
158    /// The engine may call this function if it failed to get a property value via [`ScriptInstance::get_property`] or the native type's getter.
159    fn property_get_fallback(&self, name: StringName) -> Option<Variant>;
160
161    /// The engine may call this function if [`IScriptExtension::is_placeholder_fallback_enabled`] is enabled.
162    fn property_set_fallback(this: SiMut<Self>, name: StringName, value: &Variant) -> bool;
163
164    /// This function will be called to handle calls to [`Object::get_method_argument_count`](crate::classes::Object::get_method_argument_count)
165    /// and `Callable::get_argument_count`.
166    ///
167    /// If `None` is returned the public methods will return `0`.
168    #[cfg(since_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(since_api = "4.3")))]
169    fn get_method_argument_count(&self, _method: StringName) -> Option<u32>;
170}
171
172#[cfg(before_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(before_api = "4.3")))]
173type ScriptInstanceInfo = sys::GDExtensionScriptInstanceInfo2;
174#[cfg(since_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(since_api = "4.3")))]
175type ScriptInstanceInfo = sys::GDExtensionScriptInstanceInfo3;
176
177struct ScriptInstanceData<T: ScriptInstance> {
178    inner: GdCell<T>,
179    script_instance_ptr: *mut ScriptInstanceInfo,
180    #[cfg(before_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(before_api = "4.3")))]
181    property_lists: BoundedPtrList<sys::GDExtensionPropertyInfo>,
182    #[cfg(before_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(before_api = "4.3")))]
183    method_lists: BoundedPtrList<sys::GDExtensionMethodInfo>,
184    base: Base<T::Base>,
185}
186
187impl<T: ScriptInstance> ScriptInstanceData<T> {
188    ///  Convert a `ScriptInstanceData` sys pointer to a reference with unbounded lifetime.
189    ///
190    /// # Safety
191    ///
192    /// `ptr` must point to a live `ScriptInstanceData<T>` for the duration of `'a`.
193    unsafe fn borrow_script_sys<'a>(ptr: sys::GDExtensionScriptInstanceDataPtr) -> &'a Self {
194        &*(ptr.cast::<ScriptInstanceData<T>>())
195    }
196
197    fn borrow(&self) -> RefGuard<'_, T> {
198        self.inner
199            .borrow()
200            .unwrap_or_else(|err| Self::borrow_panic(err))
201    }
202
203    fn borrow_mut(&self) -> MutGuard<'_, T> {
204        self.inner
205            .borrow_mut()
206            .unwrap_or_else(|err| Self::borrow_panic(err))
207    }
208
209    fn cell_ref(&self) -> &GdCell<T> {
210        &self.inner
211    }
212
213    fn borrow_panic(err: Box<dyn std::error::Error>) -> ! {
214        panic!(
215            "\
216                ScriptInstance borrow failed, already bound; T = {}.\n  \
217                Make sure to use `SiMut::base_mut()` when possible.\n  \
218                Details: {err}.\
219            ",
220            std::any::type_name::<T>(),
221        )
222    }
223}
224
225impl<T: ScriptInstance> Drop for ScriptInstanceData<T> {
226    fn drop(&mut self) {
227        // SAFETY: The ownership of ScriptInstanceData is transferred to Godot after its creation. The engine then calls
228        // script_instance_info::free_func when it frees its own GDExtensionScriptInstance and subsequently wants to drop the ScriptInstanceData.
229        // After the data has been dropped, the instance info is no longer being used, but never freed. It is therefore safe to drop the
230        // instance info at the same time.
231        let instance = unsafe { Box::from_raw(self.script_instance_ptr) };
232
233        drop(instance);
234    }
235}
236
237/// Creates a new  from a type that implements [`ScriptInstance`].
238///
239/// See [`ScriptInstance`] for usage. Discarding the resulting value will result in a memory leak.
240///
241/// The exact GDExtension type of the pointer is `sys::GDExtensionScriptInstancePtr`, but you can treat it like an opaque pointer.
242///
243/// # Safety
244/// The caller must ensure that `for_object` is not freed before passing the returned pointer back to Godot.
245#[must_use]
246pub unsafe fn create_script_instance<T: ScriptInstance>(
247    rust_instance: T,
248    for_object: Gd<T::Base>,
249) -> *mut c_void {
250    // Field grouping matches C header.
251    let gd_instance = ScriptInstanceInfo {
252        set_func: Some(script_instance_info::set_property_func::<T>),
253        get_func: Some(script_instance_info::get_property_func::<T>),
254        get_property_list_func: Some(script_instance_info::get_property_list_func::<T>),
255        #[cfg(before_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(before_api = "4.3")))]
256        free_property_list_func: Some(script_instance_info::free_property_list_func::<T>),
257        #[cfg(since_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(since_api = "4.3")))]
258        free_property_list_func: Some(script_instance_info::free_property_list_func),
259
260        get_class_category_func: None, // not yet implemented.
261
262        property_can_revert_func: None, // unimplemented until needed.
263        property_get_revert_func: None, // unimplemented until needed.
264
265        get_owner_func: None,
266        get_property_state_func: Some(script_instance_info::get_property_state_func::<T>),
267
268        get_method_list_func: Some(script_instance_info::get_method_list_func::<T>),
269        #[cfg(before_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(before_api = "4.3")))]
270        free_method_list_func: Some(script_instance_info::free_method_list_func::<T>),
271        #[cfg(since_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(since_api = "4.3")))]
272        free_method_list_func: Some(script_instance_info::free_method_list_func),
273        get_property_type_func: Some(script_instance_info::get_property_type_func::<T>),
274        validate_property_func: None, // not yet implemented.
275
276        has_method_func: Some(script_instance_info::has_method_func::<T>),
277
278        call_func: Some(script_instance_info::call_func::<T>),
279        notification_func: None, // not yet implemented.
280
281        to_string_func: Some(script_instance_info::to_string_func::<T>),
282
283        refcount_incremented_func: Some(script_instance_info::refcount_incremented_func::<T>),
284        refcount_decremented_func: Some(script_instance_info::refcount_decremented_func::<T>),
285
286        get_script_func: Some(script_instance_info::get_script_func::<T>),
287
288        is_placeholder_func: Some(script_instance_info::is_placeholder_func::<T>),
289
290        get_fallback_func: Some(script_instance_info::get_fallback_func::<T>),
291        set_fallback_func: Some(script_instance_info::set_fallback_func::<T>),
292
293        get_language_func: Some(script_instance_info::get_language_func::<T>),
294
295        free_func: Some(script_instance_info::free_func::<T>),
296
297        #[cfg(since_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(since_api = "4.3")))]
298        get_method_argument_count_func: Some(
299            script_instance_info::get_method_argument_count_func::<T>,
300        ),
301    };
302
303    let instance_ptr = Box::into_raw(Box::new(gd_instance));
304
305    let data = ScriptInstanceData {
306        inner: GdCell::new(rust_instance),
307        script_instance_ptr: instance_ptr,
308        #[cfg(before_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(before_api = "4.3")))]
309        property_lists: BoundedPtrList::new(),
310        #[cfg(before_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(before_api = "4.3")))]
311        method_lists: BoundedPtrList::new(),
312        // SAFETY: The script instance is always freed before the base object is destroyed. The weak reference should therefore never be
313        // accessed after it has been freed.
314        base: unsafe { Base::from_script_gd(&for_object) },
315    };
316
317    let data_ptr = Box::into_raw(Box::new(data));
318
319    // SAFETY: `script_instance_create` expects a `GDExtensionScriptInstanceInfoPtr` and a generic `GDExtensionScriptInstanceDataPtr` of our
320    // choice. The validity of the instance info struct is ensured by code generation.
321    //
322    // It is expected that the engine upholds the safety invariants stated on each of the GDEXtensionScriptInstanceInfo functions.
323    unsafe {
324        #[cfg(before_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(before_api = "4.3")))]
325        let create_fn = sys::interface_fn!(script_instance_create2);
326
327        #[cfg(since_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(since_api = "4.3")))]
328        let create_fn = sys::interface_fn!(script_instance_create3);
329
330        create_fn(
331            instance_ptr,
332            data_ptr as sys::GDExtensionScriptInstanceDataPtr,
333        ) as *mut c_void
334    }
335}
336
337/// Checks if an instance of the script exists for a given object.
338///
339/// This function both checks if the passed script matches the one currently assigned to the passed object, as well as verifies that
340/// there is an instance for the script.
341///
342/// Use this function to implement [`IScriptExtension::instance_has`].
343pub fn script_instance_exists<O, S>(object: &Gd<O>, script: &Gd<S>) -> bool
344where
345    O: Inherits<Object>,
346    S: Inherits<Script> + IScriptExtension + super::Bounds<Declarer = super::bounds::DeclUser>,
347{
348    let Some(object_script) = object.upcast_ref().get_script() else {
349        return false;
350    };
351
352    if object_script.instance_id() != script.instance_id() {
353        return false;
354    }
355
356    let Some(language) = script.bind().get_language() else {
357        return false;
358    };
359
360    let get_instance_fn = sys::interface_fn!(object_get_script_instance);
361
362    // SAFETY: Object and language are alive and their sys pointers are valid.
363    let instance = unsafe { get_instance_fn(object.obj_sys(), language.obj_sys()) };
364
365    !instance.is_null()
366}
367
368/// Mutable/exclusive reference guard for a `T` where `T` implements [`ScriptInstance`].
369///
370/// This can be used to access the base object of a [`ScriptInstance`], which in turn can be used to make reentrant calls to engine APIs.
371/// For details see [`SiMut::base_mut()`].
372pub struct SiMut<'a, T: ScriptInstance> {
373    mut_ref: &'a mut T,
374    cell: &'a GdCell<T>,
375    base_ref: &'a Base<T::Base>,
376}
377
378impl<'a, T: ScriptInstance> SiMut<'a, T> {
379    fn new(
380        cell: &'a GdCell<T>,
381        cell_guard: &'a mut MutGuard<T>,
382        base_ref: &'a Base<T::Base>,
383    ) -> Self {
384        let mut_ref = cell_guard.deref_mut();
385
386        Self {
387            mut_ref,
388            cell,
389            base_ref,
390        }
391    }
392
393    /// Returns a shared reference suitable for calling engine methods on this object.
394    ///
395    /// Holding a shared guard prevents other code paths from obtaining a _mutable_ reference to `self`, as such it is recommended to drop the
396    /// guard as soon as you no longer need it.
397    ///
398    /// ```no_run
399    /// # use godot::prelude::*;
400    /// # use godot::classes::{ScriptLanguage, Script};
401    /// # use godot::obj::script::{ScriptInstance, SiMut};
402    /// # use godot::meta::{MethodInfo, PropertyInfo};
403    /// # use godot::meta::error::CallErrorType;
404    /// # use godot::sys;
405    ///
406    /// struct ExampleScriptInstance;
407    ///
408    /// impl ScriptInstance for ExampleScriptInstance {
409    ///     type Base = Node;
410    ///
411    ///     fn call(
412    ///         this: SiMut<Self>,
413    ///         method: StringName,
414    ///         args: &[&Variant],
415    ///     ) -> Result<Variant, CallErrorType>{
416    ///         let name = this.base().get_name();
417    ///         godot_print!("name is {name}");
418    ///         // However, we cannot call methods that require `&mut Base`, such as:
419    ///         // this.base().add_child(&node);
420    ///         Ok(Variant::nil())
421    ///     }
422    ///     # fn class_name(&self) -> GString { todo!() }
423    ///     # fn set_property(_: SiMut<'_, Self>, _: StringName, _: &Variant) -> bool { todo!() }
424    ///     # fn get_property(&self, _: StringName) -> Option<Variant> { todo!() }
425    ///     # fn get_property_list(&self) -> Vec<PropertyInfo> { todo!() }
426    ///     # fn get_method_list(&self) -> Vec<MethodInfo> { todo!() }
427    ///     # fn is_placeholder(&self) -> bool { todo!() }
428    ///     # fn has_method(&self, _: StringName) -> bool { todo!() }
429    ///     # fn get_script(&self) -> &Gd<Script> { todo!() }
430    ///     # fn get_property_type(&self, _: StringName) -> VariantType { todo!() }
431    ///     # fn to_string(&self) -> GString { todo!() }
432    ///     # fn get_property_state(&self) -> Vec<(StringName, Variant)> { todo!() }
433    ///     # fn get_language(&self) -> Gd<ScriptLanguage> { todo!() }
434    ///     # fn on_refcount_decremented(&self) -> bool { todo!() }
435    ///     # fn on_refcount_incremented(&self) { todo!() }
436    ///     # fn property_get_fallback(&self, _: StringName) -> Option<Variant> { todo!() }
437    ///     # fn property_set_fallback(_: SiMut<'_, Self>, _: StringName, _: &Variant) -> bool { todo!() }
438    ///     # fn get_method_argument_count(&self, _: StringName) -> Option<u32> { todo!() }
439    /// }
440    /// ```
441    pub fn base(&self) -> ScriptBaseRef<'_, T> {
442        let passive_gd = self.base_ref.to_script_passive();
443        ScriptBaseRef::new(passive_gd, self.mut_ref)
444    }
445
446    /// Returns a mutable reference suitable for calling engine methods on this object.
447    ///
448    /// This method will allow you to call back into the same object from Godot (re-entrancy).
449    /// You have to keep the `ScriptBaseRef` guard bound for the entire duration the engine might re-enter a function of your
450    /// `ScriptInstance`. The guard temporarily absorbs the `&mut self` reference, which allows for an additional mutable reference to be
451    /// acquired.
452    ///
453    /// Holding a mutable guard prevents other code paths from obtaining _any_ reference to `self`, as such it is recommended to drop the
454    /// guard as soon as you no longer need it.
455    ///
456    /// ```no_run
457    /// # use godot::prelude::*;
458    /// # use godot::classes::{ScriptLanguage, Script};
459    /// # use godot::obj::script::{ScriptInstance, SiMut};
460    /// # use godot::meta::{MethodInfo, PropertyInfo};
461    /// # use godot::meta::error::CallErrorType;
462    /// # use godot::sys;
463    ///
464    /// struct ExampleScriptInstance;
465    ///
466    /// impl ScriptInstance for ExampleScriptInstance {
467    ///     type Base = Object;
468    ///
469    ///     fn call(
470    ///         mut this: SiMut<Self>,
471    ///         method: StringName,
472    ///         args: &[&Variant],
473    ///     ) -> Result<Variant, CallErrorType> {
474    ///         // Check whether method is available on this script
475    ///         if method == StringName::from("script_method") {
476    ///             godot_print!("script_method called!");
477    ///             return Ok(true.to_variant());
478    ///         }
479    ///
480    ///         let node = Node::new_alloc();
481    ///
482    ///         // We can call back into `self` through Godot:
483    ///         this.base_mut().call("script_method", &[]);
484    ///
485    ///         Ok(Variant::nil())
486    ///     }
487    ///     # fn class_name(&self) -> GString { todo!() }
488    ///     # fn set_property(_: SiMut<'_, Self>, _: StringName, _: &Variant) -> bool { todo!() }
489    ///     # fn get_property(&self, _: StringName) -> Option<Variant> { todo!() }
490    ///     # fn get_property_list(&self) -> Vec<PropertyInfo> { todo!() }
491    ///     # fn get_method_list(&self) -> Vec<MethodInfo> { todo!() }
492    ///     # fn is_placeholder(&self) -> bool { todo!() }
493    ///     # fn has_method(&self, _: StringName) -> bool { todo!() }
494    ///     # fn get_script(&self) -> &Gd<Script> { todo!() }
495    ///     # fn get_property_type(&self, _: StringName) -> VariantType { todo!() }
496    ///     # fn to_string(&self) -> GString { todo!() }
497    ///     # fn get_property_state(&self) -> Vec<(StringName, Variant)> { todo!() }
498    ///     # fn get_language(&self) -> Gd<ScriptLanguage> { todo!() }
499    ///     # fn on_refcount_decremented(&self) -> bool { todo!() }
500    ///     # fn on_refcount_incremented(&self) { todo!() }
501    ///     # fn property_get_fallback(&self, _: StringName) -> Option<Variant> { todo!() }
502    ///     # fn property_set_fallback(_: SiMut<'_, Self>, _: StringName, _: &Variant) -> bool { todo!() }
503    ///     # fn get_method_argument_count(&self, _: StringName) -> Option<u32> { todo!() }
504    /// }
505    /// ```
506    pub fn base_mut(&mut self) -> ScriptBaseMut<'_, T> {
507        let guard = self.cell.make_inaccessible(self.mut_ref).unwrap();
508        let passive_gd = self.base_ref.to_script_passive();
509
510        ScriptBaseMut::new(passive_gd, guard)
511    }
512}
513
514impl<T: ScriptInstance> Deref for SiMut<'_, T> {
515    type Target = T;
516
517    fn deref(&self) -> &Self::Target {
518        self.mut_ref
519    }
520}
521
522impl<T: ScriptInstance> DerefMut for SiMut<'_, T> {
523    fn deref_mut(&mut self) -> &mut Self::Target {
524        self.mut_ref
525    }
526}
527
528// Encapsulate BoundedPtrList to help ensure safety.
529#[cfg(before_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(before_api = "4.3")))]
530mod bounded_ptr_list {
531    use std::collections::HashMap;
532    use std::sync::Mutex;
533
534    use godot_ffi as sys;
535
536    /// Helper struct to store the lengths of lists, so they can be properly freed.
537    ///
538    /// This uses the term `list` because it refers to property/method lists in gdextension.
539    pub struct BoundedPtrList<T> {
540        list_lengths: Mutex<HashMap<*mut T, u32>>,
541    }
542
543    impl<T> BoundedPtrList<T> {
544        pub fn new() -> Self {
545            Self {
546                list_lengths: Mutex::new(HashMap::new()),
547            }
548        }
549
550        /// Convert a list into a pointer + length pair. Should be used together with [`list_from_sys`](Self::list_from_sys).
551        ///
552        /// If `list_from_sys` is not called on this list then that will cause a memory leak.
553        pub fn list_into_sys(&self, list: Vec<T>) -> (*const T, u32) {
554            let len: u32 = list
555                .len()
556                .try_into()
557                .expect("list must have length that fits in u32");
558            let ptr = Box::leak(list.into_boxed_slice()).as_mut_ptr();
559
560            let old_value = self.list_lengths.lock().unwrap().insert(ptr, len);
561            assert_eq!(
562                old_value, None,
563                "attempted to insert the same list twice, this is a bug"
564            );
565
566            (ptr.cast_const(), len)
567        }
568
569        /// Get a list back from a previous call to [`list_into_sys`](Self::list_into_sys).
570        ///
571        /// # Safety
572        /// - `ptr` must have been returned from a call to `list_into_sys` on `self`.
573        /// - `ptr` must not have been used in a call to this function before.
574        /// - `ptr` must not have been mutated since the call to `list_into_sys`.
575        /// - `ptr` must not be accessed after calling this function.
576        #[deny(unsafe_op_in_unsafe_fn)]
577        pub unsafe fn list_from_sys(&self, ptr: *const T) -> Box<[T]> {
578            let ptr: *mut T = ptr.cast_mut();
579            let len = self
580                .list_lengths
581                .lock()
582                .unwrap()
583                .remove(&ptr)
584                .expect("attempted to free list from wrong collection, this is a bug");
585            let len: usize = sys::conv::u32_to_usize(len);
586
587            // SAFETY: `ptr` was created in `list_into_sys` from a slice of length `len`.
588            // And has not been mutated since.
589            let slice = unsafe { std::slice::from_raw_parts_mut(ptr, len) };
590
591            // SAFETY: This is the first call to this function, and the list will not be accessed again after this function call.
592            unsafe { Box::from_raw(slice) }
593        }
594    }
595}
596
597#[cfg(before_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(before_api = "4.3")))]
598use self::bounded_ptr_list::BoundedPtrList;
599
600#[deny(unsafe_op_in_unsafe_fn)]
601mod script_instance_info {
602    use std::any::type_name;
603    use std::ffi::c_void;
604
605    use sys::conv::{bool_to_sys, SYS_FALSE, SYS_TRUE};
606    #[cfg(since_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(since_api = "4.3")))]
607    use sys::conv::{ptr_list_from_sys, ptr_list_into_sys};
608
609    use super::{ScriptInstance, ScriptInstanceData, SiMut};
610    use crate::builtin::{StringName, Variant};
611    use crate::meta::{MethodInfo, PropertyInfo};
612    use crate::private::handle_panic;
613    use crate::sys;
614
615    /// # Safety
616    ///
617    /// - `p_instance` must point to a live immutable [`ScriptInstanceData<T>`] for the duration of this function call
618    /// - `p_name` must be a valid [`StringName`] pointer.
619    /// - `p_value` must be a valid [`Variant`] pointer.
620    pub(super) unsafe extern "C" fn set_property_func<T: ScriptInstance>(
621        p_instance: sys::GDExtensionScriptInstanceDataPtr,
622        p_name: sys::GDExtensionConstStringNamePtr,
623        p_value: sys::GDExtensionConstVariantPtr,
624    ) -> sys::GDExtensionBool {
625        let (name, value);
626        // SAFETY: `p_name` and `p_value` are valid pointers to a `StringName` and `Variant`.
627        unsafe {
628            name = StringName::new_from_string_sys(p_name);
629            value = Variant::borrow_var_sys(p_value);
630        }
631        let ctx = || format!("error when calling {}::set", type_name::<T>());
632
633        let result = handle_panic(ctx, || {
634            // SAFETY: `p_instance` points to a live immutable `ScriptInstanceData<T>` for the duration of this call.
635            let instance = unsafe { ScriptInstanceData::<T>::borrow_script_sys(p_instance) };
636            let mut guard = instance.borrow_mut();
637
638            let instance_guard = SiMut::new(instance.cell_ref(), &mut guard, &instance.base);
639
640            ScriptInstance::set_property(instance_guard, name, value)
641        })
642        // Unwrapping to a default of false, to indicate that the assignment is not handled by the script.
643        .unwrap_or_default();
644
645        bool_to_sys(result)
646    }
647
648    /// # Safety
649    ///
650    /// - `p_instance` must point to a live immutable [`ScriptInstanceData<T>`] for the duration of this function call
651    /// - `p_name` must be a valid [`StringName`] pointer.
652    /// - It must be safe to move a `Variant` into `r_ret`.
653    pub(super) unsafe extern "C" fn get_property_func<T: ScriptInstance>(
654        p_instance: sys::GDExtensionScriptInstanceDataPtr,
655        p_name: sys::GDExtensionConstStringNamePtr,
656        r_ret: sys::GDExtensionVariantPtr,
657    ) -> sys::GDExtensionBool {
658        // SAFETY: `p_name` is a valid [`StringName`] pointer.
659        let name = unsafe { StringName::new_from_string_sys(p_name) };
660        let ctx = || format!("error when calling {}::get", type_name::<T>());
661
662        let return_value = handle_panic(ctx, || {
663            // SAFETY: `p_instance` points to a live immutable `ScriptInstanceData<T>` for the duration of this call.
664            unsafe { ScriptInstanceData::<T>::borrow_script_sys(p_instance) }
665                .borrow()
666                .get_property(name)
667        });
668
669        match return_value {
670            Ok(Some(variant)) => {
671                // SAFETY: It is safe to move a `Variant` into `r_ret`.
672                unsafe { variant.move_into_var_ptr(r_ret) };
673                SYS_TRUE
674            }
675            _ => SYS_FALSE,
676        }
677    }
678
679    /// # Safety
680    ///
681    /// - `p_instance` must point to a live immutable [`ScriptInstanceData<T>`] for the duration of this function call
682    /// - It must be safe to assign a `u32` to `r_count`.
683    pub(super) unsafe extern "C" fn get_property_list_func<T: ScriptInstance>(
684        p_instance: sys::GDExtensionScriptInstanceDataPtr,
685        r_count: *mut u32,
686    ) -> *const sys::GDExtensionPropertyInfo {
687        let ctx = || format!("error when calling {}::get_property_list", type_name::<T>());
688
689        // Encapsulate this unsafe block to avoid repeating the safety comment.
690        // SAFETY: This closure is only used in this function, and we may dereference `p_instance` to an immutable reference for the duration of
691        // this call.
692        let borrow_instance =
693            move || unsafe { ScriptInstanceData::<T>::borrow_script_sys(p_instance) };
694
695        let property_list = handle_panic(ctx, || {
696            let property_list = borrow_instance().borrow().get_property_list();
697
698            property_list
699                .into_iter()
700                .map(|prop| prop.into_owned_property_sys())
701                .collect::<Vec<_>>()
702        })
703        .unwrap_or_default();
704
705        #[cfg(before_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(before_api = "4.3")))]
706        let (list_ptr, list_length) = borrow_instance()
707            .property_lists
708            .list_into_sys(property_list);
709
710        #[cfg(since_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(since_api = "4.3")))]
711        let (list_ptr, list_length) = ptr_list_into_sys(property_list);
712
713        // SAFETY: It is safe to assign a `u32` to `r_count`.
714        unsafe {
715            *r_count = list_length;
716        }
717
718        list_ptr
719    }
720
721    /// # Safety
722    ///
723    /// - `p_instance` must point to a live immutable [`ScriptInstanceData<T>`] for the duration of this function call
724    /// - `r_count` is expected to be a valid pointer to an u32.
725    pub(super) unsafe extern "C" fn get_method_list_func<T: ScriptInstance>(
726        p_instance: sys::GDExtensionScriptInstanceDataPtr,
727        r_count: *mut u32,
728    ) -> *const sys::GDExtensionMethodInfo {
729        let ctx = || format!("error when calling {}::get_method_list", type_name::<T>());
730
731        // Encapsulate this unsafe block to avoid repeating the safety comment.
732        // SAFETY: This closure is only used in this function, and we may dereference `p_instance` to an immutable reference for the duration of
733        // this call.
734        let borrow_instance =
735            move || unsafe { ScriptInstanceData::<T>::borrow_script_sys(p_instance) };
736
737        let method_list = handle_panic(ctx, || {
738            let method_list = borrow_instance().borrow().get_method_list();
739
740            method_list
741                .into_iter()
742                .map(|method| method.into_owned_method_sys())
743                .collect()
744        })
745        .unwrap_or_default();
746
747        #[cfg(before_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(before_api = "4.3")))]
748        let (return_pointer, list_length) =
749            borrow_instance().method_lists.list_into_sys(method_list);
750        #[cfg(since_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(since_api = "4.3")))]
751        let (return_pointer, list_length) = ptr_list_into_sys(method_list);
752
753        unsafe {
754            *r_count = list_length;
755        }
756
757        return_pointer
758    }
759
760    /// Provides the same functionality as the function below, but for Godot 4.2 and lower.
761    ///
762    /// # Safety
763    ///
764    /// See latest version below.
765    #[cfg(before_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(before_api = "4.3")))]
766    pub(super) unsafe extern "C" fn free_property_list_func<T: ScriptInstance>(
767        p_instance: sys::GDExtensionScriptInstanceDataPtr,
768        p_prop_info: *const sys::GDExtensionPropertyInfo,
769    ) {
770        // SAFETY: `p_instance` points to a live immutable `ScriptInstanceData<T>` for the duration of this call.
771        let instance = unsafe { ScriptInstanceData::<T>::borrow_script_sys(p_instance) };
772
773        // SAFETY: `p_prop_info` was returned from a call to `list_into_sys`, and has not been mutated since. This is also the first call
774        // to `list_from_sys` with this pointer.
775        let property_infos = unsafe { instance.property_lists.list_from_sys(p_prop_info) };
776
777        for info in property_infos.iter() {
778            // SAFETY: `info` was returned from a call to `into_owned_property_sys` and this is the first and only time this function is called
779            // on it.
780            unsafe { PropertyInfo::free_owned_property_sys(*info) };
781        }
782    }
783
784    /// # Safety
785    /// - `p_instance` must point to a live immutable [`ScriptInstanceData<T>`] for the duration of this function call
786    /// - `p_prop_info` must have been returned from a call to [`get_property_list_func`] called with the same `p_instance` pointer.
787    /// - `p_prop_info` must not have been mutated since the call to `get_property_list_func`.
788    #[cfg(since_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(since_api = "4.3")))]
789    pub(super) unsafe extern "C" fn free_property_list_func(
790        _p_instance: sys::GDExtensionScriptInstanceDataPtr,
791        p_prop_info: *const sys::GDExtensionPropertyInfo,
792        p_len: u32,
793    ) {
794        // SAFETY: `p_prop_info` was returned from a call to `list_into_sys`, and has not been mutated since. This is also the first call
795        // to `list_from_sys` with this pointer.
796        let property_infos = unsafe { ptr_list_from_sys(p_prop_info, p_len) };
797
798        for info in property_infos.iter() {
799            // SAFETY: `info` was returned from a call to `into_owned_property_sys` and this is the first and only time this function is called
800            // on it.
801            unsafe { PropertyInfo::free_owned_property_sys(*info) };
802        }
803    }
804
805    /// # Safety
806    ///
807    /// - `p_self` must point to a live immutable [`ScriptInstanceData<T>`] for the duration of this function call
808    /// - `p_method` must be a valid [`StringName`] pointer.
809    /// - `p_args` has to point to a list of Variant pointers of length `p_argument_count`.
810    /// - All the variant pointers in `p_args`, as well the `p_args` pointer itself must be dereferenceable to an immutable reference for the
811    ///   duration of this call.
812    /// - It must be safe to move a [`Variant`] into `r_return`.
813    /// - `r_error` must point to an initialized [`sys::GDExtensionCallError`] which can be written to.
814    pub(super) unsafe extern "C" fn call_func<T: ScriptInstance>(
815        p_self: sys::GDExtensionScriptInstanceDataPtr,
816        p_method: sys::GDExtensionConstStringNamePtr,
817        p_args: *const sys::GDExtensionConstVariantPtr,
818        p_argument_count: sys::GDExtensionInt,
819        r_return: sys::GDExtensionVariantPtr,
820        r_error: *mut sys::GDExtensionCallError,
821    ) {
822        // SAFETY: `p_method` is a valid [`StringName`] pointer.
823        let method = unsafe { StringName::new_from_string_sys(p_method) };
824
825        // SAFETY: `p_args` is a valid array of length `p_argument_count`.
826        let args = unsafe {
827            Variant::borrow_ref_slice(
828                p_args,
829                p_argument_count
830                    .try_into()
831                    .expect("argument count should be a valid `u32`"),
832            )
833        };
834        let ctx = || format!("error when calling {}::call", type_name::<T>());
835
836        let result = handle_panic(ctx, || {
837            // SAFETY: `p_self` points to a live immutable `ScriptInstanceData<T>` for the duration of this call.
838            let instance = unsafe { ScriptInstanceData::<T>::borrow_script_sys(p_self) };
839            let mut guard = instance.borrow_mut();
840
841            let instance_guard = SiMut::new(instance.cell_ref(), &mut guard, &instance.base);
842
843            ScriptInstance::call(instance_guard, method.clone(), args)
844        });
845
846        let error = match result {
847            Ok(Ok(variant)) => {
848                // SAFETY: It is safe to move a `Variant` into `r_return`.
849                unsafe { variant.move_into_var_ptr(r_return) };
850                sys::GDEXTENSION_CALL_OK
851            }
852
853            Ok(Err(err)) => err.to_sys(),
854
855            Err(_) => sys::GDEXTENSION_CALL_ERROR_INVALID_METHOD,
856        };
857
858        // SAFETY: `r_error` is an initialized pointer which we can write to.
859        unsafe { (*r_error).error = error };
860    }
861
862    /// Ownership of the returned object is not transferred to the caller. The caller is therefore responsible for incrementing the reference
863    /// count.
864    ///
865    /// # Safety
866    ///
867    /// - `p_instance` must point to a live immutable [`ScriptInstanceData<T>`] for the duration of this function call
868    pub(super) unsafe extern "C" fn get_script_func<T: ScriptInstance>(
869        p_instance: sys::GDExtensionScriptInstanceDataPtr,
870    ) -> sys::GDExtensionObjectPtr {
871        let ctx = || format!("error when calling {}::get_script", type_name::<T>());
872
873        let script = handle_panic(ctx, || {
874            // SAFETY: `p_instance` points to a live immutable `ScriptInstanceData<T>` for the duration of this call.
875            unsafe { ScriptInstanceData::<T>::borrow_script_sys(p_instance) }
876                .borrow()
877                .get_script()
878                .clone()
879        });
880
881        match script {
882            Ok(script) => script.obj_sys(),
883            Err(_) => std::ptr::null_mut(),
884        }
885    }
886
887    /// # Safety
888    ///
889    /// - `p_instance` must point to a live immutable [`ScriptInstanceData<T>`] for the duration of this function call
890    pub(super) unsafe extern "C" fn is_placeholder_func<T: ScriptInstance>(
891        p_instance: sys::GDExtensionScriptInstanceDataPtr,
892    ) -> sys::GDExtensionBool {
893        let ctx = || format!("error when calling {}::is_placeholder", type_name::<T>());
894
895        let is_placeholder = handle_panic(ctx, || {
896            // SAFETY: `p_instance` points to a live immutable `ScriptInstanceData<T>` for the duration of this call.
897            unsafe { ScriptInstanceData::<T>::borrow_script_sys(p_instance) }
898                .borrow()
899                .is_placeholder()
900        })
901        .unwrap_or_default();
902
903        bool_to_sys(is_placeholder)
904    }
905
906    /// # Safety
907    ///
908    /// - `p_instance` must point to a live immutable [`ScriptInstanceData<T>`] for the duration of this function call
909    /// - `p_method` has to point to a valid `StringName`.
910    pub(super) unsafe extern "C" fn has_method_func<T: ScriptInstance>(
911        p_instance: sys::GDExtensionScriptInstanceDataPtr,
912        p_method: sys::GDExtensionConstStringNamePtr,
913    ) -> sys::GDExtensionBool {
914        // SAFETY: `p_method` is a valid [`StringName`] pointer.
915        let method = unsafe { StringName::new_from_string_sys(p_method) };
916        let ctx = || format!("error when calling {}::has_method", type_name::<T>());
917
918        let has_method = handle_panic(ctx, || {
919            // SAFETY: `p_instance` points to a live immutable `ScriptInstanceData<T>` for the duration of this call.
920            unsafe { ScriptInstanceData::<T>::borrow_script_sys(p_instance) }
921                .borrow()
922                .has_method(method)
923        })
924        .unwrap_or_default();
925
926        bool_to_sys(has_method)
927    }
928
929    /// Provides the same functionality as the function below, but for Godot 4.2 and lower.
930    ///
931    /// # Safety
932    ///
933    /// See latest version below.
934    #[cfg(before_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(before_api = "4.3")))]
935    pub(super) unsafe extern "C" fn free_method_list_func<T: ScriptInstance>(
936        p_instance: sys::GDExtensionScriptInstanceDataPtr,
937        p_method_info: *const sys::GDExtensionMethodInfo,
938    ) {
939        // SAFETY: `p_instance` points to a live immutable `ScriptInstanceData<T>` for the duration of this call.
940        let instance = unsafe { ScriptInstanceData::<T>::borrow_script_sys(p_instance) };
941
942        // SAFETY: `p_method_info` was returned from a call to `list_into_sys`, and has not been mutated since. This is also the first call
943        // to `list_from_sys` with this pointer.
944        let method_infos = unsafe { instance.method_lists.list_from_sys(p_method_info) };
945
946        for info in method_infos.iter() {
947            // SAFETY: `info` was returned from a call to `into_owned_method_sys`, and this is the first and only time we call this method on
948            // it.
949            unsafe { MethodInfo::free_owned_method_sys(*info) };
950        }
951    }
952
953    /// # Safety
954    ///
955    /// - `p_instance` must point to a live immutable [`ScriptInstanceData<T>`] for the duration of this function call
956    /// - `p_method_info` must have been returned from a call to [`get_method_list_func`] called with the same `p_instance` pointer.
957    /// - `p_method_info` must not have been mutated since the call to `get_method_list_func`.
958    #[cfg(since_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(since_api = "4.3")))]
959    pub(super) unsafe extern "C" fn free_method_list_func(
960        _p_instance: sys::GDExtensionScriptInstanceDataPtr,
961        p_method_info: *const sys::GDExtensionMethodInfo,
962        p_len: u32,
963    ) {
964        // SAFETY: `p_method_info` was returned from a call to `list_into_sys`, and has not been mutated since. This is also the first call
965        // to `list_from_sys` with this pointer.
966        let method_infos = unsafe { ptr_list_from_sys(p_method_info, p_len) };
967
968        for info in method_infos.iter() {
969            // SAFETY: `info` was returned from a call to `into_owned_method_sys`, and this is the first and only time we call this method on
970            // it.
971            unsafe { MethodInfo::free_owned_method_sys(*info) };
972        }
973    }
974
975    /// # Safety
976    ///
977    /// - `p_instance` must point to a live immutable [`ScriptInstanceData<T>`] for the duration of this function call
978    /// - `p_name` must be a valid [`StringName`] pointer.
979    /// - `r_is_valid` must be assignable.
980    pub(super) unsafe extern "C" fn get_property_type_func<T: ScriptInstance>(
981        p_instance: sys::GDExtensionScriptInstanceDataPtr,
982        p_name: sys::GDExtensionConstStringNamePtr,
983        r_is_valid: *mut sys::GDExtensionBool,
984    ) -> sys::GDExtensionVariantType {
985        let ctx = || {
986            format!(
987                "error while calling {}::get_property_type",
988                type_name::<T>()
989            )
990        };
991        // SAFETY: `p_name` is a valid [`StringName`] pointer.
992        let name = unsafe { StringName::new_from_string_sys(p_name) };
993
994        let result = handle_panic(ctx, || {
995            // SAFETY: `p_instance` points to a live immutable `ScriptInstanceData<T>` for the duration of this call.
996            unsafe { ScriptInstanceData::<T>::borrow_script_sys(p_instance) }
997                .borrow()
998                .get_property_type(name.clone())
999        });
1000
1001        let (is_valid, result) = if let Ok(result) = result {
1002            (SYS_TRUE, result.sys())
1003        } else {
1004            (SYS_FALSE, sys::GDEXTENSION_VARIANT_TYPE_NIL)
1005        };
1006
1007        // SAFETY: `r_is_valid` is assignable.
1008        unsafe { *r_is_valid = is_valid };
1009        result
1010    }
1011
1012    /// # Safety
1013    ///
1014    /// - `p_instance` must point to a live immutable [`ScriptInstanceData<T>`] for the duration of this function call
1015    /// - `r_is_valid` must be assignable.
1016    /// - It must be safe to move a [`GString`](crate::builtin::GString) into `r_str`.
1017    pub(super) unsafe extern "C" fn to_string_func<T: ScriptInstance>(
1018        p_instance: sys::GDExtensionScriptInstanceDataPtr,
1019        r_is_valid: *mut sys::GDExtensionBool,
1020        r_str: sys::GDExtensionStringPtr,
1021    ) {
1022        let ctx = || format!("error when calling {}::to_string", type_name::<T>());
1023
1024        let string = handle_panic(ctx, || {
1025            // SAFETY: `p_instance` points to a live immutable `ScriptInstanceData<T>` for the duration of this call.
1026            unsafe { ScriptInstanceData::<T>::borrow_script_sys(p_instance) }
1027                .borrow()
1028                .to_string()
1029        })
1030        .ok();
1031
1032        let Some(string) = string else {
1033            return;
1034        };
1035
1036        // SAFETY: `r_is_valid` is assignable.
1037        unsafe { *r_is_valid = SYS_TRUE };
1038        // SAFETY: It is safe to move a `GString` into `r_str`.
1039        unsafe { string.move_into_string_ptr(r_str) };
1040    }
1041
1042    /// # Safety
1043    ///
1044    /// - `p_instance` must point to a live immutable [`ScriptInstanceData<T>`] for the duration of this function call
1045    ///
1046    /// If `property_state_add` is non-null, then:
1047    /// - It is safe to call `property_state_add` using the provided `userdata`.
1048    /// - `property_state_add` must take ownership of the `StringName` and `Variant` it is called with.
1049    pub(super) unsafe extern "C" fn get_property_state_func<T: ScriptInstance>(
1050        p_instance: sys::GDExtensionScriptInstanceDataPtr,
1051        property_state_add: sys::GDExtensionScriptInstancePropertyStateAdd,
1052        userdata: *mut c_void,
1053    ) {
1054        let ctx = || {
1055            format!(
1056                "error when calling {}::get_property_state",
1057                type_name::<T>()
1058            )
1059        };
1060
1061        let property_states = handle_panic(ctx, || {
1062            // SAFETY: `p_instance` points to a live immutable `ScriptInstanceData<T>` for the duration of this call.
1063            unsafe { ScriptInstanceData::<T>::borrow_script_sys(p_instance) }
1064                .borrow()
1065                .get_property_state()
1066        })
1067        .unwrap_or_default();
1068
1069        let Some(property_state_add) = property_state_add else {
1070            return;
1071        };
1072
1073        for (name, value) in property_states {
1074            // SAFETY: `property_state_add` is non-null, therefore we can call the function with the provided `userdata`.
1075            // Additionally `property_state_add` takes ownership of `name` and `value`.
1076            unsafe {
1077                property_state_add(
1078                    name.into_owned_string_sys(),
1079                    value.into_owned_var_sys(),
1080                    userdata,
1081                )
1082            }
1083        }
1084    }
1085
1086    /// Ownership of the returned object is not transferred to the caller. The caller must therefore ensure it's not freed when used.
1087    ///
1088    /// # Safety
1089    ///
1090    /// - `p_instance` must point to a live immutable [`ScriptInstanceData<T>`] for the duration of this function call
1091    pub(super) unsafe extern "C" fn get_language_func<T: ScriptInstance>(
1092        p_instance: sys::GDExtensionScriptInstanceDataPtr,
1093    ) -> sys::GDExtensionScriptLanguagePtr {
1094        let ctx = || format!("error when calling {}::get_language", type_name::<T>());
1095
1096        let language = handle_panic(ctx, || {
1097            // SAFETY: `p_instance` points to a live immutable `ScriptInstanceData<T>` for the duration of this call.
1098            unsafe { ScriptInstanceData::<T>::borrow_script_sys(p_instance) }
1099                .borrow()
1100                .get_language()
1101        });
1102
1103        if let Ok(language) = language {
1104            language.obj_sys().cast()
1105        } else {
1106            std::ptr::null_mut()
1107        }
1108    }
1109
1110    /// # Safety
1111    ///
1112    /// - `p_instance` must fulfill the safety preconditions of [`Box::from_raw`] for `Box<ScriptInstanceData<T>>`.
1113    pub(super) unsafe extern "C" fn free_func<T: ScriptInstance>(
1114        p_instance: sys::GDExtensionScriptInstanceDataPtr,
1115    ) {
1116        unsafe { drop(Box::from_raw(p_instance.cast::<ScriptInstanceData<T>>())) }
1117    }
1118
1119    /// # Safety
1120    ///
1121    /// - `p_instance` must point to a live immutable [`ScriptInstanceData<T>`] for the duration of this function call
1122    pub(super) unsafe extern "C" fn refcount_decremented_func<T: ScriptInstance>(
1123        p_instance: sys::GDExtensionScriptInstanceDataPtr,
1124    ) -> sys::GDExtensionBool {
1125        let ctx = || {
1126            format!(
1127                "error when calling {}::refcount_decremented",
1128                type_name::<T>()
1129            )
1130        };
1131
1132        let result = handle_panic(ctx, || {
1133            // SAFETY: `p_instance` points to a live immutable `ScriptInstanceData<T>` for the duration of this call.
1134            unsafe { ScriptInstanceData::<T>::borrow_script_sys(p_instance) }
1135                .borrow()
1136                .on_refcount_decremented()
1137        })
1138        .unwrap_or(true);
1139
1140        bool_to_sys(result)
1141    }
1142
1143    /// # Safety
1144    ///
1145    /// - `p_instance` must point to a live immutable [`ScriptInstanceData<T>`] for the duration of this function call
1146    pub(super) unsafe extern "C" fn refcount_incremented_func<T: ScriptInstance>(
1147        p_instance: sys::GDExtensionScriptInstanceDataPtr,
1148    ) {
1149        let ctx = || {
1150            format!(
1151                "error when calling {}::refcount_incremented",
1152                type_name::<T>()
1153            )
1154        };
1155
1156        handle_panic(ctx, || {
1157            // SAFETY: `p_instance` points to a live immutable `ScriptInstanceData<T>` for the duration of this call.
1158            unsafe { ScriptInstanceData::<T>::borrow_script_sys(p_instance) }
1159                .borrow()
1160                .on_refcount_incremented();
1161        })
1162        .unwrap_or_default();
1163    }
1164
1165    /// # Safety
1166    ///
1167    /// - `p_instance` must point to a live immutable [`ScriptInstanceData<T>`] for the duration of this function call
1168    /// - `p_name` must be a valid [`StringName`] pointer.
1169    /// - It must be safe to move a `Variant` into `r_ret`.
1170    pub(super) unsafe extern "C" fn get_fallback_func<T: ScriptInstance>(
1171        p_instance: sys::GDExtensionScriptInstanceDataPtr,
1172        p_name: sys::GDExtensionConstStringNamePtr,
1173        r_ret: sys::GDExtensionVariantPtr,
1174    ) -> sys::GDExtensionBool {
1175        // SAFETY: `p_name` is a valid `StringName` pointer.
1176        let name = unsafe { StringName::new_from_string_sys(p_name) };
1177
1178        let ctx = || {
1179            format!(
1180                "error when calling {}::property_get_fallback",
1181                type_name::<T>()
1182            )
1183        };
1184
1185        let return_value = handle_panic(ctx, || {
1186            // SAFETY: `p_instance` points to a live immutable `ScriptInstanceData<T>` for the duration of this call.
1187            unsafe { ScriptInstanceData::<T>::borrow_script_sys(p_instance) }
1188                .borrow()
1189                .property_get_fallback(name)
1190        });
1191
1192        match return_value {
1193            Ok(Some(variant)) => {
1194                // SAFETY: It is safe to move a `Variant` into `r_ret`.
1195                unsafe { variant.move_into_var_ptr(r_ret) };
1196                SYS_TRUE
1197            }
1198            _ => SYS_FALSE,
1199        }
1200    }
1201
1202    /// # Safety
1203    ///
1204    /// - `p_instance` must point to a live immutable [`ScriptInstanceData<T>`] for the duration of this function call
1205    /// - `p_name` must be a valid [`StringName`] pointer.
1206    /// - `p_value` must be a valid [`Variant`] pointer.
1207    pub(super) unsafe extern "C" fn set_fallback_func<T: ScriptInstance>(
1208        p_instance: sys::GDExtensionScriptInstanceDataPtr,
1209        p_name: sys::GDExtensionConstStringNamePtr,
1210        p_value: sys::GDExtensionConstVariantPtr,
1211    ) -> sys::GDExtensionBool {
1212        let (name, value);
1213        // SAFETY: `p_name` and `p_value` are valid `StringName` and `Variant` pointers respectively.
1214        unsafe {
1215            name = StringName::new_from_string_sys(p_name);
1216            value = Variant::borrow_var_sys(p_value);
1217        };
1218
1219        let ctx = || {
1220            format!(
1221                "error when calling {}::property_set_fallback",
1222                type_name::<T>()
1223            )
1224        };
1225
1226        let result = handle_panic(ctx, || {
1227            // SAFETY: `p_instance` points to a live immutable `ScriptInstanceData<T>` for the duration of this call.
1228            let instance = unsafe { ScriptInstanceData::<T>::borrow_script_sys(p_instance) };
1229            let mut guard = instance.borrow_mut();
1230
1231            let instance_guard = SiMut::new(instance.cell_ref(), &mut guard, &instance.base);
1232            ScriptInstance::property_set_fallback(instance_guard, name, value)
1233        })
1234        .unwrap_or_default();
1235
1236        bool_to_sys(result)
1237    }
1238
1239    /// # Safety
1240    ///
1241    /// - `p_instance` must point to a live immutable [`ScriptInstanceData<T>`] for the duration of this function call
1242    /// - `p_method` has to point to a valid [`StringName`].
1243    /// - `p_value` must be a valid [`sys::GDExtensionBool`] pointer.
1244    #[cfg(since_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(since_api = "4.3")))]
1245    pub(super) unsafe extern "C" fn get_method_argument_count_func<T: ScriptInstance>(
1246        p_instance: sys::GDExtensionScriptInstanceDataPtr,
1247        p_method: sys::GDExtensionConstStringNamePtr,
1248        r_is_valid: *mut sys::GDExtensionBool,
1249    ) -> sys::GDExtensionInt {
1250        // SAFETY: `p_method` is a valid [`StringName`] pointer.
1251        let method = unsafe { StringName::new_from_string_sys(p_method) };
1252        let ctx = || {
1253            format!(
1254                "error when calling {}::get_method_argument_count_func",
1255                type_name::<T>()
1256            )
1257        };
1258
1259        let method_argument_count = handle_panic(ctx, || {
1260            // SAFETY: `p_instance` points to a live immutable `ScriptInstanceData<T>` for the duration of this call.
1261            unsafe { ScriptInstanceData::<T>::borrow_script_sys(p_instance) }
1262                // Can panic if the GdCell is currently mutably bound.
1263                .borrow()
1264                // This is user code and could cause a panic.
1265                .get_method_argument_count(method)
1266        })
1267        // In case of a panic, handle_panic will print an error message. We will recover from the panic by falling back to the default value None.
1268        .unwrap_or_default();
1269
1270        let (result, is_valid) = match method_argument_count {
1271            Some(count) => (count, SYS_TRUE),
1272            None => (0, SYS_FALSE),
1273        };
1274
1275        // SAFETY: `r_is_valid` is assignable.
1276        unsafe { *r_is_valid = is_valid };
1277
1278        result.into()
1279    }
1280}