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}