Skip to content

Commit 25d51d3

Browse files
committed
add serde behind feature flag for some builtins
1 parent e27a69e commit 25d51d3

19 files changed

+180
-0
lines changed

godot-core/Cargo.toml

+2
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,12 @@ godot-ffi = { path = "../godot-ffi" }
2121

2222
# See https://docs.rs/glam/latest/glam/index.html#feature-gates
2323
glam = { version = "0.23", features = ["debug-glam-assert"] }
24+
serde = { version = "1", features = ["derive"], optional = true }
2425

2526
# Reverse dev dependencies so doctests can use `godot::` prefix
2627
[dev-dependencies]
2728
godot = { path = "../godot" }
29+
serde_json = "1.0"
2830

2931
[build-dependencies]
3032
godot-codegen = { path = "../godot-codegen" }

godot-core/src/builtin/aabb.rs

+13
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use super::Vector3;
1818
///
1919
/// The 2D counterpart to `Aabb` is [`Rect2`](super::Rect2).
2020
#[derive(Default, Copy, Clone, PartialEq, Debug)]
21+
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
2122
#[repr(C)]
2223
pub struct Aabb {
2324
pub position: Vector3,
@@ -101,3 +102,15 @@ impl std::fmt::Display for Aabb {
101102
unsafe impl GodotFfi for Aabb {
102103
ffi_methods! { type sys::GDExtensionTypePtr = *mut Self; .. }
103104
}
105+
106+
#[cfg(test)]
107+
mod test {
108+
#[cfg(feature = "serde")]
109+
#[test]
110+
fn serde_roundtrip() {
111+
let rect = super::Aabb::default();
112+
let expected_json = "{\"position\":{\"x\":0.0,\"y\":0.0,\"z\":0.0},\"size\":{\"x\":0.0,\"y\":0.0,\"z\":0.0}}";
113+
114+
crate::builtin::test_utils::roundtrip(&rect, expected_json);
115+
}
116+
}

godot-core/src/builtin/basis.rs

+10
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ use super::{real, RMat3, RQuat, RVec2, RVec3};
2323
/// The basis vectors are the columns of the matrix, whereas the [`rows`](Self::rows) field represents
2424
/// the row vectors.
2525
#[derive(Copy, Clone, PartialEq, Debug)]
26+
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
2627
#[repr(C)]
2728
pub struct Basis {
2829
/// The rows of the matrix. These are *not* the basis vectors.
@@ -835,4 +836,13 @@ mod test {
835836
"Basis with three components infinite should not be finite."
836837
);
837838
}
839+
840+
#[cfg(feature = "serde")]
841+
#[test]
842+
fn serde_roundtrip() {
843+
let rect = Basis::IDENTITY;
844+
let expected_json = "{\"rows\":[{\"x\":1.0,\"y\":0.0,\"z\":0.0},{\"x\":0.0,\"y\":1.0,\"z\":0.0},{\"x\":0.0,\"y\":0.0,\"z\":1.0}]}";
845+
846+
crate::builtin::test_utils::roundtrip(&rect, expected_json);
847+
}
838848
}

godot-core/src/builtin/color.rs

+13
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use sys::{ffi_methods, GodotFfi};
1616
/// values outside this range are explicitly allowed for e.g. High Dynamic Range (HDR).
1717
#[repr(C)]
1818
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
19+
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1920
pub struct Color {
2021
/// The color's red component.
2122
pub r: f32,
@@ -511,3 +512,15 @@ impl std::fmt::Display for Color {
511512
write!(f, "({}, {}, {}, {})", self.r, self.g, self.b, self.a)
512513
}
513514
}
515+
516+
#[cfg(test)]
517+
mod test {
518+
#[cfg(feature = "serde")]
519+
#[test]
520+
fn serde_roundtrip() {
521+
let rect = super::Color::WHITE;
522+
let expected_json = "{\"r\":1.0,\"g\":1.0,\"b\":1.0,\"a\":1.0}";
523+
524+
crate::builtin::test_utils::roundtrip(&rect, expected_json);
525+
}
526+
}

godot-core/src/builtin/mod.rs

+20
Original file line numberDiff line numberDiff line change
@@ -407,3 +407,23 @@ mod export {
407407
// TODO investigate whether Signal should impl Export at all, and if so, how
408408
// impl_export_by_clone!(Signal);
409409
}
410+
411+
#[cfg(all(test, feature = "serde"))]
412+
pub(crate) mod test_utils {
413+
use serde::{Deserialize, Serialize};
414+
415+
pub(crate) fn roundtrip<T>(value: &T, expected_json: &str)
416+
where
417+
T: for<'a> Deserialize<'a> + Serialize + PartialEq + std::fmt::Debug,
418+
{
419+
// pseudo-code
420+
let json: String = serde_json::to_string(value).unwrap();
421+
let back: T = serde_json::from_str(json.as_str()).unwrap();
422+
423+
assert_eq!(back, *value, "serde round-trip changes value");
424+
assert_eq!(
425+
json, expected_json,
426+
"value does not conform to expected JSON"
427+
);
428+
}
429+
}

godot-core/src/builtin/plane.rs

+13
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ use super::{is_equal_approx, real, Vector3};
2323
/// unit length and will panic if this invariant is violated. This is not separately
2424
/// annotated for each method.
2525
#[derive(Copy, Clone, PartialEq, Debug)]
26+
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
2627
#[repr(C)]
2728
pub struct Plane {
2829
pub normal: Vector3,
@@ -189,4 +190,16 @@ mod test {
189190
Vector3::new(0.0, 0.0, 2.0),
190191
);
191192
}
193+
194+
#[cfg(feature = "serde")]
195+
#[test]
196+
fn serde_roundtrip() {
197+
let rect = Plane {
198+
normal: Vector3::ONE,
199+
d: 0.0,
200+
};
201+
let expected_json = "{\"normal\":{\"x\":1.0,\"y\":1.0,\"z\":1.0},\"d\":0.0}";
202+
203+
crate::builtin::test_utils::roundtrip(&rect, expected_json);
204+
}
192205
}

godot-core/src/builtin/projection.rs

+10
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ use super::{real, RMat4, RealConv};
2525
/// Note: The current implementation largely makes calls to godot for its
2626
/// methods and as such are not as performant as other types.
2727
#[derive(Copy, Clone, PartialEq, Debug)]
28+
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
2829
#[repr(C)]
2930
pub struct Projection {
3031
/// The columns of the projection matrix.
@@ -960,6 +961,15 @@ mod test {
960961
}
961962
}
962963
}
964+
965+
#[cfg(feature = "serde")]
966+
#[test]
967+
fn serde_roundtrip() {
968+
let rect = Projection::IDENTITY;
969+
let expected_json = "{\"cols\":[{\"x\":1.0,\"y\":0.0,\"z\":0.0,\"w\":0.0},{\"x\":0.0,\"y\":1.0,\"z\":0.0,\"w\":0.0},{\"x\":0.0,\"y\":0.0,\"z\":1.0,\"w\":0.0},{\"x\":0.0,\"y\":0.0,\"z\":0.0,\"w\":1.0}]}";
970+
971+
crate::builtin::test_utils::roundtrip(&rect, expected_json);
972+
}
963973
}
964974

965975
impl std::fmt::Display for Projection {

godot-core/src/builtin/quaternion.rs

+13
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use super::{real, RQuat};
1515
use super::{Basis, EulerOrder};
1616

1717
#[derive(Copy, Clone, PartialEq, Debug)]
18+
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1819
#[repr(C)]
1920
pub struct Quaternion {
2021
pub x: real,
@@ -347,3 +348,15 @@ impl Neg for Quaternion {
347348
Self::new(-self.x, -self.y, -self.z, -self.w)
348349
}
349350
}
351+
352+
#[cfg(test)]
353+
mod test {
354+
#[cfg(feature = "serde")]
355+
#[test]
356+
fn serde_roundtrip() {
357+
let rect = super::Quaternion::new(1.0, 1.0, 1.0, 1.0);
358+
let expected_json = "{\"x\":1.0,\"y\":1.0,\"z\":1.0,\"w\":1.0}";
359+
360+
crate::builtin::test_utils::roundtrip(&rect, expected_json);
361+
}
362+
}

godot-core/src/builtin/rect2.rs

+13
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use super::{real, Rect2i, Vector2};
1818
///
1919
/// The 3D counterpart to `Rect2` is [`Aabb`](super::Aabb).
2020
#[derive(Default, Copy, Clone, PartialEq, Debug)]
21+
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
2122
#[repr(C)]
2223
pub struct Rect2 {
2324
pub position: Vector2,
@@ -125,3 +126,15 @@ impl std::fmt::Display for Rect2 {
125126
write!(f, "[P: {}, S: {}]", self.position, self.size)
126127
}
127128
}
129+
130+
#[cfg(test)]
131+
mod test {
132+
#[cfg(feature = "serde")]
133+
#[test]
134+
fn serde_roundtrip() {
135+
let rect = super::Rect2::default();
136+
let expected_json = "{\"position\":{\"x\":0.0,\"y\":0.0},\"size\":{\"x\":0.0,\"y\":0.0}}";
137+
138+
crate::builtin::test_utils::roundtrip(&rect, expected_json);
139+
}
140+
}

godot-core/src/builtin/rect2i.rs

+10
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use super::{Rect2, RectSide, Vector2i};
1515
/// `Rect2i` consists of a position, a size, and several utility functions. It is typically used for
1616
/// fast overlap tests.
1717
#[derive(Default, Copy, Clone, Eq, PartialEq, Debug)]
18+
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1819
#[repr(C)]
1920
pub struct Rect2i {
2021
/// The position of the rectangle.
@@ -583,4 +584,13 @@ mod test {
583584
let rect = Rect2i::from_components(0, 0, -5, -5);
584585
Rect2i::default().merge(rect);
585586
}
587+
588+
#[cfg(feature = "serde")]
589+
#[test]
590+
fn serde_roundtrip() {
591+
let rect = Rect2i::default();
592+
let expected_json = "{\"position\":{\"x\":0,\"y\":0},\"size\":{\"x\":0,\"y\":0}}";
593+
594+
crate::builtin::test_utils::roundtrip(&rect, expected_json);
595+
}
586596
}

godot-core/src/builtin/transform2d.rs

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ use super::{real, RAffine2, RMat2};
2727
///
2828
/// For methods that don't take translation into account, see [`Basis2D`].
2929
#[derive(Default, Copy, Clone, PartialEq, Debug)]
30+
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
3031
#[repr(C)]
3132
pub struct Transform2D {
3233
/// The first basis vector.

godot-core/src/builtin/transform3d.rs

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ use super::{Aabb, Basis, Plane, Projection, Vector3};
2424
/// [ a.z b.z c.z o.z ]
2525
/// ```
2626
#[derive(Default, Copy, Clone, PartialEq, Debug)]
27+
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
2728
#[repr(C)]
2829
pub struct Transform3D {
2930
/// The basis is a matrix containing 3 vectors as its columns. They can be

godot-core/src/builtin/vector2.rs

+10
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ use super::{real, RAffine2, RVec2};
2727
///
2828
/// See [`Vector2i`] for its integer counterpart.
2929
#[derive(Debug, Default, Clone, Copy, PartialEq)]
30+
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
3031
#[repr(C)]
3132
pub struct Vector2 {
3233
/// The vector's X component.
@@ -369,4 +370,13 @@ mod test {
369370
Vector2::is_equal_approx
370371
);
371372
}
373+
374+
#[cfg(feature = "serde")]
375+
#[test]
376+
fn serde_roundtrip() {
377+
let rect = Vector2::default();
378+
let expected_json = "{\"x\":0.0,\"y\":0.0}";
379+
380+
crate::builtin::test_utils::roundtrip(&rect, expected_json);
381+
}
372382
}

godot-core/src/builtin/vector2i.rs

+10
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ use super::IVec2;
2424
/// configured with an engine build option. Use `i64` or [`PackedInt64Array`] if 64-bit values are
2525
/// needed.
2626
#[derive(Debug, Default, Clone, Copy, Eq, Ord, PartialEq, PartialOrd)]
27+
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
2728
#[repr(C)]
2829
pub struct Vector2i {
2930
/// The vector's X component.
@@ -140,4 +141,13 @@ mod test {
140141
assert_eq!(a.coord_min(b), Vector2i::new(0, 3));
141142
assert_eq!(a.coord_max(b), Vector2i::new(1, 5));
142143
}
144+
145+
#[cfg(feature = "serde")]
146+
#[test]
147+
fn serde_roundtrip() {
148+
let rect = Vector2i::default();
149+
let expected_json = "{\"x\":0,\"y\":0}";
150+
151+
crate::builtin::test_utils::roundtrip(&rect, expected_json);
152+
}
143153
}

godot-core/src/builtin/vector3.rs

+10
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ use super::{real, Basis, RVec3};
2828
///
2929
/// See [`Vector3i`] for its integer counterpart.
3030
#[derive(Debug, Default, Clone, Copy, PartialEq)]
31+
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
3132
#[repr(C)]
3233
pub struct Vector3 {
3334
/// The vector's X component.
@@ -432,4 +433,13 @@ mod test {
432433
Vector3::is_equal_approx
433434
);
434435
}
436+
437+
#[cfg(feature = "serde")]
438+
#[test]
439+
fn serde_roundtrip() {
440+
let rect = Vector3::default();
441+
let expected_json = "{\"x\":0.0,\"y\":0.0,\"z\":0.0}";
442+
443+
crate::builtin::test_utils::roundtrip(&rect, expected_json);
444+
}
435445
}

godot-core/src/builtin/vector3i.rs

+10
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ use super::IVec3;
2424
/// configured with an engine build option. Use `i64` or [`PackedInt64Array`] if 64-bit values are
2525
/// needed.
2626
#[derive(Debug, Default, Clone, Copy, Eq, Ord, PartialEq, PartialOrd)]
27+
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
2728
#[repr(C)]
2829
pub struct Vector3i {
2930
/// The vector's X component.
@@ -151,4 +152,13 @@ mod test {
151152
assert_eq!(a.coord_min(b), Vector3i::new(0, 3, 2));
152153
assert_eq!(a.coord_max(b), Vector3i::new(1, 5, 5));
153154
}
155+
156+
#[cfg(feature = "serde")]
157+
#[test]
158+
fn serde_roundtrip() {
159+
let rect = Vector3i::default();
160+
let expected_json = "{\"x\":0,\"y\":0,\"z\":0}";
161+
162+
crate::builtin::test_utils::roundtrip(&rect, expected_json);
163+
}
154164
}

godot-core/src/builtin/vector4.rs

+10
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ use super::{real, RVec4};
2525
///
2626
/// See [`Vector4i`] for its integer counterpart.
2727
#[derive(Debug, Default, Clone, Copy, PartialEq)]
28+
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
2829
#[repr(C)]
2930
pub struct Vector4 {
3031
/// The vector's X component.
@@ -160,4 +161,13 @@ mod test {
160161
Vector4::is_equal_approx
161162
);
162163
}
164+
165+
#[cfg(feature = "serde")]
166+
#[test]
167+
fn serde_roundtrip() {
168+
let rect = Vector4::default();
169+
let expected_json = "{\"x\":0.0,\"y\":0.0,\"z\":0.0,\"w\":0.0}";
170+
171+
crate::builtin::test_utils::roundtrip(&rect, expected_json);
172+
}
163173
}

godot-core/src/builtin/vector4i.rs

+10
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ use super::IVec4;
2323
/// configured with an engine build option. Use `i64` or [`PackedInt64Array`] if 64-bit values are
2424
/// needed.
2525
#[derive(Debug, Default, Clone, Copy, Eq, Ord, PartialEq, PartialOrd)]
26+
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
2627
#[repr(C)]
2728
pub struct Vector4i {
2829
/// The vector's X component.
@@ -138,4 +139,13 @@ mod test {
138139
assert_eq!(a.coord_min(b), Vector4i::new(0, 3, 2, 0),);
139140
assert_eq!(a.coord_max(b), Vector4i::new(1, 5, 5, 1));
140141
}
142+
143+
#[cfg(feature = "serde")]
144+
#[test]
145+
fn serde_roundtrip() {
146+
let rect = Vector4i::default();
147+
let expected_json = "{\"x\":0,\"y\":0,\"z\":0,\"w\":0}";
148+
149+
crate::builtin::test_utils::roundtrip(&rect, expected_json);
150+
}
141151
}

godot/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ formatted = ["godot-core/codegen-fmt"]
1313
double-precision = ["godot-core/double-precision"]
1414
custom-godot = ["godot-core/custom-godot"]
1515
threads = ["godot-core/threads"]
16+
serde = ["godot-core/serde"]
1617

1718
# Private features, they are under no stability guarantee
1819
codegen-full = ["godot-core/codegen-full"]

0 commit comments

Comments
 (0)