Skip to content

Commit 864b06e

Browse files
authored
Try #207:
2 parents e0d45a3 + 783939c commit 864b06e

File tree

2 files changed

+85
-4
lines changed

2 files changed

+85
-4
lines changed

godot-codegen/src/class_generator.rs

Lines changed: 55 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -988,11 +988,63 @@ fn make_virtual_method(class_method: &ClassMethod, ctx: &mut Context) -> TokenSt
988988
// Virtual methods are never static.
989989
assert!(!class_method.is_static);
990990

991-
let receiver = make_receiver_self_param(false, class_method.is_const);
992-
let [params, _, _, _] = make_params(&class_method.arguments, class_method.is_vararg, ctx);
991+
let [params, variant_types, _, arg_names] =
992+
make_params(&class_method.arguments, class_method.is_vararg, ctx);
993+
994+
let is_varcall = class_method.is_vararg;
995+
let variant_ffi = is_varcall.then(VariantFfi::type_ptr);
996+
let (receiver, receiver_arg) = make_receiver(
997+
class_method.is_static,
998+
class_method.is_const,
999+
quote! { self.object_ptr },
1000+
);
1001+
let varcall_invocation = quote! {
1002+
__call_fn(__method_bind, #receiver_arg, __args_ptr, __args.len() as i64, return_ptr, std::ptr::addr_of_mut!(__err));
1003+
};
1004+
let ptrcall_invocation = quote! {
1005+
__call_fn(__method_bind, #receiver_arg, __args_ptr, return_ptr);
1006+
};
1007+
1008+
let (prepare_arg_types, error_fn_context);
1009+
if variant_ffi.is_some() {
1010+
// varcall (using varargs)
1011+
prepare_arg_types = quote! {
1012+
let mut __arg_types = Vec::with_capacity(__explicit_args.len() + varargs.len());
1013+
// __arg_types.extend(__explicit_args.iter().map(Variant::get_type));
1014+
__arg_types.extend(varargs.iter().map(Variant::get_type));
1015+
let __vararg_str = varargs.iter().map(|v| format!("{v}")).collect::<Vec<_>>().join(", ");
1016+
};
1017+
1018+
let joined = arg_names
1019+
.iter()
1020+
.map(|n| format!("{{{n}:?}}"))
1021+
.collect::<Vec<_>>()
1022+
.join(", ");
1023+
1024+
let fmt = format!("{method_name}({joined}; {{__vararg_str}})");
1025+
error_fn_context = quote! { &format!(#fmt) };
1026+
} else {
1027+
// ptrcall
1028+
prepare_arg_types = quote! {
1029+
let __arg_types = [
1030+
#( #variant_types ),*
1031+
];
1032+
};
1033+
error_fn_context = method_name.to_token_stream();
1034+
};
1035+
1036+
let (return_value, _) = make_return(
1037+
class_method.return_value.as_ref(),
1038+
variant_ffi.as_ref(),
1039+
&varcall_invocation,
1040+
&ptrcall_invocation,
1041+
prepare_arg_types,
1042+
error_fn_context,
1043+
ctx,
1044+
);
9931045

9941046
quote! {
995-
fn #method_name ( #receiver #( #params , )* ) {
1047+
fn #method_name ( #receiver #( #params , )* ) #return_value {
9961048
unimplemented!()
9971049
}
9981050
}

itest/rust/src/virtual_methods_test.rs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@ use crate::TestContext;
1010
use godot::bind::{godot_api, GodotClass};
1111
use godot::builtin::GodotString;
1212
use godot::engine::node::InternalMode;
13-
use godot::engine::{Node, Node2D, Node2DVirtual, RefCounted, RefCountedVirtual};
13+
use godot::engine::{Node, Node2D, Node2DVirtual, NodeVirtual, RefCounted, RefCountedVirtual};
1414
use godot::obj::{Base, Gd, Share};
15+
use godot::prelude::PackedStringArray;
1516
use godot::test::itest;
1617

1718
/// Simple class, that deliberately has no constructor accessible from GDScript
@@ -91,6 +92,26 @@ impl Node2DVirtual for TreeVirtualTest {
9192
}
9293
}
9394

95+
#[derive(GodotClass, Debug)]
96+
#[class(base=Node)]
97+
struct ReturnVirtualTest {
98+
#[base]
99+
base: Base<Node>,
100+
}
101+
102+
#[godot_api]
103+
impl NodeVirtual for ReturnVirtualTest {
104+
fn init(base: Base<Node>) -> Self {
105+
ReturnVirtualTest { base }
106+
}
107+
108+
fn get_configuration_warnings(&self) -> PackedStringArray {
109+
let mut output = PackedStringArray::new();
110+
output.push("Hello".into());
111+
output
112+
}
113+
}
114+
94115
// ----------------------------------------------------------------------------------------------------------------------------------------------
95116

96117
#[itest]
@@ -215,3 +236,11 @@ fn test_tree_enters_exits(test_context: &TestContext) {
215236
assert_eq!(obj.bind().tree_enters, 2);
216237
assert_eq!(obj.bind().tree_exits, 1);
217238
}
239+
240+
#[itest]
241+
fn test_virtual_method_with_return(_test_context: &TestContext) {
242+
let obj = Gd::<ReturnVirtualTest>::new_default();
243+
let output = obj.bind().get_configuration_warnings();
244+
assert!(output.contains("Hello".into()));
245+
assert_eq!(output.len(), 1);
246+
}

0 commit comments

Comments
 (0)