Skip to content

Commit d6a2bd0

Browse files
committed
finalize static func implementation
1 parent 0ddbed9 commit d6a2bd0

File tree

6 files changed

+364
-154
lines changed

6 files changed

+364
-154
lines changed

godot-core/src/builtin/meta/signature.rs

Lines changed: 152 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,15 @@ pub trait SignatureTuple {
3131
args_ptr: *const sys::GDExtensionConstVariantPtr,
3232
ret: sys::GDExtensionVariantPtr,
3333
err: *mut sys::GDExtensionCallError,
34-
func: fn(sys::GDExtensionClassInstancePtr, Self::Params) -> Self::Ret,
34+
func: fn(&mut C, Self::Params) -> Self::Ret,
35+
method_name: &str,
36+
);
37+
38+
unsafe fn varcall_static<C: GodotClass>(
39+
args_ptr: *const sys::GDExtensionConstVariantPtr,
40+
ret: sys::GDExtensionVariantPtr,
41+
err: *mut sys::GDExtensionCallError,
42+
func: fn(Self::Params) -> Self::Ret,
3543
method_name: &str,
3644
);
3745

@@ -52,7 +60,18 @@ pub trait SignatureTuple {
5260
instance_ptr: sys::GDExtensionClassInstancePtr,
5361
args_ptr: *const sys::GDExtensionConstTypePtr,
5462
ret: sys::GDExtensionTypePtr,
55-
func: fn(sys::GDExtensionClassInstancePtr, Self::Params) -> Self::Ret,
63+
func: fn(&mut C, Self::Params) -> Self::Ret,
64+
method_name: &str,
65+
call_type: sys::PtrcallType,
66+
);
67+
68+
// Note: this method imposes extra bounds on GodotFfi, which may not be implemented for user types.
69+
// We could fall back to varcalls in such cases, and not require GodotFfi categorically.
70+
unsafe fn ptrcall_static<C: GodotClass>(
71+
args_ptr: *const sys::GDExtensionConstTypePtr,
72+
ret: sys::GDExtensionTypePtr,
73+
func: fn(Self::Params) -> Self::Ret,
74+
method_name: &str,
5675
call_type: sys::PtrcallType,
5776
);
5877
}
@@ -133,56 +152,60 @@ macro_rules! impl_signature_for_tuple {
133152
func: fn(&C, Self::Params) -> Self::Ret,
134153
method_name: &str,
135154
) {
136-
$crate::out!("varcall: {}", method_name);
155+
$crate::out!("varcall: {}", method_name);
137156

138157
let storage = unsafe { crate::private::as_storage::<C>(instance_ptr) };
139158
let instance = storage.get();
140159

141-
let args = ( $(
142-
{
143-
let variant = unsafe { &*(*args_ptr.offset($n) as *mut Variant) }; // TODO from_var_sys
144-
let arg = <$Pn as FromVariant>::try_from_variant(variant)
145-
.unwrap_or_else(|e| param_error::<$Pn>(method_name, $n, variant));
146-
147-
arg
148-
},
149-
)* );
150-
151-
let ret_val = func(&*instance, args);
152-
let ret_variant = <$R as ToVariant>::to_variant(&ret_val); // TODO write_sys
153-
unsafe {
154-
*(ret as *mut Variant) = ret_variant;
155-
(*err).error = sys::GDEXTENSION_CALL_OK;
156-
}
160+
let args_ptr = args_ptr as *const *mut Variant;
161+
162+
let args = ($( unsafe { varcall_arg::<$Pn, $n>(args_ptr, method_name) }, )*) ;
163+
164+
let ret = ret as *mut Variant;
165+
166+
varcall_return::<$R>(func(& *instance, args), ret, err)
157167
}
158168

159169
#[inline]
160170
unsafe fn varcall_mut<C : GodotClass>(
161-
instance_ptr: sys::GDExtensionClassInstancePtr,
171+
instance_ptr: sys::GDExtensionClassInstancePtr,
162172
args_ptr: *const sys::GDExtensionConstVariantPtr,
163173
ret: sys::GDExtensionVariantPtr,
164174
err: *mut sys::GDExtensionCallError,
165-
func: fn(sys::GDExtensionClassInstancePtr, Self::Params) -> Self::Ret,
175+
func: fn(&mut C, Self::Params) -> Self::Ret,
166176
method_name: &str,
167177
) {
168-
$crate::out!("varcall: {}", method_name);
178+
$crate::out!("varcall_mut: {}", method_name);
169179

170-
let args = ( $(
171-
{
172-
let variant = unsafe { &*(*args_ptr.offset($n) as *mut Variant) }; // TODO from_var_sys
173-
let arg = <$Pn as FromVariant>::try_from_variant(variant)
174-
.unwrap_or_else(|e| param_error::<$Pn>(method_name, $n, variant));
175-
176-
arg
177-
},
178-
)* );
179-
180-
let ret_val = func(instance_ptr, args);
181-
let ret_variant = <$R as ToVariant>::to_variant(&ret_val); // TODO write_sys
182-
unsafe {
183-
*(ret as *mut Variant) = ret_variant;
184-
(*err).error = sys::GDEXTENSION_CALL_OK;
185-
}
180+
let storage = unsafe { crate::private::as_storage::<C>(instance_ptr) };
181+
let mut instance = storage.get_mut();
182+
183+
let args_ptr = args_ptr as *const *mut Variant;
184+
185+
let args = ($( unsafe { varcall_arg::<$Pn, $n>(args_ptr, method_name) }, )*) ;
186+
187+
let ret = ret as *mut Variant;
188+
189+
varcall_return::<$R>(func(&mut *instance, args), ret, err)
190+
}
191+
192+
#[inline]
193+
unsafe fn varcall_static<C : GodotClass>(
194+
args_ptr: *const sys::GDExtensionConstVariantPtr,
195+
ret: sys::GDExtensionVariantPtr,
196+
err: *mut sys::GDExtensionCallError,
197+
func: fn(Self::Params) -> Self::Ret,
198+
method_name: &str,
199+
) {
200+
$crate::out!("varcall_static: {}", method_name);
201+
202+
let args_ptr = args_ptr as *const *mut Variant;
203+
204+
let args = ($( unsafe { varcall_arg::<$Pn, $n>(args_ptr, method_name) }, )*) ;
205+
206+
let ret = ret as *mut Variant;
207+
208+
varcall_return::<$R>(func(args), ret, err)
186209
}
187210

188211
#[inline]
@@ -199,55 +222,117 @@ macro_rules! impl_signature_for_tuple {
199222
let storage = unsafe { crate::private::as_storage::<C>(instance_ptr) };
200223
let instance = storage.get();
201224

202-
let args = ( $(
203-
unsafe {
204-
<$Pn as sys::GodotFuncMarshal>::try_from_arg(
205-
sys::force_mut_ptr(*args_ptr.offset($n)),
206-
call_type
207-
)
208-
}
209-
.unwrap_or_else(|e| param_error::<$Pn>(method_name, $n, &e)),
210-
)* );
211-
212-
let ret_val = func(&*instance, args);
225+
let args = ($( unsafe { ptrcall_arg::<$Pn, $n>(args_ptr, method_name, call_type) }, )*) ;
226+
213227
// SAFETY:
214228
// `ret` is always a pointer to an initialized value of type $R
215229
// TODO: double-check the above
216-
<$R as sys::GodotFuncMarshal>::try_return(ret_val, ret, call_type)
217-
.unwrap_or_else(|ret_val| return_error::<$R>(method_name, &ret_val));
230+
ptrcall_return::<$R>(func(& *instance, args), ret, method_name, call_type)
218231
}
219232

220233
#[inline]
221234
unsafe fn ptrcall_mut<C : GodotClass>(
222-
instance_ptr: sys::GDExtensionClassInstancePtr,
235+
instance_ptr: sys::GDExtensionClassInstancePtr,
223236
args_ptr: *const sys::GDExtensionConstTypePtr,
224237
ret: sys::GDExtensionTypePtr,
225-
func: fn(sys::GDExtensionClassInstancePtr, Self::Params) -> Self::Ret,
238+
func: fn(&mut C, Self::Params) -> Self::Ret,
239+
method_name: &str,
226240
call_type: sys::PtrcallType,
227241
) {
228-
$crate::out!("ptrcall: {}", method_name);
242+
$crate::out!("ptrcall_mut: {}", method_name);
243+
244+
let storage = unsafe { crate::private::as_storage::<C>(instance_ptr) };
245+
let mut instance = storage.get_mut();
246+
247+
let args = ($( unsafe { ptrcall_arg::<$Pn, $n>(args_ptr, method_name, call_type) }, )*) ;
248+
249+
// SAFETY:
250+
// `ret` is always a pointer to an initialized value of type $R
251+
// TODO: double-check the above
252+
ptrcall_return::<$R>(func(&mut *instance, args), ret, method_name, call_type)
253+
}
254+
255+
#[inline]
256+
unsafe fn ptrcall_static<C : GodotClass>(
257+
args_ptr: *const sys::GDExtensionConstTypePtr,
258+
ret: sys::GDExtensionTypePtr,
259+
func: fn(Self::Params) -> Self::Ret,
260+
method_name: &str,
261+
call_type: sys::PtrcallType,
262+
) {
263+
$crate::out!("ptrcall_static: {}", method_name);
264+
265+
let args = ($( unsafe { ptrcall_arg::<$Pn, $n>(args_ptr, method_name, call_type) }, )*) ;
229266

230-
let args = ( $(
231-
unsafe {
232-
<$Pn as sys::GodotFuncMarshal>::try_from_arg(
233-
sys::force_mut_ptr(*args_ptr.offset($n)),
234-
call_type
235-
)
236-
}
237-
.unwrap_or_else(|e| param_error::<$Pn>(method_name, $n, &e)),
238-
)* );
239-
240-
let ret_val = func(instance_ptr, args);
241267
// SAFETY:
242268
// `ret` is always a pointer to an initialized value of type $R
243269
// TODO: double-check the above
244-
<$R as sys::GodotFuncMarshal>::try_return(ret_val, ret, call_type)
245-
.unwrap_or_else(|ret_val| return_error::<$R>(method_name, &ret_val));
270+
ptrcall_return::<$R>(func(args), ret, method_name, call_type)
246271
}
247272
}
248273
};
249274
}
250275

276+
/// Convert the `N`th argument of `args_ptr` into a value of type `P`.
277+
///
278+
/// # Safety
279+
/// - It must be safe to dereference the pointer at `args_ptr.offset(N)` .
280+
unsafe fn varcall_arg<P: FromVariant, const N: isize>(
281+
args_ptr: *const *mut Variant,
282+
method_name: &str,
283+
) -> P {
284+
let variant = &*(*args_ptr.offset(N)); // TODO from_var_sys
285+
P::try_from_variant(variant)
286+
.unwrap_or_else(|_| param_error::<P>(method_name, N as i32, variant))
287+
}
288+
289+
/// Moves `ret_val` into `ret`.
290+
///
291+
/// # Safety
292+
/// - `ret` must be a pointer to an initialized `Variant`.
293+
/// - It must be safe to write a `Variant` once to `ret`.
294+
/// - It must be safe to write a `sys::GDExtensionCallError` once to `err`.
295+
unsafe fn varcall_return<R: ToVariant>(
296+
ret_val: R,
297+
ret: *mut Variant,
298+
err: *mut sys::GDExtensionCallError,
299+
) {
300+
let ret_variant = ret_val.to_variant(); // TODO write_sys
301+
*ret = ret_variant;
302+
(*err).error = sys::GDEXTENSION_CALL_OK;
303+
}
304+
305+
/// Convert the `N`th argument of `args_ptr` into a value of type `P`.
306+
///
307+
/// # Safety
308+
/// - It must be safe to dereference the address at `args_ptr.offset(N)` .
309+
/// - The pointer at `args_ptr.offset(N)` must follow the safety requirements as laid out in
310+
/// [`GodotFuncMarshal::try_from_arg`][sys::GodotFuncMarshal::try_from_arg].
311+
unsafe fn ptrcall_arg<P: sys::GodotFuncMarshal, const N: isize>(
312+
args_ptr: *const sys::GDExtensionConstTypePtr,
313+
method_name: &str,
314+
call_type: sys::PtrcallType,
315+
) -> P {
316+
P::try_from_arg(sys::force_mut_ptr(*args_ptr.offset(N)), call_type)
317+
.unwrap_or_else(|e| param_error::<P>(method_name, N as i32, &e))
318+
}
319+
320+
/// Moves `ret_val` into `ret`.
321+
///
322+
/// # Safety
323+
/// `ret_val`, `ret`, and `call_type` must follow the safety requirements as laid out in
324+
/// [`GodotFuncMarshal::try_return`](sys::GodotFuncMarshal::try_return).
325+
unsafe fn ptrcall_return<R: sys::GodotFuncMarshal + std::fmt::Debug>(
326+
ret_val: R,
327+
ret: sys::GDExtensionTypePtr,
328+
method_name: &str,
329+
call_type: sys::PtrcallType,
330+
) {
331+
ret_val
332+
.try_return(ret, call_type)
333+
.unwrap_or_else(|ret_val| return_error::<R>(method_name, &ret_val))
334+
}
335+
251336
fn param_error<P>(method_name: &str, index: i32, arg: &impl Debug) -> ! {
252337
let param_ty = std::any::type_name::<P>();
253338
panic!(

0 commit comments

Comments
 (0)