diff --git a/crates/bevy_math/src/primitives/dim2.rs b/crates/bevy_math/src/primitives/dim2.rs index 450c8c04b126d..dec76020741a0 100644 --- a/crates/bevy_math/src/primitives/dim2.rs +++ b/crates/bevy_math/src/primitives/dim2.rs @@ -241,9 +241,10 @@ impl Segment2d { /// /// For a version without generics: [`BoxedPolyline2d`] #[derive(Clone, Debug, PartialEq)] -// #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] pub struct Polyline2d { /// The vertices of the polyline + #[serde(with = "super::serde::array")] pub vertices: [Vec2; N], } impl Primitive2d for Polyline2d {} @@ -404,9 +405,10 @@ impl Rectangle { /// /// For a version without generics: [`BoxedPolygon`] #[derive(Clone, Debug, PartialEq)] -// #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] pub struct Polygon { /// The vertices of the `Polygon` + #[serde(with = "super::serde::array")] pub vertices: [Vec2; N], } impl Primitive2d for Polygon {} diff --git a/crates/bevy_math/src/primitives/dim3.rs b/crates/bevy_math/src/primitives/dim3.rs index bf707dca180bf..629a83634d199 100644 --- a/crates/bevy_math/src/primitives/dim3.rs +++ b/crates/bevy_math/src/primitives/dim3.rs @@ -199,9 +199,10 @@ impl Segment3d { /// /// For a version without generics: [`BoxedPolyline3d`] #[derive(Clone, Debug, PartialEq)] -// #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] pub struct Polyline3d { /// The vertices of the polyline + #[serde(with = "super::serde::array")] pub vertices: [Vec3; N], } impl Primitive3d for Polyline3d {} diff --git a/crates/bevy_math/src/primitives/mod.rs b/crates/bevy_math/src/primitives/mod.rs index a6567e6330c33..db5f380897572 100644 --- a/crates/bevy_math/src/primitives/mod.rs +++ b/crates/bevy_math/src/primitives/mod.rs @@ -6,6 +6,8 @@ mod dim2; pub use dim2::*; mod dim3; pub use dim3::*; +#[cfg(feature = "serialize")] +mod serde; /// A marker trait for 2D primitives pub trait Primitive2d {} diff --git a/crates/bevy_math/src/primitives/serde.rs b/crates/bevy_math/src/primitives/serde.rs new file mode 100644 index 0000000000000..79abb778cd39d --- /dev/null +++ b/crates/bevy_math/src/primitives/serde.rs @@ -0,0 +1,63 @@ +//! This module defines serialization/deserialization for const generic arrays. +//! Unlike serde's default behavior, it supports arbitrarily large arrays. +//! The code is based on this github comment: +//! + +pub(crate) mod array { + use serde::{ + de::{SeqAccess, Visitor}, + ser::SerializeTuple, + Deserialize, Deserializer, Serialize, Serializer, + }; + use std::marker::PhantomData; + + pub fn serialize( + data: &[T; N], + ser: S, + ) -> Result { + let mut s = ser.serialize_tuple(N)?; + for item in data { + s.serialize_element(item)?; + } + s.end() + } + + struct GenericArrayVisitor(PhantomData); + + impl<'de, T, const N: usize> Visitor<'de> for GenericArrayVisitor + where + T: Deserialize<'de>, + { + type Value = [T; N]; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str(&format!("an array of length {}", N)) + } + + #[inline] + fn visit_seq(self, mut seq: A) -> Result + where + A: SeqAccess<'de>, + { + let mut data = Vec::with_capacity(N); + for _ in 0..N { + match (seq.next_element())? { + Some(val) => data.push(val), + None => return Err(serde::de::Error::invalid_length(N, &self)), + } + } + match data.try_into() { + Ok(arr) => Ok(arr), + Err(_) => unreachable!(), + } + } + } + + pub fn deserialize<'de, D, T, const N: usize>(deserializer: D) -> Result<[T; N], D::Error> + where + D: Deserializer<'de>, + T: Deserialize<'de>, + { + deserializer.deserialize_tuple(N, GenericArrayVisitor::(PhantomData)) + } +}