Skip to main content

godot_core/registry/info/
method_info.rs

1/*
2 * Copyright (c) godot-rust; Bromeon and contributors.
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
6 */
7
8use godot_ffi::conv::u32_to_usize;
9
10use crate::builtin::{StringName, Variant};
11use crate::meta::ClassId;
12use crate::registry::info::{MethodFlags, PropertyInfo};
13use crate::sys;
14
15/// Describes a method's signature and metadata required by the Godot engine.
16///
17/// Primarily used when implementing custom script instances via the [`ScriptInstance`][crate::obj::script::ScriptInstance] trait.
18/// It contains metadata Godot needs to describe and call a method.
19///
20/// `MethodInfo` is a high-level abstraction over the low-level FFI type `sys::GDExtensionMethodInfo`.
21///
22/// See also [`PropertyInfo`] for describing individual method parameters and return types.
23///
24/// # Example
25/// ```no_run
26/// use godot::builtin::{StringName, Variant, VariantType};
27/// use godot::classes::Node2D;
28/// use godot::meta::ClassId;
29/// use godot::obj::GodotClass; // Trait method ::class_id().
30/// use godot::register::info::{MethodInfo, PropertyInfo, PropertyHintInfo, MethodFlags, PropertyUsageFlags};
31///
32/// // Describe a Godot method (`World` is a GDScript class):
33/// //   func spawn_at(world: World, position: Vector2) -> Node2D.
34/// let method = MethodInfo {
35///     id: 0,
36///     method_name: StringName::from("spawn_at"),
37///     class_name: ClassId::none(),
38///     return_type: PropertyInfo {
39///         variant_type: VariantType::OBJECT,
40///         class_name: Node2D::class_id().to_string_name(),
41///         property_name: StringName::default(), // Return types use empty string.
42///         hint_info: PropertyHintInfo::none(),
43///         usage: PropertyUsageFlags::DEFAULT,
44///     },
45///     arguments: vec![
46///         PropertyInfo {
47///             variant_type: VariantType::OBJECT,
48///             class_name: ClassId::new_dynamic("World").to_string_name(),
49///             property_name: StringName::from("world"),
50///             hint_info: PropertyHintInfo::none(),
51///             usage: PropertyUsageFlags::DEFAULT,
52///         },
53///         PropertyInfo {
54///             variant_type: VariantType::VECTOR2,
55///             class_name: StringName::default(),
56///             property_name: StringName::from("position"),
57///             hint_info: PropertyHintInfo::none(),
58///             usage: PropertyUsageFlags::DEFAULT,
59///         },
60///     ],
61///     default_arguments: vec![],
62///     flags: MethodFlags::DEFAULT,
63/// };
64/// ```
65#[derive(Clone, Debug)]
66pub struct MethodInfo {
67    /// Unique identifier for the method within its class.
68    ///
69    /// This ID can be used to distinguish between methods and is typically set by the implementation. For script instances,
70    /// this is often just a sequential index.
71    pub id: i32,
72
73    /// The name of the method, as it appears in Godot.
74    pub method_name: StringName,
75
76    /// The class this method belongs to.
77    ///
78    /// For script-defined methods, this is typically the script's class ID obtained via [`ClassId::new_dynamic()`].
79    /// Use [`ClassId::none()`] if the class is not applicable or unknown.
80    pub class_name: ClassId,
81
82    /// Description of the method's return type.
83    ///
84    /// See [`PropertyInfo`] for how to construct type information. For methods that
85    /// don't return a value (void), use `VariantType::NIL`.
86    pub return_type: PropertyInfo,
87
88    /// Descriptions of each method parameter.
89    ///
90    /// Each element describes one parameter's type, name, and metadata. The order
91    /// matches the parameter order in the method signature.
92    pub arguments: Vec<PropertyInfo>,
93
94    /// Default values for parameters with defaults.
95    ///
96    /// Contains the actual default [`Variant`] values for parameters that have them.
97    /// The length of this vector is typically less than or equal to `arguments.len()`,
98    /// containing defaults only for trailing parameters.
99    pub default_arguments: Vec<Variant>,
100
101    /// Method flags controlling behavior and access.
102    ///
103    /// See [`MethodFlags`] for available options like `NORMAL`, `VIRTUAL`, `CONST`, etc.
104    pub flags: MethodFlags,
105}
106
107impl MethodInfo {
108    /// Consumes self and turns it into a `sys::GDExtensionMethodInfo`, should be used together with
109    /// [`free_owned_method_sys`](Self::free_owned_method_sys).
110    ///
111    /// This will leak memory unless used together with `free_owned_method_sys`.
112    #[doc(hidden)]
113    pub fn into_owned_method_sys(self) -> sys::GDExtensionMethodInfo {
114        use crate::obj::EngineBitfield as _;
115
116        // Destructure self to ensure all fields are used.
117        let Self {
118            id,
119            method_name,
120            // TODO: Do we need this?
121            class_name: _class_name,
122            return_type,
123            arguments,
124            default_arguments,
125            flags,
126        } = self;
127
128        let argument_count: u32 = arguments
129            .len()
130            .try_into()
131            .expect("cannot have more than `u32::MAX` arguments");
132        let arguments = arguments
133            .into_iter()
134            .map(|arg| arg.into_owned_property_sys())
135            .collect::<Box<[_]>>();
136        let arguments = Box::leak(arguments).as_mut_ptr();
137
138        let default_argument_count: u32 = default_arguments
139            .len()
140            .try_into()
141            .expect("cannot have more than `u32::MAX` default arguments");
142        let default_argument = default_arguments
143            .into_iter()
144            .map(|arg| arg.into_owned_var_sys())
145            .collect::<Box<[_]>>();
146        let default_arguments = Box::leak(default_argument).as_mut_ptr();
147
148        sys::GDExtensionMethodInfo {
149            id,
150            name: method_name.into_owned_string_sys(),
151            return_value: return_type.into_owned_property_sys(),
152            argument_count,
153            arguments,
154            default_argument_count,
155            default_arguments,
156            flags: flags.ord().try_into().expect("flags should be valid"),
157        }
158    }
159
160    /// Properly frees a `sys::GDExtensionMethodInfo` created by [`into_owned_method_sys`](Self::into_owned_method_sys).
161    ///
162    /// # Safety
163    ///
164    /// * Must only be used on a struct returned from a call to `into_owned_method_sys`, without modification.
165    /// * Must not be called more than once on a `sys::GDExtensionMethodInfo` struct.
166    #[doc(hidden)]
167    pub unsafe fn free_owned_method_sys(info: sys::GDExtensionMethodInfo) {
168        // Destructure info to ensure all fields are used.
169        let sys::GDExtensionMethodInfo {
170            name,
171            return_value,
172            flags: _flags,
173            id: _id,
174            argument_count,
175            arguments,
176            default_argument_count,
177            default_arguments,
178        } = info;
179
180        // SAFETY: `name` is a pointer that was returned from `StringName::into_owned_string_sys`, and has not been freed before this.
181        let _name = unsafe { StringName::from_owned_string_sys(name) };
182
183        // SAFETY: `return_value` is a pointer that was returned from `PropertyInfo::into_owned_property_sys`, and has not been freed before
184        // this.
185        unsafe { PropertyInfo::free_owned_property_sys(return_value) };
186
187        // SAFETY:
188        // - `from_raw_parts_mut`: `arguments` comes from `as_mut_ptr()` on a mutable slice of length `argument_count`, and no other
189        //    accesses to the pointer happens for the lifetime of the slice.
190        // - `Box::from_raw`: The slice was returned from a call to `Box::leak`, and we have ownership of the value behind this pointer.
191        let arguments = unsafe {
192            let slice = std::slice::from_raw_parts_mut(arguments, u32_to_usize(argument_count));
193
194            Box::from_raw(slice)
195        };
196
197        for info in arguments.iter() {
198            // SAFETY: These infos were originally created from a call to `PropertyInfo::into_owned_property_sys`, and this method
199            // will not be called again on this pointer.
200            unsafe { PropertyInfo::free_owned_property_sys(*info) }
201        }
202
203        // SAFETY:
204        // - `from_raw_parts_mut`: `default_arguments` comes from `as_mut_ptr()` on a mutable slice of length `default_argument_count`, and no
205        //    other accesses to the pointer happens for the lifetime of the slice.
206        // - `Box::from_raw`: The slice was returned from a call to `Box::leak`, and we have ownership of the value behind this pointer.
207        let default_arguments = unsafe {
208            let slice = std::slice::from_raw_parts_mut(
209                default_arguments,
210                u32_to_usize(default_argument_count),
211            );
212
213            Box::from_raw(slice)
214        };
215
216        for variant in default_arguments.iter() {
217            // SAFETY: These pointers were originally created from a call to `Variant::into_owned_var_sys`, and this method will not be
218            // called again on this pointer.
219            let _variant = unsafe { Variant::from_owned_var_sys(*variant) };
220        }
221    }
222}