Skip to content

Commit 9a703d2

Browse files
bors[bot]toasteaterBromeon
authored
Merge #708 #710
708: Method converting Variants to primitives by type r=toasteater a=toasteater Adds `Variant::dispatch`, a method that converts the variant to a primitive value depending on its type, and returns that result as a Rust enum the user can then conveniently `match` on. 710: TypedArray: mention use cases and limitations in doc r=toasteater a=Bromeon Adds a short paragraph to the `TypedArray` documentation: ![grafik](https://user-images.githubusercontent.com/708488/111084207-7d6a7880-8511-11eb-8167-d7ab26459fc1.png) Co-authored-by: toasteater <48371905+toasteater@users.noreply.github.com> Co-authored-by: Jan Haller <bromeon@gmail.com>
3 parents 7de34a0 + 42db695 + 083393e commit 9a703d2

File tree

4 files changed

+133
-32
lines changed

4 files changed

+133
-32
lines changed

gdnative-core/src/core_types/typed_array.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@ use crate::NewRef;
1414
/// A reference-counted CoW typed vector using Godot's pool allocator, generic over possible
1515
/// element types.
1616
///
17+
/// `TypedArray` unifies all the different `Pool*Array` types exported by Godot. It can be used
18+
/// in exported Rust methods as parameter and return types, as well as in exported properties.
19+
/// However, it is limited to the element types, for which a `Pool*Array` exists in GDScript,
20+
/// i.e. it cannot contain user-defined types.
21+
/// If you need other types, look into [`VariantArray`](struct.VariantArray.html) or directly use
22+
/// `Vec<T>` for type safety.
23+
///
1724
/// This type is CoW. The `Clone` implementation of this type creates a new reference without
1825
/// copying the contents.
1926
///

gdnative-core/src/core_types/variant.rs

Lines changed: 123 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -84,38 +84,89 @@ macro_rules! variant_to_type_from_sys {
8484
)
8585
}
8686

87-
#[repr(u32)]
88-
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
89-
pub enum VariantType {
90-
Nil = sys::godot_variant_type_GODOT_VARIANT_TYPE_NIL as u32,
91-
Bool = sys::godot_variant_type_GODOT_VARIANT_TYPE_BOOL as u32,
92-
I64 = sys::godot_variant_type_GODOT_VARIANT_TYPE_INT as u32,
93-
F64 = sys::godot_variant_type_GODOT_VARIANT_TYPE_REAL as u32,
94-
GodotString = sys::godot_variant_type_GODOT_VARIANT_TYPE_STRING as u32,
95-
Vector2 = sys::godot_variant_type_GODOT_VARIANT_TYPE_VECTOR2 as u32,
96-
Rect2 = sys::godot_variant_type_GODOT_VARIANT_TYPE_RECT2 as u32,
97-
Vector3 = sys::godot_variant_type_GODOT_VARIANT_TYPE_VECTOR3 as u32,
98-
Transform2D = sys::godot_variant_type_GODOT_VARIANT_TYPE_TRANSFORM2D as u32,
99-
Plane = sys::godot_variant_type_GODOT_VARIANT_TYPE_PLANE as u32,
100-
Quat = sys::godot_variant_type_GODOT_VARIANT_TYPE_QUAT as u32,
101-
Aabb = sys::godot_variant_type_GODOT_VARIANT_TYPE_AABB as u32,
102-
Basis = sys::godot_variant_type_GODOT_VARIANT_TYPE_BASIS as u32,
103-
Transform = sys::godot_variant_type_GODOT_VARIANT_TYPE_TRANSFORM as u32,
104-
Color = sys::godot_variant_type_GODOT_VARIANT_TYPE_COLOR as u32,
105-
NodePath = sys::godot_variant_type_GODOT_VARIANT_TYPE_NODE_PATH as u32,
106-
Rid = sys::godot_variant_type_GODOT_VARIANT_TYPE_RID as u32,
107-
Object = sys::godot_variant_type_GODOT_VARIANT_TYPE_OBJECT as u32,
108-
Dictionary = sys::godot_variant_type_GODOT_VARIANT_TYPE_DICTIONARY as u32,
109-
VariantArray = sys::godot_variant_type_GODOT_VARIANT_TYPE_ARRAY as u32,
110-
ByteArray = sys::godot_variant_type_GODOT_VARIANT_TYPE_POOL_BYTE_ARRAY as u32,
111-
Int32Array = sys::godot_variant_type_GODOT_VARIANT_TYPE_POOL_INT_ARRAY as u32,
112-
Float32Array = sys::godot_variant_type_GODOT_VARIANT_TYPE_POOL_REAL_ARRAY as u32,
113-
StringArray = sys::godot_variant_type_GODOT_VARIANT_TYPE_POOL_STRING_ARRAY as u32,
114-
Vector2Array = sys::godot_variant_type_GODOT_VARIANT_TYPE_POOL_VECTOR2_ARRAY as u32,
115-
Vector3Array = sys::godot_variant_type_GODOT_VARIANT_TYPE_POOL_VECTOR3_ARRAY as u32,
116-
ColorArray = sys::godot_variant_type_GODOT_VARIANT_TYPE_POOL_COLOR_ARRAY as u32,
87+
macro_rules! variant_dispatch_arm {
88+
($v:expr, $variant:ident ( $inner:ty )) => {
89+
VariantDispatch::$variant(<$inner>::from_variant($v).unwrap())
90+
};
91+
($v:expr, $variant:ident) => {
92+
VariantDispatch::$variant
93+
};
11794
}
11895

96+
macro_rules! decl_variant_type {
97+
(
98+
pub enum VariantType, VariantDispatch {
99+
$(
100+
$variant:ident $( ($inner:ty) )? = $c_const:path,
101+
)*
102+
}
103+
) => {
104+
#[repr(u32)]
105+
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
106+
pub enum VariantType {
107+
$(
108+
$variant = $c_const as u32,
109+
)*
110+
}
111+
112+
/// Rust enum associating each primitive variant type to its value.
113+
///
114+
/// For `Variant`s containing objects, the original `Variant` is returned unchanged, due to
115+
/// the limitations of statically-determined memory management.
116+
#[repr(u32)]
117+
pub enum VariantDispatch {
118+
$(
119+
$variant $( ($inner) )?,
120+
)*
121+
}
122+
123+
impl<'a> From<&'a Variant> for VariantDispatch {
124+
#[inline]
125+
fn from(v: &'a Variant) -> Self {
126+
match v.get_type() {
127+
$(
128+
VariantType::$variant => {
129+
variant_dispatch_arm!(v, $variant $( ($inner) )?)
130+
},
131+
)*
132+
}
133+
}
134+
}
135+
}
136+
}
137+
138+
decl_variant_type!(
139+
pub enum VariantType, VariantDispatch {
140+
Nil = sys::godot_variant_type_GODOT_VARIANT_TYPE_NIL,
141+
Bool(bool) = sys::godot_variant_type_GODOT_VARIANT_TYPE_BOOL,
142+
I64(i64) = sys::godot_variant_type_GODOT_VARIANT_TYPE_INT,
143+
F64(f64) = sys::godot_variant_type_GODOT_VARIANT_TYPE_REAL,
144+
GodotString(GodotString) = sys::godot_variant_type_GODOT_VARIANT_TYPE_STRING,
145+
Vector2(Vector2) = sys::godot_variant_type_GODOT_VARIANT_TYPE_VECTOR2,
146+
Rect2(Rect2) = sys::godot_variant_type_GODOT_VARIANT_TYPE_RECT2,
147+
Vector3(Vector3) = sys::godot_variant_type_GODOT_VARIANT_TYPE_VECTOR3,
148+
Transform2D(Transform2D) = sys::godot_variant_type_GODOT_VARIANT_TYPE_TRANSFORM2D,
149+
Plane(Plane) = sys::godot_variant_type_GODOT_VARIANT_TYPE_PLANE,
150+
Quat(Quat) = sys::godot_variant_type_GODOT_VARIANT_TYPE_QUAT,
151+
Aabb(Aabb) = sys::godot_variant_type_GODOT_VARIANT_TYPE_AABB,
152+
Basis(Basis) = sys::godot_variant_type_GODOT_VARIANT_TYPE_BASIS,
153+
Transform(Transform) = sys::godot_variant_type_GODOT_VARIANT_TYPE_TRANSFORM,
154+
Color(Color) = sys::godot_variant_type_GODOT_VARIANT_TYPE_COLOR,
155+
NodePath(NodePath) = sys::godot_variant_type_GODOT_VARIANT_TYPE_NODE_PATH,
156+
Rid(Rid) = sys::godot_variant_type_GODOT_VARIANT_TYPE_RID,
157+
Object(Variant) = sys::godot_variant_type_GODOT_VARIANT_TYPE_OBJECT,
158+
Dictionary(Dictionary) = sys::godot_variant_type_GODOT_VARIANT_TYPE_DICTIONARY,
159+
VariantArray(VariantArray) = sys::godot_variant_type_GODOT_VARIANT_TYPE_ARRAY,
160+
ByteArray(ByteArray) = sys::godot_variant_type_GODOT_VARIANT_TYPE_POOL_BYTE_ARRAY,
161+
Int32Array(Int32Array) = sys::godot_variant_type_GODOT_VARIANT_TYPE_POOL_INT_ARRAY,
162+
Float32Array(Float32Array) = sys::godot_variant_type_GODOT_VARIANT_TYPE_POOL_REAL_ARRAY,
163+
StringArray(StringArray) = sys::godot_variant_type_GODOT_VARIANT_TYPE_POOL_STRING_ARRAY,
164+
Vector2Array(Vector2Array) = sys::godot_variant_type_GODOT_VARIANT_TYPE_POOL_VECTOR2_ARRAY,
165+
Vector3Array(Vector3Array) = sys::godot_variant_type_GODOT_VARIANT_TYPE_POOL_VECTOR3_ARRAY,
166+
ColorArray(ColorArray) = sys::godot_variant_type_GODOT_VARIANT_TYPE_POOL_COLOR_ARRAY,
167+
}
168+
);
169+
119170
impl VariantType {
120171
#[doc(hidden)]
121172
#[inline]
@@ -674,6 +725,24 @@ impl Variant {
674725
unsafe { VariantType::from_sys((get_api().godot_variant_get_type)(&self.0)) }
675726
}
676727

728+
/// Converts this variant to a primitive value depending on its type.
729+
///
730+
/// # Examples
731+
///
732+
/// ```ignore
733+
/// let variant = 42.to_variant();
734+
/// let number_as_float = match variant.dispatch() {
735+
/// VariantDispatch::I64(i) => i as f64,
736+
/// VariantDispatch::F64(f) => f,
737+
/// _ => panic!("not a number"),
738+
/// };
739+
/// approx::assert_relative_eq!(42.0, number_as_float);
740+
/// ```
741+
#[inline]
742+
pub fn dispatch(&self) -> VariantDispatch {
743+
self.into()
744+
}
745+
677746
/// Returns true if this is an empty variant.
678747
#[inline]
679748
pub fn is_nil(&self) -> bool {
@@ -1928,4 +1997,28 @@ godot_test!(
19281997
let tuple = <(i64, i64)>::from_variant(&variant);
19291998
assert_eq!(Ok((42, 54)), tuple);
19301999
}
2000+
2001+
test_variant_dispatch {
2002+
let variant = 42i64.to_variant();
2003+
if let VariantDispatch::I64(i) = variant.dispatch() {
2004+
assert_eq!(42, i);
2005+
} else {
2006+
panic!("incorrect dispatch type");
2007+
};
2008+
2009+
let variant = true.to_variant();
2010+
if let VariantDispatch::Bool(b) = variant.dispatch() {
2011+
assert!(b);
2012+
} else {
2013+
panic!("incorrect dispatch type");
2014+
};
2015+
2016+
let variant = 42.to_variant();
2017+
let number_as_float = match variant.dispatch() {
2018+
VariantDispatch::I64(i) => i as f64,
2019+
VariantDispatch::F64(f) => f,
2020+
_ => panic!("not a number"),
2021+
};
2022+
approx::assert_relative_eq!(42.0, number_as_float);
2023+
}
19312024
);

gdnative/src/prelude.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ pub use gdnative_core::core_types::{
22
self, error::GodotError, Aabb, Angle, Basis, ByteArray, Color, ColorArray, Dictionary,
33
Float32Array, GodotString, Int32Array, NodePath, Plane, Point2, Point3, Quat, Rect2, Rid,
44
Rotation2D, Rotation3D, Size2, StringArray, StringName, Transform, Transform2D, TypedArray,
5-
Variant, VariantArray, VariantOperator, VariantType, Vector2, Vector2Array, Vector3,
6-
Vector3Array,
5+
Variant, VariantArray, VariantDispatch, VariantOperator, VariantType, Vector2, Vector2Array,
6+
Vector3, Vector3Array,
77
};
88
pub use gdnative_core::core_types::{
99
FromVariant, FromVariantError, OwnedToVariant, ToVariant, ToVariantEq, Vector2Godot,

test/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ pub extern "C" fn run_tests(
3939
status &= gdnative::core_types::test_variant_result();
4040
status &= gdnative::core_types::test_to_variant_iter();
4141
status &= gdnative::core_types::test_variant_tuple();
42+
status &= gdnative::core_types::test_variant_dispatch();
4243

4344
status &= gdnative::core_types::test_byte_array_access();
4445
status &= gdnative::core_types::test_byte_array_debug();

0 commit comments

Comments
 (0)