Skip to content

Commit 2609cf4

Browse files
authored
Try #252:
2 parents 0626d94 + 20bf29b commit 2609cf4

File tree

6 files changed

+441
-117
lines changed

6 files changed

+441
-117
lines changed

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

Lines changed: 142 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,14 @@ pub trait SignatureTuple {
3535
method_name: &str,
3636
);
3737

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,
43+
method_name: &str,
44+
);
45+
3846
// Note: this method imposes extra bounds on GodotFfi, which may not be implemented for user types.
3947
// We could fall back to varcalls in such cases, and not require GodotFfi categorically.
4048
unsafe fn ptrcall<C: GodotClass>(
@@ -56,6 +64,16 @@ pub trait SignatureTuple {
5664
method_name: &str,
5765
call_type: sys::PtrcallType,
5866
);
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,
75+
call_type: sys::PtrcallType,
76+
);
5977
}
6078

6179
// impl<P, const N: usize> Sig for [P; N]
@@ -127,71 +145,72 @@ macro_rules! impl_signature_for_tuple {
127145

128146
#[inline]
129147
unsafe fn varcall<C : GodotClass>(
130-
instance_ptr: sys::GDExtensionClassInstancePtr,
148+
instance_ptr: sys::GDExtensionClassInstancePtr,
131149
args_ptr: *const sys::GDExtensionConstVariantPtr,
132150
ret: sys::GDExtensionVariantPtr,
133151
err: *mut sys::GDExtensionCallError,
134152
func: fn(&C, Self::Params) -> Self::Ret,
135153
method_name: &str,
136154
) {
137-
$crate::out!("varcall: {}", method_name);
155+
$crate::out!("varcall: {}", method_name);
138156

139157
let storage = unsafe { crate::private::as_storage::<C>(instance_ptr) };
140158
let instance = storage.get();
141159

142-
let args = ( $(
143-
{
144-
let variant = unsafe { &*(*args_ptr.offset($n) as *mut Variant) }; // TODO from_var_sys
145-
let arg = <$Pn as FromVariant>::try_from_variant(variant)
146-
.unwrap_or_else(|e| param_error::<$Pn>(method_name, $n, variant));
147-
148-
arg
149-
},
150-
)* );
151-
152-
let ret_val = func(&*instance, args);
153-
let ret_variant = <$R as ToVariant>::to_variant(&ret_val); // TODO write_sys
154-
unsafe {
155-
*(ret as *mut Variant) = ret_variant;
156-
(*err).error = sys::GDEXTENSION_CALL_OK;
157-
}
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)
158167
}
159168

160169
#[inline]
161170
unsafe fn varcall_mut<C : GodotClass>(
162-
instance_ptr: sys::GDExtensionClassInstancePtr,
171+
instance_ptr: sys::GDExtensionClassInstancePtr,
163172
args_ptr: *const sys::GDExtensionConstVariantPtr,
164173
ret: sys::GDExtensionVariantPtr,
165174
err: *mut sys::GDExtensionCallError,
166175
func: fn(&mut C, Self::Params) -> Self::Ret,
167176
method_name: &str,
168177
) {
169-
$crate::out!("varcall: {}", method_name);
178+
$crate::out!("varcall_mut: {}", method_name);
170179

171180
let storage = unsafe { crate::private::as_storage::<C>(instance_ptr) };
172181
let mut instance = storage.get_mut();
173182

174-
let args = ( $(
175-
{
176-
let variant = unsafe { &*(*args_ptr.offset($n) as *mut Variant) }; // TODO from_var_sys
177-
let arg = <$Pn as FromVariant>::try_from_variant(variant)
178-
.unwrap_or_else(|e| param_error::<$Pn>(method_name, $n, variant));
179-
180-
arg
181-
},
182-
)* );
183-
184-
let ret_val = func(&mut *instance, args);
185-
let ret_variant = <$R as ToVariant>::to_variant(&ret_val); // TODO write_sys
186-
unsafe {
187-
*(ret as *mut Variant) = ret_variant;
188-
(*err).error = sys::GDEXTENSION_CALL_OK;
189-
}
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)
190209
}
191210

192211
#[inline]
193212
unsafe fn ptrcall<C : GodotClass>(
194-
instance_ptr: sys::GDExtensionClassInstancePtr,
213+
instance_ptr: sys::GDExtensionClassInstancePtr,
195214
args_ptr: *const sys::GDExtensionConstTypePtr,
196215
ret: sys::GDExtensionTypePtr,
197216
func: fn(&C, Self::Params) -> Self::Ret,
@@ -203,59 +222,117 @@ macro_rules! impl_signature_for_tuple {
203222
let storage = unsafe { crate::private::as_storage::<C>(instance_ptr) };
204223
let instance = storage.get();
205224

206-
let args = ( $(
207-
unsafe {
208-
<$Pn as sys::GodotFuncMarshal>::try_from_arg(
209-
sys::force_mut_ptr(*args_ptr.offset($n)),
210-
call_type
211-
)
212-
}
213-
.unwrap_or_else(|e| param_error::<$Pn>(method_name, $n, &e)),
214-
)* );
215-
216-
let ret_val = func(&*instance, args);
225+
let args = ($( unsafe { ptrcall_arg::<$Pn, $n>(args_ptr, method_name, call_type) }, )*) ;
226+
217227
// SAFETY:
218228
// `ret` is always a pointer to an initialized value of type $R
219229
// TODO: double-check the above
220-
<$R as sys::GodotFuncMarshal>::try_return(ret_val, ret, call_type)
221-
.unwrap_or_else(|ret_val| return_error::<$R>(method_name, &ret_val));
230+
ptrcall_return::<$R>(func(& *instance, args), ret, method_name, call_type)
222231
}
223232

224233
#[inline]
225234
unsafe fn ptrcall_mut<C : GodotClass>(
226-
instance_ptr: sys::GDExtensionClassInstancePtr,
235+
instance_ptr: sys::GDExtensionClassInstancePtr,
227236
args_ptr: *const sys::GDExtensionConstTypePtr,
228237
ret: sys::GDExtensionTypePtr,
229238
func: fn(&mut C, Self::Params) -> Self::Ret,
230239
method_name: &str,
231240
call_type: sys::PtrcallType,
232241
) {
233-
$crate::out!("ptrcall: {}", method_name);
242+
$crate::out!("ptrcall_mut: {}", method_name);
234243

235244
let storage = unsafe { crate::private::as_storage::<C>(instance_ptr) };
236245
let mut instance = storage.get_mut();
237246

238-
let args = ( $(
239-
unsafe {
240-
<$Pn as sys::GodotFuncMarshal>::try_from_arg(
241-
sys::force_mut_ptr(*args_ptr.offset($n)),
242-
call_type
243-
)
244-
}
245-
.unwrap_or_else(|e| param_error::<$Pn>(method_name, $n, &e)),
246-
)* );
247-
248-
let ret_val = func(&mut *instance, args);
247+
let args = ($( unsafe { ptrcall_arg::<$Pn, $n>(args_ptr, method_name, call_type) }, )*) ;
248+
249249
// SAFETY:
250250
// `ret` is always a pointer to an initialized value of type $R
251251
// TODO: double-check the above
252-
<$R as sys::GodotFuncMarshal>::try_return(ret_val, ret, call_type)
253-
.unwrap_or_else(|ret_val| return_error::<$R>(method_name, &ret_val));
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) }, )*) ;
266+
267+
// SAFETY:
268+
// `ret` is always a pointer to an initialized value of type $R
269+
// TODO: double-check the above
270+
ptrcall_return::<$R>(func(args), ret, method_name, call_type)
254271
}
255272
}
256273
};
257274
}
258275

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+
259336
fn param_error<P>(method_name: &str, index: i32, arg: &impl Debug) -> ! {
260337
let param_ty = std::any::type_name::<P>();
261338
panic!(

0 commit comments

Comments
 (0)