From 1a9f3125934c4516024955e8ccb1223fdfdb532c Mon Sep 17 00:00:00 2001 From: Jakob Hellermann Date: Mon, 13 Mar 2023 13:39:50 +0100 Subject: [PATCH 1/6] remove serde_derive --- Cargo.toml | 2 +- src/euler.rs | 160 ++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 160 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 15c69e10..a5d784a2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,7 +50,7 @@ bytemuck = { version = "1.5", optional = true, default-features = false } mint = { version = "0.5.8", optional = true, default-features = false } num-traits = { version = "0.2.14", optional = true, default-features = false } rand = { version = "0.8", optional = true, default-features = false } -serde = { version = "1.0", optional = true, default-features = false, features = ["derive"] } +serde = { version = "1.0", optional = true, default-features = false } rkyv = { version = "0.7", optional = true } bytecheck = { version = "0.6", optional = true, default-features = false} diff --git a/src/euler.rs b/src/euler.rs index c97a9628..30fff1e1 100644 --- a/src/euler.rs +++ b/src/euler.rs @@ -17,7 +17,6 @@ use num_traits::Float; /// /// YXZ can be used for yaw (y-axis), pitch (x-axis), roll (z-axis). #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub enum EulerRot { /// Intrinsic three-axis rotation ZYX ZYX, @@ -33,6 +32,165 @@ pub enum EulerRot { XZY, } +#[cfg(feature = "serde")] +impl serde::Serialize for EulerRot { + fn serialize(&self, serializer: S) -> Result { + match *self { + EulerRot::ZYX => { + serde::Serializer::serialize_unit_variant(serializer, "EulerRot", 0u32, "ZYX") + } + EulerRot::ZXY => { + serde::Serializer::serialize_unit_variant(serializer, "EulerRot", 1u32, "ZXY") + } + EulerRot::YXZ => { + serde::Serializer::serialize_unit_variant(serializer, "EulerRot", 2u32, "YXZ") + } + EulerRot::YZX => { + serde::Serializer::serialize_unit_variant(serializer, "EulerRot", 3u32, "YZX") + } + EulerRot::XYZ => { + serde::Serializer::serialize_unit_variant(serializer, "EulerRot", 4u32, "XYZ") + } + EulerRot::XZY => { + serde::Serializer::serialize_unit_variant(serializer, "EulerRot", 5u32, "XZY") + } + } + } +} + +#[cfg(feature = "serde")] +impl<'de> serde::Deserialize<'de> for EulerRot { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + enum Field { + ZYX, + ZXY, + YXZ, + YZX, + XYZ, + XZY, + } + struct FieldVisitor; + + impl<'de> serde::de::Visitor<'de> for FieldVisitor { + type Value = Field; + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Formatter::write_str(formatter, "variant identifier") + } + fn visit_u64(self, value: u64) -> Result + where + E: serde::de::Error, + { + match value { + 0u64 => Ok(Field::ZYX), + 1u64 => Ok(Field::ZXY), + 2u64 => Ok(Field::YXZ), + 3u64 => Ok(Field::YZX), + 4u64 => Ok(Field::XYZ), + 5u64 => Ok(Field::XZY), + _ => Err(serde::de::Error::invalid_value( + serde::de::Unexpected::Unsigned(value), + &"variant index 0 <= i < 6", + )), + } + } + fn visit_str(self, value: &str) -> Result + where + E: serde::de::Error, + { + match value { + "ZYX" => Ok(Field::ZYX), + "ZXY" => Ok(Field::ZXY), + "YXZ" => Ok(Field::YXZ), + "YZX" => Ok(Field::YZX), + "XYZ" => Ok(Field::XYZ), + "XZY" => Ok(Field::XZY), + _ => Err(serde::de::Error::unknown_variant(value, VARIANTS)), + } + } + fn visit_bytes(self, value: &[u8]) -> Result + where + E: serde::de::Error, + { + match value { + b"ZYX" => Ok(Field::ZYX), + b"ZXY" => Ok(Field::ZXY), + b"YXZ" => Ok(Field::YXZ), + b"YZX" => Ok(Field::YZX), + b"XYZ" => Ok(Field::XYZ), + b"XZY" => Ok(Field::XZY), + _ => { + let value = &String::from_utf8_lossy(value); + Err(serde::de::Error::unknown_variant(value, VARIANTS)) + } + } + } + } + impl<'de> serde::Deserialize<'de> for Field { + #[inline] + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + serde::Deserializer::deserialize_identifier(deserializer, FieldVisitor) + } + } + struct Visitor<'de> { + marker: std::marker::PhantomData, + lifetime: std::marker::PhantomData<&'de ()>, + } + impl<'de> serde::de::Visitor<'de> for Visitor<'de> { + type Value = EulerRot; + fn expecting(&self, __formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Formatter::write_str(__formatter, "enum EulerRot") + } + fn visit_enum(self, data: A) -> Result + where + A: serde::de::EnumAccess<'de>, + { + match serde::de::EnumAccess::variant(data)? { + (Field::ZYX, variant) => { + serde::de::VariantAccess::unit_variant(variant)?; + Ok(EulerRot::ZYX) + } + (Field::ZXY, variant) => { + serde::de::VariantAccess::unit_variant(variant)?; + Ok(EulerRot::ZXY) + } + (Field::YXZ, variant) => { + serde::de::VariantAccess::unit_variant(variant)?; + Ok(EulerRot::YXZ) + } + (Field::YZX, variant) => { + serde::de::VariantAccess::unit_variant(variant)?; + Ok(EulerRot::YZX) + } + (Field::XYZ, variant) => { + serde::de::VariantAccess::unit_variant(variant)?; + Ok(EulerRot::XYZ) + } + (Field::XZY, variant) => { + serde::de::VariantAccess::unit_variant(variant)?; + Ok(EulerRot::XZY) + } + } + } + } + const VARIANTS: &'static [&'static str] = &["ZYX", "ZXY", "YXZ", "YZX", "XYZ", "XZY"]; + serde::Deserializer::deserialize_enum( + deserializer, + "EulerRot", + VARIANTS, + Visitor { + marker: std::marker::PhantomData::, + lifetime: std::marker::PhantomData, + }, + ) + } +} + impl Default for EulerRot { /// Default `YXZ` as yaw (y-axis), pitch (x-axis), roll (z-axis). fn default() -> Self { From f699e1c8fa01ddf1fd81d7b2c3b3659411788abf Mon Sep 17 00:00:00 2001 From: Jakob Hellermann Date: Tue, 14 Mar 2023 09:25:18 +0100 Subject: [PATCH 2/6] fix clippy lints --- src/euler.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/euler.rs b/src/euler.rs index 30fff1e1..d120238c 100644 --- a/src/euler.rs +++ b/src/euler.rs @@ -64,6 +64,7 @@ impl<'de> serde::Deserialize<'de> for EulerRot { where D: serde::Deserializer<'de>, { + #[allow(clippy::upper_case_acronyms)] enum Field { ZYX, ZXY, @@ -178,7 +179,7 @@ impl<'de> serde::Deserialize<'de> for EulerRot { } } } - const VARIANTS: &'static [&'static str] = &["ZYX", "ZXY", "YXZ", "YZX", "XYZ", "XZY"]; + const VARIANTS: &[&str] = &["ZYX", "ZXY", "YXZ", "YZX", "XYZ", "XZY"]; serde::Deserializer::deserialize_enum( deserializer, "EulerRot", From 7d1981d48e929e3575c401b29bc7b678c240cd7d Mon Sep 17 00:00:00 2001 From: Jakob Hellermann Date: Tue, 14 Mar 2023 09:21:53 +0100 Subject: [PATCH 3/6] replace std with core --- src/euler.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/euler.rs b/src/euler.rs index d120238c..6c2cffec 100644 --- a/src/euler.rs +++ b/src/euler.rs @@ -77,8 +77,8 @@ impl<'de> serde::Deserialize<'de> for EulerRot { impl<'de> serde::de::Visitor<'de> for FieldVisitor { type Value = Field; - fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - std::fmt::Formatter::write_str(formatter, "variant identifier") + fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + core::fmt::Formatter::write_str(formatter, "variant identifier") } fn visit_u64(self, value: u64) -> Result where @@ -139,13 +139,13 @@ impl<'de> serde::Deserialize<'de> for EulerRot { } } struct Visitor<'de> { - marker: std::marker::PhantomData, - lifetime: std::marker::PhantomData<&'de ()>, + marker: core::marker::PhantomData, + lifetime: core::marker::PhantomData<&'de ()>, } impl<'de> serde::de::Visitor<'de> for Visitor<'de> { type Value = EulerRot; - fn expecting(&self, __formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - std::fmt::Formatter::write_str(__formatter, "enum EulerRot") + fn expecting(&self, __formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + core::fmt::Formatter::write_str(__formatter, "enum EulerRot") } fn visit_enum(self, data: A) -> Result where @@ -185,8 +185,8 @@ impl<'de> serde::Deserialize<'de> for EulerRot { "EulerRot", VARIANTS, Visitor { - marker: std::marker::PhantomData::, - lifetime: std::marker::PhantomData, + marker: core::marker::PhantomData::, + lifetime: core::marker::PhantomData, }, ) } From b98fd19fab49c653f616cdfe3fc40e40a5a34ab3 Mon Sep 17 00:00:00 2001 From: Jakob Hellermann Date: Tue, 14 Mar 2023 09:33:55 +0100 Subject: [PATCH 4/6] fix usage of String --- src/euler.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/euler.rs b/src/euler.rs index 6c2cffec..839b8e4a 100644 --- a/src/euler.rs +++ b/src/euler.rs @@ -123,7 +123,11 @@ impl<'de> serde::Deserialize<'de> for EulerRot { b"XYZ" => Ok(Field::XYZ), b"XZY" => Ok(Field::XZY), _ => { + #[cfg(feature = "std")] let value = &String::from_utf8_lossy(value); + #[cfg(not(feature = "std"))] + let value = + core::str::from_utf8(value).unwrap_or("\u{fffd}\u{fffd}\u{fffd}"); Err(serde::de::Error::unknown_variant(value, VARIANTS)) } } From 5cf7ee748cb236e22e22e8ae9d072854b80a7c5a Mon Sep 17 00:00:00 2001 From: Jakob Hellermann Date: Fri, 17 Mar 2023 10:41:08 +0100 Subject: [PATCH 5/6] move serde code to impl_serde --- src/euler.rs | 164 ----------------------------------- src/features/impl_serde.rs | 169 +++++++++++++++++++++++++++++++++++++ 2 files changed, 169 insertions(+), 164 deletions(-) diff --git a/src/euler.rs b/src/euler.rs index 839b8e4a..cd658bf3 100644 --- a/src/euler.rs +++ b/src/euler.rs @@ -32,170 +32,6 @@ pub enum EulerRot { XZY, } -#[cfg(feature = "serde")] -impl serde::Serialize for EulerRot { - fn serialize(&self, serializer: S) -> Result { - match *self { - EulerRot::ZYX => { - serde::Serializer::serialize_unit_variant(serializer, "EulerRot", 0u32, "ZYX") - } - EulerRot::ZXY => { - serde::Serializer::serialize_unit_variant(serializer, "EulerRot", 1u32, "ZXY") - } - EulerRot::YXZ => { - serde::Serializer::serialize_unit_variant(serializer, "EulerRot", 2u32, "YXZ") - } - EulerRot::YZX => { - serde::Serializer::serialize_unit_variant(serializer, "EulerRot", 3u32, "YZX") - } - EulerRot::XYZ => { - serde::Serializer::serialize_unit_variant(serializer, "EulerRot", 4u32, "XYZ") - } - EulerRot::XZY => { - serde::Serializer::serialize_unit_variant(serializer, "EulerRot", 5u32, "XZY") - } - } - } -} - -#[cfg(feature = "serde")] -impl<'de> serde::Deserialize<'de> for EulerRot { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - #[allow(clippy::upper_case_acronyms)] - enum Field { - ZYX, - ZXY, - YXZ, - YZX, - XYZ, - XZY, - } - struct FieldVisitor; - - impl<'de> serde::de::Visitor<'de> for FieldVisitor { - type Value = Field; - fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - core::fmt::Formatter::write_str(formatter, "variant identifier") - } - fn visit_u64(self, value: u64) -> Result - where - E: serde::de::Error, - { - match value { - 0u64 => Ok(Field::ZYX), - 1u64 => Ok(Field::ZXY), - 2u64 => Ok(Field::YXZ), - 3u64 => Ok(Field::YZX), - 4u64 => Ok(Field::XYZ), - 5u64 => Ok(Field::XZY), - _ => Err(serde::de::Error::invalid_value( - serde::de::Unexpected::Unsigned(value), - &"variant index 0 <= i < 6", - )), - } - } - fn visit_str(self, value: &str) -> Result - where - E: serde::de::Error, - { - match value { - "ZYX" => Ok(Field::ZYX), - "ZXY" => Ok(Field::ZXY), - "YXZ" => Ok(Field::YXZ), - "YZX" => Ok(Field::YZX), - "XYZ" => Ok(Field::XYZ), - "XZY" => Ok(Field::XZY), - _ => Err(serde::de::Error::unknown_variant(value, VARIANTS)), - } - } - fn visit_bytes(self, value: &[u8]) -> Result - where - E: serde::de::Error, - { - match value { - b"ZYX" => Ok(Field::ZYX), - b"ZXY" => Ok(Field::ZXY), - b"YXZ" => Ok(Field::YXZ), - b"YZX" => Ok(Field::YZX), - b"XYZ" => Ok(Field::XYZ), - b"XZY" => Ok(Field::XZY), - _ => { - #[cfg(feature = "std")] - let value = &String::from_utf8_lossy(value); - #[cfg(not(feature = "std"))] - let value = - core::str::from_utf8(value).unwrap_or("\u{fffd}\u{fffd}\u{fffd}"); - Err(serde::de::Error::unknown_variant(value, VARIANTS)) - } - } - } - } - impl<'de> serde::Deserialize<'de> for Field { - #[inline] - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - serde::Deserializer::deserialize_identifier(deserializer, FieldVisitor) - } - } - struct Visitor<'de> { - marker: core::marker::PhantomData, - lifetime: core::marker::PhantomData<&'de ()>, - } - impl<'de> serde::de::Visitor<'de> for Visitor<'de> { - type Value = EulerRot; - fn expecting(&self, __formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - core::fmt::Formatter::write_str(__formatter, "enum EulerRot") - } - fn visit_enum(self, data: A) -> Result - where - A: serde::de::EnumAccess<'de>, - { - match serde::de::EnumAccess::variant(data)? { - (Field::ZYX, variant) => { - serde::de::VariantAccess::unit_variant(variant)?; - Ok(EulerRot::ZYX) - } - (Field::ZXY, variant) => { - serde::de::VariantAccess::unit_variant(variant)?; - Ok(EulerRot::ZXY) - } - (Field::YXZ, variant) => { - serde::de::VariantAccess::unit_variant(variant)?; - Ok(EulerRot::YXZ) - } - (Field::YZX, variant) => { - serde::de::VariantAccess::unit_variant(variant)?; - Ok(EulerRot::YZX) - } - (Field::XYZ, variant) => { - serde::de::VariantAccess::unit_variant(variant)?; - Ok(EulerRot::XYZ) - } - (Field::XZY, variant) => { - serde::de::VariantAccess::unit_variant(variant)?; - Ok(EulerRot::XZY) - } - } - } - } - const VARIANTS: &[&str] = &["ZYX", "ZXY", "YXZ", "YZX", "XYZ", "XZY"]; - serde::Deserializer::deserialize_enum( - deserializer, - "EulerRot", - VARIANTS, - Visitor { - marker: core::marker::PhantomData::, - lifetime: core::marker::PhantomData, - }, - ) - } -} - impl Default for EulerRot { /// Default `YXZ` as yaw (y-axis), pitch (x-axis), roll (z-axis). fn default() -> Self { diff --git a/src/features/impl_serde.rs b/src/features/impl_serde.rs index c3a44e08..402875e4 100644 --- a/src/features/impl_serde.rs +++ b/src/features/impl_serde.rs @@ -1000,3 +1000,172 @@ mod u32 { impl_serde_vec_types!(u32, UVec2, UVec3, UVec4); } + +mod euler { + use crate::EulerRot; + + impl serde::Serialize for EulerRot { + fn serialize(&self, serializer: S) -> Result { + match *self { + EulerRot::ZYX => { + serde::Serializer::serialize_unit_variant(serializer, "EulerRot", 0u32, "ZYX") + } + EulerRot::ZXY => { + serde::Serializer::serialize_unit_variant(serializer, "EulerRot", 1u32, "ZXY") + } + EulerRot::YXZ => { + serde::Serializer::serialize_unit_variant(serializer, "EulerRot", 2u32, "YXZ") + } + EulerRot::YZX => { + serde::Serializer::serialize_unit_variant(serializer, "EulerRot", 3u32, "YZX") + } + EulerRot::XYZ => { + serde::Serializer::serialize_unit_variant(serializer, "EulerRot", 4u32, "XYZ") + } + EulerRot::XZY => { + serde::Serializer::serialize_unit_variant(serializer, "EulerRot", 5u32, "XZY") + } + } + } + } + + impl<'de> serde::Deserialize<'de> for EulerRot { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + #[allow(clippy::upper_case_acronyms)] + enum Field { + ZYX, + ZXY, + YXZ, + YZX, + XYZ, + XZY, + } + struct FieldVisitor; + + impl<'de> serde::de::Visitor<'de> for FieldVisitor { + type Value = Field; + fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + core::fmt::Formatter::write_str(formatter, "variant identifier") + } + fn visit_u64(self, value: u64) -> Result + where + E: serde::de::Error, + { + match value { + 0u64 => Ok(Field::ZYX), + 1u64 => Ok(Field::ZXY), + 2u64 => Ok(Field::YXZ), + 3u64 => Ok(Field::YZX), + 4u64 => Ok(Field::XYZ), + 5u64 => Ok(Field::XZY), + _ => Err(serde::de::Error::invalid_value( + serde::de::Unexpected::Unsigned(value), + &"variant index 0 <= i < 6", + )), + } + } + fn visit_str(self, value: &str) -> Result + where + E: serde::de::Error, + { + match value { + "ZYX" => Ok(Field::ZYX), + "ZXY" => Ok(Field::ZXY), + "YXZ" => Ok(Field::YXZ), + "YZX" => Ok(Field::YZX), + "XYZ" => Ok(Field::XYZ), + "XZY" => Ok(Field::XZY), + _ => Err(serde::de::Error::unknown_variant(value, VARIANTS)), + } + } + fn visit_bytes(self, value: &[u8]) -> Result + where + E: serde::de::Error, + { + match value { + b"ZYX" => Ok(Field::ZYX), + b"ZXY" => Ok(Field::ZXY), + b"YXZ" => Ok(Field::YXZ), + b"YZX" => Ok(Field::YZX), + b"XYZ" => Ok(Field::XYZ), + b"XZY" => Ok(Field::XZY), + _ => { + #[cfg(feature = "std")] + let value = &String::from_utf8_lossy(value); + #[cfg(not(feature = "std"))] + let value = + core::str::from_utf8(value).unwrap_or("\u{fffd}\u{fffd}\u{fffd}"); + Err(serde::de::Error::unknown_variant(value, VARIANTS)) + } + } + } + } + impl<'de> serde::Deserialize<'de> for Field { + #[inline] + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + serde::Deserializer::deserialize_identifier(deserializer, FieldVisitor) + } + } + struct Visitor<'de> { + marker: core::marker::PhantomData, + lifetime: core::marker::PhantomData<&'de ()>, + } + impl<'de> serde::de::Visitor<'de> for Visitor<'de> { + type Value = EulerRot; + fn expecting( + &self, + __formatter: &mut core::fmt::Formatter<'_>, + ) -> core::fmt::Result { + core::fmt::Formatter::write_str(__formatter, "enum EulerRot") + } + fn visit_enum(self, data: A) -> Result + where + A: serde::de::EnumAccess<'de>, + { + match serde::de::EnumAccess::variant(data)? { + (Field::ZYX, variant) => { + serde::de::VariantAccess::unit_variant(variant)?; + Ok(EulerRot::ZYX) + } + (Field::ZXY, variant) => { + serde::de::VariantAccess::unit_variant(variant)?; + Ok(EulerRot::ZXY) + } + (Field::YXZ, variant) => { + serde::de::VariantAccess::unit_variant(variant)?; + Ok(EulerRot::YXZ) + } + (Field::YZX, variant) => { + serde::de::VariantAccess::unit_variant(variant)?; + Ok(EulerRot::YZX) + } + (Field::XYZ, variant) => { + serde::de::VariantAccess::unit_variant(variant)?; + Ok(EulerRot::XYZ) + } + (Field::XZY, variant) => { + serde::de::VariantAccess::unit_variant(variant)?; + Ok(EulerRot::XZY) + } + } + } + } + const VARIANTS: &[&str] = &["ZYX", "ZXY", "YXZ", "YZX", "XYZ", "XZY"]; + serde::Deserializer::deserialize_enum( + deserializer, + "EulerRot", + VARIANTS, + Visitor { + marker: core::marker::PhantomData::, + lifetime: core::marker::PhantomData, + }, + ) + } + } +} From adf9a68b906a480477611bcd1c1a16c800ddad2e Mon Sep 17 00:00:00 2001 From: Jakob Hellermann Date: Fri, 17 Mar 2023 10:48:13 +0100 Subject: [PATCH 6/6] add test for EulerRot serialization/deserialization --- src/features/impl_serde.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/features/impl_serde.rs b/src/features/impl_serde.rs index 402875e4..547240fa 100644 --- a/src/features/impl_serde.rs +++ b/src/features/impl_serde.rs @@ -1168,4 +1168,13 @@ mod euler { ) } } + + #[test] + fn test_euler_rot_serde() { + let a = EulerRot::XYZ; + let serialized = serde_json::to_string(&a).unwrap(); + assert_eq!("\"XYZ\"", serialized); + let deserialized = serde_json::from_str(&serialized).unwrap(); + assert_eq!(a, deserialized); + } }