godot_core/registry/
method.rs1use godot_ffi as sys;
9use sys::interface_fn;
10
11use crate::builtin::{StringName, Variant};
12use crate::meta::{ClassId, GodotConvert, ParamTuple, Signature};
13use crate::obj::GodotClass;
14use crate::registry::info::{MethodFlags, PropertyInfo};
15
16pub struct MethodParamOrReturnInfo {
18 pub(crate) info: PropertyInfo,
19 metadata: sys::GDExtensionClassMethodArgumentMetadata,
20}
21
22impl MethodParamOrReturnInfo {
23 pub fn new(info: PropertyInfo, metadata: sys::GDExtensionClassMethodArgumentMetadata) -> Self {
24 Self { info, metadata }
25 }
26
27 pub fn for_parameter<T: GodotConvert>(param_name: &str) -> Self {
29 let shape = T::godot_shape();
30 Self {
31 info: shape.to_method_signature_property(param_name),
32 metadata: shape.param_metadata().to_sys(),
33 }
34 }
35
36 pub fn for_return<T: GodotConvert>() -> Option<Self> {
38 let shape = T::godot_shape();
39 Some(Self {
40 info: shape.to_method_signature_property(""),
41 metadata: shape.param_metadata().to_sys(),
42 })
43 }
44}
45
46pub struct ClassMethodInfo {
48 class_id: ClassId,
49 method_name: StringName,
50 call_func: sys::GDExtensionClassMethodCall,
51 ptrcall_func: sys::GDExtensionClassMethodPtrCall,
52 method_flags: MethodFlags,
53 return_value: Option<MethodParamOrReturnInfo>,
54 arguments: Vec<MethodParamOrReturnInfo>,
55 default_arguments: Vec<Variant>,
58}
59
60impl ClassMethodInfo {
61 pub unsafe fn from_signature<C: GodotClass, Params: ParamTuple, Ret: GodotConvert>(
77 method_name: StringName,
78 call_func: sys::GDExtensionClassMethodCall,
79 ptrcall_func: sys::GDExtensionClassMethodPtrCall,
80 method_flags: MethodFlags,
81 param_names: &[&str],
82 default_arguments: Vec<Variant>,
83 ) -> Self {
84 let return_value = MethodParamOrReturnInfo::for_return::<Ret>();
85 let arguments = Signature::<Params, Ret>::param_names(param_names);
86
87 assert!(
88 default_arguments.len() <= arguments.len(),
89 "cannot have more default arguments than arguments"
90 );
91
92 Self {
93 class_id: C::class_id(),
94 method_name,
95 call_func,
96 ptrcall_func,
97 method_flags,
98 return_value,
99 arguments,
100 default_arguments,
101 }
102 }
103
104 pub fn register_extension_class_method(&self) {
105 use crate::obj::EngineBitfield as _;
106
107 let (return_value_info, return_value_metadata) = match &self.return_value {
108 Some(info) => (Some(&info.info), info.metadata),
109 None => (None, 0),
110 };
111
112 let mut return_value_sys = return_value_info
113 .as_ref()
114 .map(|info| info.property_sys())
115 .unwrap_or(PropertyInfo::empty_sys());
116
117 let mut arguments_info_sys: Vec<sys::GDExtensionPropertyInfo> = self
118 .arguments
119 .iter()
120 .map(|argument| argument.info.property_sys())
121 .collect();
122
123 let mut arguments_metadata: Vec<sys::GDExtensionClassMethodArgumentMetadata> =
124 self.arguments.iter().map(|info| info.metadata).collect();
125
126 let mut default_arguments_sys: Vec<sys::GDExtensionVariantPtr> = self
127 .default_arguments
128 .iter()
129 .map(|v| sys::SysPtr::force_mut(v.var_sys()))
130 .collect();
131
132 let method_info_sys = sys::GDExtensionClassMethodInfo {
133 name: sys::SysPtr::force_mut(self.method_name.string_sys()),
134 method_userdata: std::ptr::null_mut(),
135 call_func: self.call_func,
136 ptrcall_func: self.ptrcall_func,
137 method_flags: self.method_flags.ord() as u32,
138 has_return_value: self.return_value.is_some() as u8,
139 return_value_info: std::ptr::addr_of_mut!(return_value_sys),
140 return_value_metadata,
141 argument_count: self.argument_count(),
142 arguments_info: arguments_info_sys.as_mut_ptr(),
143 arguments_metadata: arguments_metadata.as_mut_ptr(),
144 default_argument_count: self.default_argument_count(),
145 default_arguments: default_arguments_sys.as_mut_ptr(),
146 };
147
148 if self.method_flags.is_set(MethodFlags::VIRTUAL) {
149 self.register_virtual_class_method(method_info_sys, return_value_sys);
150 } else {
151 self.register_nonvirtual_class_method(method_info_sys);
152 }
153 }
154
155 fn register_nonvirtual_class_method(&self, method_info_sys: sys::GDExtensionClassMethodInfo) {
156 crate::registry::reg_validation::validate_method(self.class_id, &self.method_name);
158
159 unsafe {
164 interface_fn!(classdb_register_extension_class_method)(
165 sys::get_library(),
166 self.class_id.string_sys(),
167 std::ptr::addr_of!(method_info_sys),
168 )
169 }
170 }
171
172 #[cfg(since_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(since_api = "4.3")))]
173 fn register_virtual_class_method(
174 &self,
175 normal_method_info: sys::GDExtensionClassMethodInfo,
176 return_value_sys: sys::GDExtensionPropertyInfo, ) {
178 let method_info_sys = sys::GDExtensionClassVirtualMethodInfo {
180 name: normal_method_info.name,
181 method_flags: normal_method_info.method_flags,
182 return_value: return_value_sys,
183 return_value_metadata: normal_method_info.return_value_metadata,
184 argument_count: normal_method_info.argument_count,
185 arguments: normal_method_info.arguments_info,
186 arguments_metadata: normal_method_info.arguments_metadata,
187 };
188
189 unsafe {
191 interface_fn!(classdb_register_extension_class_virtual_method)(
192 sys::get_library(),
193 self.class_id.string_sys(),
194 std::ptr::addr_of!(method_info_sys),
195 )
196 }
197 }
198
199 #[cfg(before_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(before_api = "4.3")))]
201 fn register_virtual_class_method(
202 &self,
203 _normal_method_info: sys::GDExtensionClassMethodInfo,
204 _return_value_sys: sys::GDExtensionPropertyInfo,
205 ) {
206 }
207
208 fn argument_count(&self) -> u32 {
209 self.arguments
210 .len()
211 .try_into()
212 .expect("arguments length should fit in u32")
213 }
214
215 fn default_argument_count(&self) -> u32 {
216 self.default_arguments
217 .len()
218 .try_into()
219 .expect("arguments length should fit in u32")
220 }
221}