godot_core/registry/
method.rs1use godot_ffi as sys;
9use sys::interface_fn;
10
11use crate::builtin::{StringName, Variant};
12use crate::global::MethodFlags;
13use crate::meta::{ClassId, GodotConvert, GodotType, ParamTuple, PropertyInfo, Signature};
14use crate::obj::GodotClass;
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
28pub struct ClassMethodInfo {
30 class_id: ClassId,
31 method_name: StringName,
32 call_func: sys::GDExtensionClassMethodCall,
33 ptrcall_func: sys::GDExtensionClassMethodPtrCall,
34 method_flags: MethodFlags,
35 return_value: Option<MethodParamOrReturnInfo>,
36 arguments: Vec<MethodParamOrReturnInfo>,
37 default_arguments: Vec<Variant>,
40}
41
42impl ClassMethodInfo {
43 pub unsafe fn from_signature<C: GodotClass, Params: ParamTuple, Ret: GodotConvert>(
59 method_name: StringName,
60 call_func: sys::GDExtensionClassMethodCall,
61 ptrcall_func: sys::GDExtensionClassMethodPtrCall,
62 method_flags: MethodFlags,
63 param_names: &[&str],
64 default_arguments: Vec<Variant>,
65 ) -> Self {
66 let return_value = Ret::Via::return_info();
67 let arguments = Signature::<Params, Ret>::param_names(param_names);
68
69 assert!(
70 default_arguments.len() <= arguments.len(),
71 "cannot have more default arguments than arguments"
72 );
73
74 Self {
75 class_id: C::class_id(),
76 method_name,
77 call_func,
78 ptrcall_func,
79 method_flags,
80 return_value,
81 arguments,
82 default_arguments,
83 }
84 }
85
86 pub fn register_extension_class_method(&self) {
87 use crate::obj::EngineBitfield as _;
88
89 let (return_value_info, return_value_metadata) = match &self.return_value {
90 Some(info) => (Some(&info.info), info.metadata),
91 None => (None, 0),
92 };
93
94 let mut return_value_sys = return_value_info
95 .as_ref()
96 .map(|info| info.property_sys())
97 .unwrap_or(PropertyInfo::empty_sys());
98
99 let mut arguments_info_sys: Vec<sys::GDExtensionPropertyInfo> = self
100 .arguments
101 .iter()
102 .map(|argument| argument.info.property_sys())
103 .collect();
104
105 let mut arguments_metadata: Vec<sys::GDExtensionClassMethodArgumentMetadata> =
106 self.arguments.iter().map(|info| info.metadata).collect();
107
108 let mut default_arguments_sys: Vec<sys::GDExtensionVariantPtr> = self
109 .default_arguments
110 .iter()
111 .map(|v| sys::SysPtr::force_mut(v.var_sys()))
112 .collect();
113
114 let method_info_sys = sys::GDExtensionClassMethodInfo {
115 name: sys::SysPtr::force_mut(self.method_name.string_sys()),
116 method_userdata: std::ptr::null_mut(),
117 call_func: self.call_func,
118 ptrcall_func: self.ptrcall_func,
119 method_flags: self.method_flags.ord() as u32,
120 has_return_value: self.return_value.is_some() as u8,
121 return_value_info: std::ptr::addr_of_mut!(return_value_sys),
122 return_value_metadata,
123 argument_count: self.argument_count(),
124 arguments_info: arguments_info_sys.as_mut_ptr(),
125 arguments_metadata: arguments_metadata.as_mut_ptr(),
126 default_argument_count: self.default_argument_count(),
127 default_arguments: default_arguments_sys.as_mut_ptr(),
128 };
129
130 if self.method_flags.is_set(MethodFlags::VIRTUAL) {
131 self.register_virtual_class_method(method_info_sys, return_value_sys);
132 } else {
133 self.register_nonvirtual_class_method(method_info_sys);
134 }
135 }
136
137 fn register_nonvirtual_class_method(&self, method_info_sys: sys::GDExtensionClassMethodInfo) {
138 unsafe {
143 interface_fn!(classdb_register_extension_class_method)(
144 sys::get_library(),
145 self.class_id.string_sys(),
146 std::ptr::addr_of!(method_info_sys),
147 )
148 }
149 }
150
151 #[cfg(since_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(since_api = "4.3")))]
152 fn register_virtual_class_method(
153 &self,
154 normal_method_info: sys::GDExtensionClassMethodInfo,
155 return_value_sys: sys::GDExtensionPropertyInfo, ) {
157 let method_info_sys = sys::GDExtensionClassVirtualMethodInfo {
159 name: normal_method_info.name,
160 method_flags: normal_method_info.method_flags,
161 return_value: return_value_sys,
162 return_value_metadata: normal_method_info.return_value_metadata,
163 argument_count: normal_method_info.argument_count,
164 arguments: normal_method_info.arguments_info,
165 arguments_metadata: normal_method_info.arguments_metadata,
166 };
167
168 unsafe {
170 interface_fn!(classdb_register_extension_class_virtual_method)(
171 sys::get_library(),
172 self.class_id.string_sys(),
173 std::ptr::addr_of!(method_info_sys),
174 )
175 }
176 }
177
178 #[cfg(before_api = "4.3")] #[cfg_attr(published_docs, doc(cfg(before_api = "4.3")))]
180 fn register_virtual_class_method(
181 &self,
182 _normal_method_info: sys::GDExtensionClassMethodInfo,
183 _return_value_sys: sys::GDExtensionPropertyInfo,
184 ) {
185 }
186
187 fn argument_count(&self) -> u32 {
188 self.arguments
189 .len()
190 .try_into()
191 .expect("arguments length should fit in u32")
192 }
193
194 fn default_argument_count(&self) -> u32 {
195 self.default_arguments
196 .len()
197 .try_into()
198 .expect("arguments length should fit in u32")
199 }
200}