Skip to content

Commit 9db7baf

Browse files
committed
More extensive tests of #[func] passing between GDScript and Rust
1 parent 47027d3 commit 9db7baf

File tree

8 files changed

+123
-59
lines changed

8 files changed

+123
-59
lines changed

godot-core/src/builtin/array.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -849,7 +849,7 @@ macro_rules! varray {
849849
/// [`set_typed`](https://docs.godotengine.org/en/latest/classes/class_array.html#class-array-method-set-typed).
850850
///
851851
/// We ignore the `script` parameter because it has no impact on typing in Godot.
852-
#[derive(Debug, PartialEq, Eq)]
852+
#[derive(PartialEq, Eq)]
853853
struct TypeInfo {
854854
variant_type: VariantType,
855855
class_name: StringName,
@@ -874,3 +874,16 @@ impl TypeInfo {
874874
self.variant_type != VariantType::Nil
875875
}
876876
}
877+
878+
impl fmt::Debug for TypeInfo {
879+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
880+
let class = self.class_name.to_string();
881+
let class_str = if class.is_empty() {
882+
String::new()
883+
} else {
884+
format!(" (class={class})")
885+
};
886+
887+
write!(f, "{:?}{}", self.variant_type, class_str)
888+
}
889+
}

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

Lines changed: 15 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,14 @@ pub trait VariantMetadata {
2727
}
2828

2929
fn property_info(property_name: &str) -> PropertyInfo {
30-
PropertyInfo::new(
31-
Self::variant_type(),
32-
Self::class_name(),
33-
StringName::from(property_name),
34-
global::PropertyHint::PROPERTY_HINT_NONE,
35-
GodotString::new(),
36-
)
30+
PropertyInfo {
31+
variant_type: Self::variant_type(),
32+
class_name: Self::class_name(),
33+
property_name: StringName::from(property_name),
34+
hint: global::PropertyHint::PROPERTY_HINT_NONE,
35+
hint_string: GodotString::new(),
36+
usage: global::PropertyUsageFlags::PROPERTY_USAGE_DEFAULT,
37+
}
3738
}
3839

3940
fn param_metadata() -> sys::GDExtensionClassMethodArgumentMetadata {
@@ -52,33 +53,17 @@ impl<T: VariantMetadata> VariantMetadata for Option<T> {
5253
/// Rusty abstraction of sys::GDExtensionPropertyInfo
5354
/// Keeps the actual allocated values (the sys equivalent only keeps pointers, which fall out of scope)
5455
#[derive(Debug)]
56+
// Note: is not #[non_exhaustive], so adding fields is a breaking change. Mostly used internally at the moment though.
5557
pub struct PropertyInfo {
56-
variant_type: VariantType,
57-
class_name: ClassName,
58-
property_name: StringName,
59-
hint: global::PropertyHint,
60-
hint_string: GodotString,
61-
usage: global::PropertyUsageFlags,
58+
pub variant_type: VariantType,
59+
pub class_name: ClassName,
60+
pub property_name: StringName,
61+
pub hint: global::PropertyHint,
62+
pub hint_string: GodotString,
63+
pub usage: global::PropertyUsageFlags,
6264
}
6365

6466
impl PropertyInfo {
65-
pub fn new(
66-
variant_type: VariantType,
67-
class_name: ClassName,
68-
property_name: StringName,
69-
hint: global::PropertyHint,
70-
hint_string: GodotString,
71-
) -> Self {
72-
Self {
73-
variant_type,
74-
class_name,
75-
property_name,
76-
hint,
77-
hint_string,
78-
usage: global::PropertyUsageFlags::PROPERTY_USAGE_DEFAULT,
79-
}
80-
}
81-
8267
/// Converts to the FFI type. Keep this object allocated while using that!
8368
pub fn property_sys(&self) -> sys::GDExtensionPropertyInfo {
8469
use crate::obj::EngineEnum as _;

godot-core/src/builtin/node_path.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,5 +80,7 @@ impl_builtin_traits! {
8080
Default => node_path_construct_default;
8181
Clone => node_path_construct_copy;
8282
Drop => node_path_destroy;
83+
Eq => node_path_operator_equal;
84+
// Ord => node_path_operator_less;
8385
}
8486
}

godot-core/src/builtin/variant/impls.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@
55
*/
66

77
use super::*;
8-
use crate::builtin::meta::VariantMetadata;
8+
use crate::builtin::meta::{PropertyInfo, VariantMetadata};
99
use crate::builtin::*;
1010
use crate::obj::EngineEnum;
1111
use godot_ffi as sys;
1212
use sys::GodotFfi;
13+
use crate::engine::global;
1314

1415
// ----------------------------------------------------------------------------------------------------------------------------------------------
1516
// Macro definitions
@@ -224,6 +225,21 @@ impl VariantMetadata for Variant {
224225
// Arrays use the `NIL` type to indicate that they are untyped.
225226
VariantType::Nil
226227
}
228+
229+
fn property_info(property_name: &str) -> PropertyInfo {
230+
PropertyInfo {
231+
variant_type: Self::variant_type(),
232+
class_name: Self::class_name(),
233+
property_name: StringName::from(property_name),
234+
hint: global::PropertyHint::PROPERTY_HINT_NONE,
235+
hint_string: GodotString::new(),
236+
usage: global::PropertyUsageFlags::PROPERTY_USAGE_NIL_IS_VARIANT,
237+
}
238+
}
239+
240+
fn param_metadata() -> sys::GDExtensionClassMethodArgumentMetadata {
241+
sys::GDEXTENSION_METHOD_ARGUMENT_METADATA_INT_IS_INT8
242+
}
227243
}
228244

229245
impl<T: EngineEnum> ToVariant for T {

godot-macros/src/derive_godot_class.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -287,13 +287,14 @@ fn make_exports_impl(class_name: &Ident, fields: &Fields) -> TokenStream {
287287
use ::godot::builtin::meta::VariantMetadata;
288288

289289
let class_name = ::godot::builtin::StringName::from(#class_name::CLASS_NAME);
290-
let property_info = ::godot::builtin::meta::PropertyInfo::new(
291-
<#field_type>::variant_type(),
292-
::godot::builtin::meta::ClassName::of::<#class_name>(),
293-
::godot::builtin::StringName::from(#name),
294-
::godot::engine::global::PropertyHint::#hint_type,
295-
GodotString::from(#description),
296-
);
290+
let property_info = ::godot::builtin::meta::PropertyInfo {
291+
variant_type: <#field_type>::variant_type(),
292+
class_name: ::godot::builtin::meta::ClassName::of::<#class_name>(),
293+
property_name: ::godot::builtin::StringName::from(#name),
294+
hint: ::godot::engine::global::PropertyHint::#hint_type,
295+
hint_string: GodotString::from(#description),
296+
usage: ::godot::engine::global::PropertyUsageFlags::PROPERTY_USAGE_DEFAULT,
297+
};
297298
let property_info_sys = property_info.property_sys();
298299

299300
let getter_string_name = ::godot::builtin::StringName::from(#getter);

itest/godot/TestSuite.gd

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ func assert_that(what: bool, message: String = "") -> bool:
1515

1616
_assertion_failed = true
1717
if message:
18-
print("assertion failed: %s" % message)
18+
print("GDScript assertion failed: %s" % message)
1919
else:
20-
print("assertion failed")
20+
print("GDScript assertion failed")
2121
return false
2222

2323
func assert_eq(left, right, message: String = "") -> bool:
@@ -26,7 +26,7 @@ func assert_eq(left, right, message: String = "") -> bool:
2626

2727
_assertion_failed = true
2828
if message:
29-
print("assertion failed: %s\n left: %s\n right: %s" % [message, left, right])
29+
print("GDScript assertion failed: %s\n left: %s\n right: %s" % [message, left, right])
3030
else:
31-
print("assertion failed: `(left == right)`\n left: %s\n right: %s" % [left, right])
31+
print("GDScript assertion failed: `(left == right)`\n left: %s\n right: %s" % [left, right])
3232
return false

itest/godot/input/GenFfiTests.template.gd

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,31 @@
44

55
extends TestSuite
66

7+
# Note: GDScript only uses ptrcalls if it has the full type information available at "compile" (parse) time.
8+
# That includes all arguments (including receiver) as well as function signature (parameters + return type).
9+
# Otherwise, GDScript will use varcall. Both are tested below.
10+
# It is thus important that `ffi` is initialized using = for varcalls, and using := for ptrcalls.
11+
712
#(
813
func test_varcall_IDENT():
914
var ffi = GenFfi.new()
1015

11-
var from_rust = ffi.return_IDENT()
12-
assert_that(ffi.accept_IDENT(from_rust))
16+
var from_rust: Variant = ffi.return_IDENT()
17+
assert_that(ffi.accept_IDENT(from_rust), "ffi.accept_IDENT(from_rust)")
18+
19+
var from_gdscript: Variant = VAL
20+
var mirrored: Variant = ffi.mirror_IDENT(from_gdscript)
21+
assert_eq(mirrored, from_gdscript, "mirrored == from_gdscript")
22+
#)
23+
24+
#(
25+
func test_ptrcall_IDENT():
26+
var ffi := GenFfi.new()
27+
28+
var from_rust: TYPE = ffi.return_IDENT()
29+
assert_that(ffi.accept_IDENT(from_rust), "ffi.accept_IDENT(from_rust)")
1330

14-
var from_gdscript = VAL
15-
var mirrored = ffi.mirror_IDENT(from_gdscript)
16-
assert_eq(mirrored, from_gdscript)
31+
var from_gdscript: TYPE = VAL
32+
var mirrored: TYPE = ffi.mirror_IDENT(from_gdscript)
33+
assert_eq(mirrored, from_gdscript, "mirrored == from_gdscript")
1734
#)

itest/rust/build.rs

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,22 +11,33 @@ use std::path::Path;
1111

1212
type IoResult = std::io::Result<()>;
1313

14-
macro_rules! push {
15-
($inputs:ident; $gdscript_ty:ident, $rust_ty:ty, $val:expr) => {
16-
push!($inputs; $gdscript_ty, $rust_ty, $val, $val);
17-
};
18-
19-
($inputs:ident; $gdscript_ty:ident, $rust_ty:ty, $gdscript_val:expr, $rust_val:expr) => {
14+
/// Push with GDScript expr in string
15+
macro_rules! pushs {
16+
($inputs:ident; $GDScriptTy:expr, $RustTy:ty, $gdscript_val:expr, $rust_val:expr) => {
2017
$inputs.push(Input {
21-
ident: stringify!($rust_ty).to_ascii_lowercase(),
22-
gdscript_ty: stringify!($gdscript_ty),
23-
gdscript_val: stringify!($gdscript_val),
24-
rust_ty: quote! { $rust_ty },
18+
ident: stringify!($RustTy)
19+
.to_ascii_lowercase()
20+
.replace("<", "_")
21+
.replace(">", ""),
22+
gdscript_ty: stringify!($GDScriptTy),
23+
gdscript_val: $gdscript_val,
24+
rust_ty: quote! { $RustTy },
2525
rust_val: quote! { $rust_val },
2626
});
2727
};
2828
}
2929

30+
/// Push simple GDScript expression, outside string
31+
macro_rules! push {
32+
($inputs:ident; $GDScriptTy:expr, $RustTy:ty, $val:expr) => {
33+
push!($inputs; $GDScriptTy, $RustTy, $val, $val);
34+
};
35+
36+
($inputs:ident; $GDScriptTy:expr, $RustTy:ty, $gdscript_val:expr, $rust_val:expr) => {
37+
pushs!($inputs; $GDScriptTy, $RustTy, stringify!($gdscript_val), $rust_val);
38+
};
39+
}
40+
3041
// Edit this to change involved types
3142
fn collect_inputs() -> Vec<Input> {
3243
let mut inputs = vec![];
@@ -41,15 +52,34 @@ fn collect_inputs() -> Vec<Input> {
4152
push!(inputs; bool, bool, true);
4253
push!(inputs; Color, Color, Color(0.7, 0.5, 0.3, 0.2), Color::from_rgba(0.7, 0.5, 0.3, 0.2));
4354
push!(inputs; String, GodotString, "hello", "hello".into());
55+
push!(inputs; StringName, StringName, &"hello", "hello".into());
56+
pushs!(inputs; NodePath, NodePath, r#"^"hello""#, "hello".into());
4457
push!(inputs; Vector2, Vector2, Vector2(12.5, -3.5), Vector2::new(12.5, -3.5));
4558
push!(inputs; Vector3, Vector3, Vector3(117.5, 100.0, -323.25), Vector3::new(117.5, 100.0, -323.25));
4659
push!(inputs; Vector4, Vector4, Vector4(-18.5, 24.75, -1.25, 777.875), Vector4::new(-18.5, 24.75, -1.25, 777.875));
4760
push!(inputs; Vector2i, Vector2i, Vector2i(-2147483648, 2147483647), Vector2i::new(-2147483648, 2147483647));
4861
push!(inputs; Vector3i, Vector3i, Vector3i(-1, -2147483648, 2147483647), Vector3i::new(-1, -2147483648, 2147483647));
49-
//push!(inputs; Variant, Variant, 123, 123i64.to_variant());
62+
63+
// Data structures
64+
// TODO enable below, when GDScript has typed array literals, or find a hack with eval/lambdas
65+
/*pushs!(inputs; Array[int], Array<i32>,
66+
"(func() -> Array[int]: [-7, 12, 40])()",
67+
array![-7, 12, 40]
68+
);*/
69+
70+
push!(inputs; Array, VariantArray,
71+
[-7, "godot", false, Vector2i(-77, 88)],
72+
varray![-7, "godot", false, Vector2i::new(-77, 88)]);
73+
74+
pushs!(inputs; Dictionary, Dictionary,
75+
r#"{"key": 83, -3: Vector2(1, 2), 0.03: true}"#,
76+
dict! { "key": 83, (-3): Vector2::new(1.0, 2.0), 0.03: true }
77+
);
78+
5079

5180
// Composite
5281
push!(inputs; int, InstanceId, -1, InstanceId::from_nonzero(0xFFFFFFFFFFFFFFF));
82+
push!(inputs; Variant, Variant, 123, 123i64.to_variant());
5383

5484
inputs
5585
}

0 commit comments

Comments
 (0)