Skip to content

Commit 82a6779

Browse files
committed
Add support for typed arrays
- Rename `Array` to `TypedArray<T>` - Check/set runtime type of the underlying Godot `Array` - Make all parameters and return values `T` instead of `Variant` - Add `Array` as an alias for `TypedArray<Variant>` - Add `array!` macro and use it in tests See #33 for design discussion
1 parent b2f75f8 commit 82a6779

File tree

16 files changed

+930
-456
lines changed

16 files changed

+930
-456
lines changed

godot-codegen/src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,8 @@ const SELECTED_CLASSES: &[&str] = &[
270270
"Control",
271271
"FileAccess",
272272
"HTTPRequest",
273+
"Image",
274+
"ImageTextureLayered",
273275
"Input",
274276
"Label",
275277
"MainLoop",
@@ -290,6 +292,9 @@ const SELECTED_CLASSES: &[&str] = &[
290292
"SceneTree",
291293
"Sprite2D",
292294
"SpriteFrames",
295+
"Texture",
296+
"Texture2DArray",
297+
"TextureLayered",
293298
"Time",
294299
"Timer",
295300
];

godot-core/src/builtin/arrays.rs renamed to godot-core/src/builtin/array.rs

Lines changed: 527 additions & 307 deletions
Large diffs are not rendered by default.

godot-core/src/builtin/macros.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,9 +108,13 @@ macro_rules! impl_builtin_traits_inner {
108108
}
109109
};
110110

111+
// TODO remove; use godot-core/src/builtin/variant/impls.rs instead (this one is only used for Callable)
111112
( FromVariant for $Type:ty => $gd_method:ident ) => {
112113
impl $crate::builtin::variant::FromVariant for $Type {
113114
fn try_from_variant(variant: &$crate::builtin::Variant) -> Result<Self, $crate::builtin::variant::VariantConversionError> {
115+
if variant.get_type() != <Self as $crate::builtin::meta::VariantMetadata>::variant_type() {
116+
return Err($crate::builtin::variant::VariantConversionError)
117+
}
114118
let result = unsafe {
115119
Self::from_sys_init(|self_ptr| {
116120
let converter = sys::builtin_fn!($gd_method);

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ pub struct ClassName {
1919
}
2020

2121
impl ClassName {
22-
pub fn new<T: GodotClass>() -> Self {
22+
pub fn of<T: GodotClass>() -> Self {
2323
Self {
2424
backing: StringName::from(T::CLASS_NAME),
2525
}
@@ -36,6 +36,12 @@ impl ClassName {
3636
}
3737
}
3838

39+
impl From<ClassName> for StringName {
40+
fn from(class_name: ClassName) -> Self {
41+
class_name.backing
42+
}
43+
}
44+
3945
impl Display for ClassName {
4046
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
4147
self.backing.fmt(f)

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,14 @@ use godot_ffi as sys;
2222
pub trait VariantMetadata {
2323
fn variant_type() -> VariantType;
2424

25+
fn class_name() -> ClassName {
26+
ClassName::of::<()>() // FIXME Option or so
27+
}
28+
2529
fn property_info(property_name: &str) -> PropertyInfo {
2630
PropertyInfo::new(
2731
Self::variant_type(),
28-
ClassName::new::<()>(), // FIXME Option or so
32+
Self::class_name(),
2933
StringName::from(property_name),
3034
)
3135
}

godot-core/src/builtin/mod.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
mod macros;
3636
mod vector_macros;
3737

38-
mod arrays;
38+
mod array;
3939
mod color;
4040
mod dictionary;
4141
mod math;
@@ -54,9 +54,10 @@ mod vector4i;
5454

5555
pub mod meta;
5656

57-
pub use crate::dict;
57+
// Re-export macros.
58+
pub use crate::{array, dict};
5859

59-
pub use arrays::*;
60+
pub use array::*;
6061
pub use color::*;
6162
pub use dictionary::*;
6263
pub use math::*;

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

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,18 @@ use sys::GodotFfi;
1414
// ----------------------------------------------------------------------------------------------------------------------------------------------
1515
// Macro definitions
1616

17+
macro_rules! impl_variant_metadata {
18+
($T:ty, $variant_type:ident $( ; $($extra:tt)* )?) => {
19+
impl VariantMetadata for $T {
20+
fn variant_type() -> VariantType {
21+
VariantType::$variant_type
22+
}
23+
24+
$($($extra)*)?
25+
}
26+
};
27+
}
28+
1729
macro_rules! impl_variant_traits {
1830
($T:ty, $from_fn:ident, $to_fn:ident, $variant_type:ident) => {
1931
impl_variant_traits!(@@ $T, $from_fn, $to_fn, $variant_type;);
@@ -62,13 +74,7 @@ macro_rules! impl_variant_traits {
6274
}
6375
}
6476

65-
impl VariantMetadata for $T {
66-
fn variant_type() -> VariantType {
67-
VariantType::$variant_type
68-
}
69-
70-
$($extra)*
71-
}
77+
impl_variant_metadata!($T, $variant_type; $($extra)*);
7278
};
7379
}
7480

@@ -144,21 +150,19 @@ mod impls {
144150
impl_variant_traits!(GodotString, string_to_variant, string_from_variant, String);
145151
impl_variant_traits!(StringName, string_name_to_variant, string_name_from_variant, StringName);
146152
impl_variant_traits!(NodePath, node_path_to_variant, node_path_from_variant, NodePath);
147-
/* TODO provide those, as soon as `Default` is available. Also consider auto-generating.
148-
impl_variant_traits!(Rect2, rect2_to_variant, rect2_from_variant, Rect2);
149-
impl_variant_traits!(Rect2i, rect2i_to_variant, rect2i_from_variant, Rect2i);
150-
impl_variant_traits!(Plane, plane_to_variant, plane_from_variant, Plane);
151-
impl_variant_traits!(Quaternion, quaternion_to_variant, quaternion_from_variant, Quaternion);
152-
impl_variant_traits!(Aabb, aabb_to_variant, aabb_from_variant, AABB);
153-
impl_variant_traits!(Basis, basis_to_variant, basis_from_variant, Basis);
154-
impl_variant_traits!(Transform2D, transform_2d_to_variant, transform_2d_from_variant, Transform2D);
155-
impl_variant_traits!(Transform3D, transform_3d_to_variant, transform_3d_from_variant, Transform3D);
156-
impl_variant_traits!(Projection, projection_to_variant, projection_from_variant, Projection);
157-
impl_variant_traits!(Rid, rid_to_variant, rid_from_variant, RID);
158-
impl_variant_traits!(Callable, callable_to_variant, callable_from_variant, Callable);
159-
impl_variant_traits!(Signal, signal_to_variant, signal_from_variant, Signal);
160-
*/
161-
impl_variant_traits!(Array, array_to_variant, array_from_variant, Array);
153+
// TODO use impl_variant_traits!, as soon as `Default` is available. Also consider auto-generating.
154+
impl_variant_metadata!(Rect2, /* rect2_to_variant, rect2_from_variant, */ Rect2);
155+
impl_variant_metadata!(Rect2i, /* rect2i_to_variant, rect2i_from_variant, */ Rect2i);
156+
impl_variant_metadata!(Plane, /* plane_to_variant, plane_from_variant, */ Plane);
157+
impl_variant_metadata!(Quaternion, /* quaternion_to_variant, quaternion_from_variant, */ Quaternion);
158+
impl_variant_metadata!(Aabb, /* aabb_to_variant, aabb_from_variant, */ Aabb);
159+
impl_variant_metadata!(Basis, /* basis_to_variant, basis_from_variant, */ Basis);
160+
impl_variant_metadata!(Transform2D, /* transform_2d_to_variant, transform_2d_from_variant, */ Transform2D);
161+
impl_variant_metadata!(Transform3D, /* transform_3d_to_variant, transform_3d_from_variant, */ Transform3D);
162+
impl_variant_metadata!(Projection, /* projection_to_variant, projection_from_variant, */ Projection);
163+
impl_variant_metadata!(Rid, /* rid_to_variant, rid_from_variant, */ Rid);
164+
impl_variant_metadata!(Callable, /* callable_to_variant, callable_from_variant, */ Callable);
165+
impl_variant_metadata!(Signal, /* signal_to_variant, signal_from_variant, */ Signal);
162166
impl_variant_traits!(PackedByteArray, packed_byte_array_to_variant, packed_byte_array_from_variant, PackedByteArray);
163167
impl_variant_traits!(PackedInt32Array, packed_int32_array_to_variant, packed_int32_array_from_variant, PackedInt32Array);
164168
impl_variant_traits!(PackedInt64Array, packed_int64_array_to_variant, packed_int64_array_from_variant, PackedInt64Array);
@@ -215,7 +219,8 @@ impl FromVariant for Variant {
215219
// Variant itself
216220
impl VariantMetadata for Variant {
217221
fn variant_type() -> VariantType {
218-
VariantType::Nil // FIXME is this correct? what else to use? is this called at all?
222+
// Arrays use the `NIL` type to indicate that they are untyped.
223+
VariantType::Nil
219224
}
220225
}
221226

godot-core/src/obj/gd.rs

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ use godot_ffi::VariantType;
1414
use sys::types::OpaqueObject;
1515
use sys::{ffi_methods, interface_fn, static_assert_eq_size, GodotFfi};
1616

17-
use crate::builtin::meta::{ClassName, PropertyInfo, VariantMetadata};
18-
use crate::builtin::{FromVariant, StringName, ToVariant, Variant, VariantConversionError};
17+
use crate::builtin::meta::{ClassName, VariantMetadata};
18+
use crate::builtin::{FromVariant, ToVariant, Variant, VariantConversionError};
1919
use crate::obj::dom::Domain as _;
2020
use crate::obj::mem::Memory as _;
2121
use crate::obj::{cap, dom, mem, GodotClass, Inherits, Share};
@@ -332,7 +332,7 @@ impl<T: GodotClass> Gd<T> {
332332
where
333333
U: GodotClass,
334334
{
335-
let class_name = ClassName::new::<U>();
335+
let class_name = ClassName::of::<U>();
336336
let class_tag = interface_fn!(classdb_get_class_tag)(class_name.string_sys());
337337
let cast_object_ptr = interface_fn!(object_cast_to)(self.obj_sys(), class_tag);
338338

@@ -631,11 +631,7 @@ impl<T: GodotClass> VariantMetadata for Gd<T> {
631631
VariantType::Object
632632
}
633633

634-
fn property_info(property_name: &str) -> PropertyInfo {
635-
PropertyInfo::new(
636-
Self::variant_type(),
637-
ClassName::new::<T>(),
638-
StringName::from(property_name),
639-
)
634+
fn class_name() -> ClassName {
635+
ClassName::of::<T>()
640636
}
641637
}

godot-core/src/registry.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ pub fn register_class<T: GodotExt + cap::GodotInit + cap::ImplementsGodotExt>()
117117
// TODO: provide overloads with only some trait impls
118118

119119
out!("Manually register class {}", std::any::type_name::<T>());
120-
let class_name = ClassName::new::<T>();
120+
let class_name = ClassName::of::<T>();
121121

122122
let godot_params = sys::GDExtensionClassCreationInfo {
123123
to_string_func: Some(callbacks::to_string::<T>),
@@ -133,7 +133,7 @@ pub fn register_class<T: GodotExt + cap::GodotInit + cap::ImplementsGodotExt>()
133133

134134
register_class_raw(ClassRegistrationInfo {
135135
class_name,
136-
parent_class_name: Some(ClassName::new::<T::Base>()),
136+
parent_class_name: Some(ClassName::of::<T::Base>()),
137137
generated_register_fn: None,
138138
user_register_fn: Some(ErasedRegisterFn {
139139
raw: callbacks::register_class_by_builder::<T>,
@@ -287,8 +287,8 @@ pub mod callbacks {
287287
T: GodotClass,
288288
F: FnOnce(Base<T::Base>) -> T,
289289
{
290-
let class_name = ClassName::new::<T>();
291-
let base_class_name = ClassName::new::<T::Base>();
290+
let class_name = ClassName::of::<T>();
291+
let base_class_name = ClassName::of::<T::Base>();
292292

293293
//out!("create callback: {}", class_name.backing);
294294

godot-macros/src/derive_godot_class.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,7 @@ fn make_exports_impl(class_name: &Ident, fields: &Fields) -> TokenStream {
325325
let class_name = ::godot::builtin::StringName::from(#class_name::CLASS_NAME);
326326
let property_info = ::godot::builtin::meta::PropertyInfo::new(
327327
#variant_type,
328-
::godot::builtin::meta::ClassName::new::<#class_name>(),
328+
::godot::builtin::meta::ClassName::of::<#class_name>(),
329329
::godot::builtin::StringName::from(#name),
330330
);
331331
let property_info_sys = property_info.property_sys();

godot/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,8 @@ pub use godot_core::private;
127127
/// Often-imported symbols.
128128
pub mod prelude {
129129
pub use super::bind::{godot_api, GodotClass, GodotExt};
130-
pub use super::builtin::dict; // Re-export macros.
131130
pub use super::builtin::*;
131+
pub use super::builtin::{array, dict}; // Re-export macros.
132132
pub use super::engine::{
133133
load, try_load, utilities, AudioStreamPlayer, Camera2D, Camera3D, Input, Node, Node2D,
134134
Node3D, Object, PackedScene, RefCounted, Resource, SceneTree,

itest/godot/ManualFfiTests.gd

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,23 @@ func test_export():
3838

3939
obj.free()
4040
node.free()
41+
42+
func test_untyped_array_pass_to_user_func():
43+
var obj = ArrayTest.new()
44+
var array: Array = [42, "answer"]
45+
assert_eq(obj.pass_untyped_array(array), 2)
46+
47+
func test_untyped_array_return_from_user_func():
48+
var obj = ArrayTest.new()
49+
var array: Array = obj.return_untyped_array()
50+
assert_eq(array, [42, "answer"])
51+
52+
func test_typed_array_pass_to_user_func():
53+
var obj = ArrayTest.new()
54+
var array: Array[int] = [1, 2, 3]
55+
assert_eq(obj.pass_typed_array(array), 6)
56+
57+
func test_typed_array_return_from_user_func():
58+
var obj = ArrayTest.new()
59+
var array: Array[int] = obj.return_typed_array(3)
60+
assert_eq(array, [1, 2, 3])

itest/godot/TestRunner.gd

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ class _Test:
6969
return ok
7070

7171
static func _suite_name(suite: Object) -> String:
72-
var script := suite.get_script()
72+
var script: Script = suite.get_script()
7373
if script:
7474
# Test suite written in GDScript.
7575
return script.resource_path.get_file().get_basename()

0 commit comments

Comments
 (0)