Skip to content

Add serde behind feature flag for some builtins #237

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 8, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/full-ci.yml
Original file line number Diff line number Diff line change
@@ -169,11 +169,11 @@ jobs:
godot-binary: godot.linuxbsd.editor.dev.double.x86_64
rust-extra-args: --features double-precision

- name: linux-threads
- name: linux-features
os: ubuntu-20.04
artifact-name: linux
godot-binary: godot.linuxbsd.editor.dev.x86_64
rust-extra-args: --features threads
rust-extra-args: --features threads,serde

- name: linux-nightly
os: ubuntu-20.04
2 changes: 2 additions & 0 deletions godot-core/Cargo.toml
Original file line number Diff line number Diff line change
@@ -21,10 +21,12 @@ godot-ffi = { path = "../godot-ffi" }

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

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

[build-dependencies]
godot-codegen = { path = "../godot-codegen" }
13 changes: 13 additions & 0 deletions godot-core/src/builtin/aabb.rs
Original file line number Diff line number Diff line change
@@ -18,6 +18,7 @@ use super::Vector3;
///
/// The 2D counterpart to `Aabb` is [`Rect2`](super::Rect2).
#[derive(Default, Copy, Clone, PartialEq, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(C)]
pub struct Aabb {
pub position: Vector3,
@@ -101,3 +102,15 @@ impl std::fmt::Display for Aabb {
unsafe impl GodotFfi for Aabb {
ffi_methods! { type sys::GDExtensionTypePtr = *mut Self; .. }
}

#[cfg(test)]
mod test {
#[cfg(feature = "serde")]
#[test]
fn serde_roundtrip() {
let aabb = super::Aabb::default();
let expected_json = "{\"position\":{\"x\":0.0,\"y\":0.0,\"z\":0.0},\"size\":{\"x\":0.0,\"y\":0.0,\"z\":0.0}}";

crate::builtin::test_utils::roundtrip(&aabb, expected_json);
}
}
10 changes: 10 additions & 0 deletions godot-core/src/builtin/basis.rs
Original file line number Diff line number Diff line change
@@ -23,6 +23,7 @@ use super::{real, RMat3, RQuat, RVec2, RVec3};
/// The basis vectors are the columns of the matrix, whereas the [`rows`](Self::rows) field represents
/// the row vectors.
#[derive(Copy, Clone, PartialEq, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(C)]
pub struct Basis {
/// The rows of the matrix. These are *not* the basis vectors.
@@ -835,4 +836,13 @@ mod test {
"Basis with three components infinite should not be finite."
);
}

#[cfg(feature = "serde")]
#[test]
fn serde_roundtrip() {
let basis = Basis::IDENTITY;
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}]}";

crate::builtin::test_utils::roundtrip(&basis, expected_json);
}
}
13 changes: 13 additions & 0 deletions godot-core/src/builtin/color.rs
Original file line number Diff line number Diff line change
@@ -16,6 +16,7 @@ use sys::{ffi_methods, GodotFfi};
/// values outside this range are explicitly allowed for e.g. High Dynamic Range (HDR).
#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Color {
/// The color's red component.
pub r: f32,
@@ -511,3 +512,15 @@ impl std::fmt::Display for Color {
write!(f, "({}, {}, {}, {})", self.r, self.g, self.b, self.a)
}
}

#[cfg(test)]
mod test {
#[cfg(feature = "serde")]
#[test]
fn serde_roundtrip() {
let color = super::Color::WHITE;
let expected_json = "{\"r\":1.0,\"g\":1.0,\"b\":1.0,\"a\":1.0}";

crate::builtin::test_utils::roundtrip(&color, expected_json);
}
}
19 changes: 19 additions & 0 deletions godot-core/src/builtin/mod.rs
Original file line number Diff line number Diff line change
@@ -407,3 +407,22 @@ mod export {
// TODO investigate whether Signal should impl Export at all, and if so, how
// impl_export_by_clone!(Signal);
}

#[cfg(all(test, feature = "serde"))]
pub(crate) mod test_utils {
use serde::{Deserialize, Serialize};

pub(crate) fn roundtrip<T>(value: &T, expected_json: &str)
where
T: for<'a> Deserialize<'a> + Serialize + PartialEq + std::fmt::Debug,
{
let json: String = serde_json::to_string(value).unwrap();
let back: T = serde_json::from_str(json.as_str()).unwrap();

assert_eq!(back, *value, "serde round-trip changes value");
assert_eq!(
json, expected_json,
"value does not conform to expected JSON"
);
}
}
13 changes: 13 additions & 0 deletions godot-core/src/builtin/plane.rs
Original file line number Diff line number Diff line change
@@ -23,6 +23,7 @@ use super::{is_equal_approx, real, Vector3};
/// unit length and will panic if this invariant is violated. This is not separately
/// annotated for each method.
#[derive(Copy, Clone, PartialEq, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(C)]
pub struct Plane {
pub normal: Vector3,
@@ -189,4 +190,16 @@ mod test {
Vector3::new(0.0, 0.0, 2.0),
);
}

#[cfg(feature = "serde")]
#[test]
fn serde_roundtrip() {
let plane = Plane {
normal: Vector3::ONE,
d: 0.0,
};
let expected_json = "{\"normal\":{\"x\":1.0,\"y\":1.0,\"z\":1.0},\"d\":0.0}";

crate::builtin::test_utils::roundtrip(&plane, expected_json);
}
}
10 changes: 10 additions & 0 deletions godot-core/src/builtin/projection.rs
Original file line number Diff line number Diff line change
@@ -25,6 +25,7 @@ use super::{real, RMat4, RealConv};
/// Note: The current implementation largely makes calls to godot for its
/// methods and as such are not as performant as other types.
#[derive(Copy, Clone, PartialEq, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(C)]
pub struct Projection {
/// The columns of the projection matrix.
@@ -960,6 +961,15 @@ mod test {
}
}
}

#[cfg(feature = "serde")]
#[test]
fn serde_roundtrip() {
let projection = Projection::IDENTITY;
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}]}";

crate::builtin::test_utils::roundtrip(&projection, expected_json);
}
}

impl std::fmt::Display for Projection {
13 changes: 13 additions & 0 deletions godot-core/src/builtin/quaternion.rs
Original file line number Diff line number Diff line change
@@ -15,6 +15,7 @@ use super::{real, RQuat};
use super::{Basis, EulerOrder};

#[derive(Copy, Clone, PartialEq, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(C)]
pub struct Quaternion {
pub x: real,
@@ -347,3 +348,15 @@ impl Neg for Quaternion {
Self::new(-self.x, -self.y, -self.z, -self.w)
}
}

#[cfg(test)]
mod test {
#[cfg(feature = "serde")]
#[test]
fn serde_roundtrip() {
let quaternion = super::Quaternion::new(1.0, 1.0, 1.0, 1.0);
let expected_json = "{\"x\":1.0,\"y\":1.0,\"z\":1.0,\"w\":1.0}";

crate::builtin::test_utils::roundtrip(&quaternion, expected_json);
}
}
13 changes: 13 additions & 0 deletions godot-core/src/builtin/rect2.rs
Original file line number Diff line number Diff line change
@@ -18,6 +18,7 @@ use super::{real, Rect2i, Vector2};
///
/// The 3D counterpart to `Rect2` is [`Aabb`](super::Aabb).
#[derive(Default, Copy, Clone, PartialEq, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(C)]
pub struct Rect2 {
pub position: Vector2,
@@ -125,3 +126,15 @@ impl std::fmt::Display for Rect2 {
write!(f, "[P: {}, S: {}]", self.position, self.size)
}
}

#[cfg(test)]
mod test {
#[cfg(feature = "serde")]
#[test]
fn serde_roundtrip() {
let rect = super::Rect2::default();
let expected_json = "{\"position\":{\"x\":0.0,\"y\":0.0},\"size\":{\"x\":0.0,\"y\":0.0}}";

crate::builtin::test_utils::roundtrip(&rect, expected_json);
}
}
10 changes: 10 additions & 0 deletions godot-core/src/builtin/rect2i.rs
Original file line number Diff line number Diff line change
@@ -15,6 +15,7 @@ use super::{Rect2, RectSide, Vector2i};
/// `Rect2i` consists of a position, a size, and several utility functions. It is typically used for
/// fast overlap tests.
#[derive(Default, Copy, Clone, Eq, PartialEq, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(C)]
pub struct Rect2i {
/// The position of the rectangle.
@@ -583,4 +584,13 @@ mod test {
let rect = Rect2i::from_components(0, 0, -5, -5);
Rect2i::default().merge(rect);
}

#[cfg(feature = "serde")]
#[test]
fn serde_roundtrip() {
let rect = Rect2i::default();
let expected_json = "{\"position\":{\"x\":0,\"y\":0},\"size\":{\"x\":0,\"y\":0}}";

crate::builtin::test_utils::roundtrip(&rect, expected_json);
}
}
10 changes: 10 additions & 0 deletions godot-core/src/builtin/transform2d.rs
Original file line number Diff line number Diff line change
@@ -27,6 +27,7 @@ use super::{real, RAffine2, RMat2};
///
/// For methods that don't take translation into account, see [`Basis2D`].
#[derive(Default, Copy, Clone, PartialEq, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(C)]
pub struct Transform2D {
/// The first basis vector.
@@ -739,4 +740,13 @@ mod test {
"let with: Transform2D three components infinite should not be finite.",
);
}

#[cfg(feature = "serde")]
#[test]
fn serde_roundtrip() {
let transform = Transform2D::default();
let expected_json = "{\"a\":{\"x\":0.0,\"y\":0.0},\"b\":{\"x\":0.0,\"y\":0.0},\"origin\":{\"x\":0.0,\"y\":0.0}}";

crate::builtin::test_utils::roundtrip(&transform, expected_json);
}
}
10 changes: 10 additions & 0 deletions godot-core/src/builtin/transform3d.rs
Original file line number Diff line number Diff line change
@@ -24,6 +24,7 @@ use super::{Aabb, Basis, Plane, Projection, Vector3};
/// [ a.z b.z c.z o.z ]
/// ```
#[derive(Default, Copy, Clone, PartialEq, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(C)]
pub struct Transform3D {
/// The basis is a matrix containing 3 vectors as its columns. They can be
@@ -459,4 +460,13 @@ mod test {
"Transform3D with two components infinite should not be finite.",
);
}

#[cfg(feature = "serde")]
#[test]
fn serde_roundtrip() {
let transform = Transform3D::default();
let expected_json = "{\"basis\":{\"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}]},\"origin\":{\"x\":0.0,\"y\":0.0,\"z\":0.0}}";

crate::builtin::test_utils::roundtrip(&transform, expected_json);
}
}
10 changes: 10 additions & 0 deletions godot-core/src/builtin/vector2.rs
Original file line number Diff line number Diff line change
@@ -27,6 +27,7 @@ use super::{real, RAffine2, RVec2};
///
/// See [`Vector2i`] for its integer counterpart.
#[derive(Debug, Default, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(C)]
pub struct Vector2 {
/// The vector's X component.
@@ -369,4 +370,13 @@ mod test {
Vector2::is_equal_approx
);
}

#[cfg(feature = "serde")]
#[test]
fn serde_roundtrip() {
let vector = Vector2::default();
let expected_json = "{\"x\":0.0,\"y\":0.0}";

crate::builtin::test_utils::roundtrip(&vector, expected_json);
}
}
10 changes: 10 additions & 0 deletions godot-core/src/builtin/vector2i.rs
Original file line number Diff line number Diff line change
@@ -24,6 +24,7 @@ use super::IVec2;
/// configured with an engine build option. Use `i64` or [`PackedInt64Array`] if 64-bit values are
/// needed.
#[derive(Debug, Default, Clone, Copy, Eq, Ord, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(C)]
pub struct Vector2i {
/// The vector's X component.
@@ -140,4 +141,13 @@ mod test {
assert_eq!(a.coord_min(b), Vector2i::new(0, 3));
assert_eq!(a.coord_max(b), Vector2i::new(1, 5));
}

#[cfg(feature = "serde")]
#[test]
fn serde_roundtrip() {
let vector = Vector2i::default();
let expected_json = "{\"x\":0,\"y\":0}";

crate::builtin::test_utils::roundtrip(&vector, expected_json);
}
}
10 changes: 10 additions & 0 deletions godot-core/src/builtin/vector3.rs
Original file line number Diff line number Diff line change
@@ -28,6 +28,7 @@ use super::{real, Basis, RVec3};
///
/// See [`Vector3i`] for its integer counterpart.
#[derive(Debug, Default, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(C)]
pub struct Vector3 {
/// The vector's X component.
@@ -432,4 +433,13 @@ mod test {
Vector3::is_equal_approx
);
}

#[cfg(feature = "serde")]
#[test]
fn serde_roundtrip() {
let vector = Vector3::default();
let expected_json = "{\"x\":0.0,\"y\":0.0,\"z\":0.0}";

crate::builtin::test_utils::roundtrip(&vector, expected_json);
}
}
10 changes: 10 additions & 0 deletions godot-core/src/builtin/vector3i.rs
Original file line number Diff line number Diff line change
@@ -24,6 +24,7 @@ use super::IVec3;
/// configured with an engine build option. Use `i64` or [`PackedInt64Array`] if 64-bit values are
/// needed.
#[derive(Debug, Default, Clone, Copy, Eq, Ord, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(C)]
pub struct Vector3i {
/// The vector's X component.
@@ -151,4 +152,13 @@ mod test {
assert_eq!(a.coord_min(b), Vector3i::new(0, 3, 2));
assert_eq!(a.coord_max(b), Vector3i::new(1, 5, 5));
}

#[cfg(feature = "serde")]
#[test]
fn serde_roundtrip() {
let vector = Vector3i::default();
let expected_json = "{\"x\":0,\"y\":0,\"z\":0}";

crate::builtin::test_utils::roundtrip(&vector, expected_json);
}
}
10 changes: 10 additions & 0 deletions godot-core/src/builtin/vector4.rs
Original file line number Diff line number Diff line change
@@ -25,6 +25,7 @@ use super::{real, RVec4};
///
/// See [`Vector4i`] for its integer counterpart.
#[derive(Debug, Default, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(C)]
pub struct Vector4 {
/// The vector's X component.
@@ -160,4 +161,13 @@ mod test {
Vector4::is_equal_approx
);
}

#[cfg(feature = "serde")]
#[test]
fn serde_roundtrip() {
let vector = Vector4::default();
let expected_json = "{\"x\":0.0,\"y\":0.0,\"z\":0.0,\"w\":0.0}";

crate::builtin::test_utils::roundtrip(&vector, expected_json);
}
}
Loading