Skip to content

Commit ff2dec6

Browse files
authored
Merge pull request #977 from lilizoey/feature/builtin-varargs
Make builtin methods with varargs get generated
2 parents 6b69890 + 4a9f5b0 commit ff2dec6

File tree

9 files changed

+75
-8
lines changed

9 files changed

+75
-8
lines changed

godot-codegen/src/generator/builtins.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -262,15 +262,17 @@ fn make_builtin_method_definition(
262262
)
263263
};
264264

265-
// TODO(#382): wait for https://github.com/godot-rust/gdext/issues/382
266265
let varcall_invocation = quote! {
267-
/*<CallSig as VarcallSignatureTuple>::out_class_varcall(
266+
let method_bind = sys::builtin_method_table().#fptr_access;
267+
268+
<CallSig as VarcallSignatureTuple>::out_builtin_ptrcall_varargs(
268269
method_bind,
270+
#builtin_name_str,
269271
#method_name_str,
270272
#object_ptr,
271273
args,
272274
varargs
273-
)*/
275+
)
274276
};
275277

276278
let safety_doc = method_safety_doc(builtin_class.name(), method);
@@ -282,6 +284,7 @@ fn make_builtin_method_definition(
282284
varcall_invocation,
283285
ptrcall_invocation,
284286
is_virtual_required: false,
287+
is_varcall_fallible: false,
285288
},
286289
safety_doc,
287290
&TokenStream::new(),

godot-codegen/src/generator/classes.rs

+1
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,7 @@ fn make_class_method_definition(
536536
varcall_invocation,
537537
ptrcall_invocation,
538538
is_virtual_required: false,
539+
is_varcall_fallible: true,
539540
},
540541
None,
541542
cfg_attributes,

godot-codegen/src/generator/functions_common.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ pub struct FnCode {
4343
pub varcall_invocation: TokenStream,
4444
pub ptrcall_invocation: TokenStream,
4545
pub is_virtual_required: bool,
46+
pub is_varcall_fallible: bool,
4647
}
4748

4849
pub struct FnDefinition {
@@ -207,7 +208,7 @@ pub fn make_function_definition(
207208
let varcall_invocation = &code.varcall_invocation;
208209

209210
// TODO Utility functions: update as well.
210-
if code.receiver.param.is_empty() {
211+
if !code.is_varcall_fallible {
211212
quote! {
212213
#maybe_safety_doc
213214
#vis #maybe_unsafe fn #primary_fn_name (

godot-codegen/src/generator/utility_functions.rs

+1
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ pub(crate) fn make_utility_function_definition(function: &UtilityFunction) -> To
7171
varcall_invocation,
7272
ptrcall_invocation,
7373
is_virtual_required: false,
74+
is_varcall_fallible: false,
7475
},
7576
None,
7677
&TokenStream::new(),

godot-codegen/src/generator/virtual_traits.rs

+1
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ fn make_virtual_method(method: &ClassMethod) -> Option<TokenStream> {
155155
varcall_invocation: TokenStream::new(),
156156
ptrcall_invocation: TokenStream::new(),
157157
is_virtual_required: method.is_virtual_required(),
158+
is_varcall_fallible: true,
158159
},
159160
None,
160161
&TokenStream::new(),

godot-codegen/src/special_cases/codegen_special_cases.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,14 @@ use crate::models::json::{JsonBuiltinMethod, JsonClassMethod, JsonUtilityFunctio
1414
use crate::special_cases;
1515

1616
pub(crate) fn is_builtin_method_excluded(method: &JsonBuiltinMethod) -> bool {
17-
// TODO Fall back to varcall (recent addition in GDExtension API).
18-
// See https://github.com/godot-rust/gdext/issues/382.
19-
method.is_vararg
17+
// The `cfg` below becomes `false` for api > 4.1 so clippy would complain it's always false.
18+
#[allow(clippy::needless_bool)]
19+
if method.is_vararg {
20+
// Support for calling varargs using gdextension were added in 4.2.
21+
cfg!(before_api = "4.2")
22+
} else {
23+
false
24+
}
2025
}
2126

2227
#[cfg(not(feature = "codegen-full"))]

godot-codegen/src/special_cases/special_cases.rs

-1
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,6 @@ pub fn is_class_method_param_required(
343343

344344
/// True if builtin method is excluded. Does NOT check for type exclusion; use [`is_builtin_type_deleted`] for that.
345345
pub fn is_builtin_method_deleted(_class_name: &TyName, method: &JsonBuiltinMethod) -> bool {
346-
// Currently only deleted if codegen.
347346
codegen_special_cases::is_builtin_method_excluded(method)
348347
}
349348

godot-core/src/meta/signature.rs

+38
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,15 @@ pub trait VarcallSignatureTuple: PtrcallSignatureTuple {
7474
varargs: &[Variant],
7575
) -> Self::Ret;
7676

77+
unsafe fn out_builtin_ptrcall_varargs(
78+
builtin_fn: BuiltinMethodBind,
79+
class_name: &'static str,
80+
method_name: &'static str,
81+
type_ptr: sys::GDExtensionTypePtr,
82+
args: Self::Params,
83+
varargs: &[Variant],
84+
) -> Self::Ret;
85+
7786
fn format_args(args: &Self::Params) -> String;
7887
}
7988

@@ -303,6 +312,35 @@ macro_rules! impl_varcall_signature_for_tuple {
303312
result.unwrap_or_else(|err| return_error::<Self::Ret>(&call_ctx, err))
304313
}
305314

315+
#[inline]
316+
unsafe fn out_builtin_ptrcall_varargs(
317+
builtin_fn: BuiltinMethodBind,
318+
class_name: &'static str,
319+
method_name: &'static str,
320+
type_ptr: sys::GDExtensionTypePtr,
321+
($($pn,)*): Self::Params,
322+
varargs: &[Variant],
323+
) -> Self::Ret {
324+
let call_ctx = CallContext::outbound(class_name, method_name);
325+
//$crate::out!("out_builtin_ptrcall_varargs: {call_ctx}");
326+
327+
let explicit_args: [Variant; $PARAM_COUNT] = [
328+
$(
329+
into_ffi_variant(&$pn),
330+
)*
331+
];
332+
333+
let mut type_ptrs = Vec::with_capacity(explicit_args.len() + varargs.len());
334+
type_ptrs.extend(explicit_args.iter().map(sys::GodotFfi::sys));
335+
type_ptrs.extend(varargs.iter().map(sys::GodotFfi::sys));
336+
337+
// Important: this calls from_sys_init_default().
338+
let result = new_from_ptrcall::<Self::Ret>(|return_ptr| {
339+
builtin_fn(type_ptr, type_ptrs.as_ptr(), return_ptr, type_ptrs.len() as i32);
340+
});
341+
result.unwrap_or_else(|err| return_error::<Self::Ret>(&call_ctx, err))
342+
}
343+
306344
#[inline]
307345
fn format_args(args: &Self::Params) -> String {
308346
let mut string = String::new();

itest/rust/src/builtin_tests/containers/callable_test.rs

+18
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,24 @@ fn callable_bindv() {
151151
);
152152
}
153153

154+
// This is also testing that using works at all.
155+
#[itest]
156+
#[cfg(since_api = "4.2")]
157+
fn callable_varargs() {
158+
// TODO: Replace with proper apis instead of using `InnerCallable`.
159+
use godot::builtin::inner;
160+
let obj = CallableTestObj::new_gd();
161+
let callable = obj.callable("bar");
162+
let inner_callable = inner::InnerCallable::from_outer(&callable);
163+
let callable_bound = inner_callable.bind(&[10.to_variant()]);
164+
let inner_callable_bound = inner::InnerCallable::from_outer(&callable_bound);
165+
166+
assert_eq!(
167+
inner_callable_bound.call(&[]),
168+
10.to_variant().stringify().to_variant()
169+
);
170+
}
171+
154172
// Testing https://github.com/godot-rust/gdext/issues/410
155173

156174
#[derive(GodotClass)]

0 commit comments

Comments
 (0)