Skip to content

Commit ced187f

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

19 files changed

+197
-0
lines changed

godot-core/Cargo.toml

Lines changed: 2 additions & 0 deletions
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

Lines changed: 13 additions & 0 deletions
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 aabb = 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(&aabb, expected_json);
115+
}
116+
}

godot-core/src/builtin/basis.rs

Lines changed: 10 additions & 0 deletions
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 basis = 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(&basis, expected_json);
847+
}
838848
}

godot-core/src/builtin/color.rs

Lines changed: 13 additions & 0 deletions
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 color = 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(&color, expected_json);
525+
}
526+
}

godot-core/src/builtin/mod.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,3 +407,22 @@ 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+
let json: String = serde_json::to_string(value).unwrap();
420+
let back: T = serde_json::from_str(json.as_str()).unwrap();
421+
422+
assert_eq!(back, *value, "serde round-trip changes value");
423+
assert_eq!(
424+
json, expected_json,
425+
"value does not conform to expected JSON"
426+
);
427+
}
428+
}

godot-core/src/builtin/plane.rs

Lines changed: 13 additions & 0 deletions
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 plane = 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(&plane, expected_json);
204+
}
192205
}

godot-core/src/builtin/projection.rs

Lines changed: 10 additions & 0 deletions
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 projection = 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(&projection, expected_json);
972+
}
963973
}
964974

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

godot-core/src/builtin/quaternion.rs

Lines changed: 13 additions & 0 deletions
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 quaternion = 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(&quaternion, expected_json);
361+
}
362+
}

godot-core/src/builtin/rect2.rs

Lines changed: 13 additions & 0 deletions
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

Lines changed: 10 additions & 0 deletions
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
}

0 commit comments

Comments
 (0)