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