diff --git a/Cargo.toml b/Cargo.toml index ff55c83..ef3bdba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,9 +15,11 @@ documentation = "https://docs.rs/rend" [dependencies] bytecheck = { version = "0.8", optional = true, default-features = false } +serde = { version = "1.0.210", default-features = false, features = ["derive"], optional = true } [features] default = [] +serde = ["dep:serde"] [patch.crates-io] bytecheck = { git = "https://github.com/rkyv/bytecheck" } diff --git a/src/common.rs b/src/common.rs index 968d3d6..2cdd757 100644 --- a/src/common.rs +++ b/src/common.rs @@ -68,6 +68,7 @@ macro_rules! impl_signed_integer_traits { impl_binassign!(SubAssign::sub_assign for $name: $prim); impl_fmt!(UpperExp for $name); impl_fmt!(UpperHex for $name); + impl_serde!(for $name: $prim); }; } @@ -114,6 +115,7 @@ macro_rules! impl_unsigned_integer_traits { impl_binassign!(SubAssign::sub_assign for $name: $prim); impl_fmt!(UpperExp for $name); impl_fmt!(UpperHex for $name); + impl_serde!(for $name: $prim); }; } @@ -192,6 +194,7 @@ macro_rules! impl_float { impl_binassign!(RemAssign::rem_assign for $name: $prim); impl_binop!(Sub::sub for $name: $prim); impl_binassign!(SubAssign::sub_assign for $name: $prim); + impl_serde!(for $name: $prim); impl_fmt!(UpperExp for $name); }; } diff --git a/src/lib.rs b/src/lib.rs index 7f204f7..a068b12 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,6 +13,8 @@ //! ## Features //! //! - `bytecheck`: Enables support for validating types using `bytecheck`. +//! - `serde`: Derives [`serde::Serialize`] and [`serde::Deserialize`] for types +//! that support it. //! //! ## Example: #![doc = include_str!("../example.md")] diff --git a/src/traits.rs b/src/traits.rs index 4637d7f..675306e 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -386,3 +386,58 @@ macro_rules! unsafe_impl_check_bytes_noop { } }; } + +macro_rules! impl_serde { + (for $name:ident : $prim:ty) => { + #[cfg(feature = "serde")] + impl serde::Serialize for $name { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + serializer + .serialize_bytes(self.to_native().to_ne_bytes().as_slice()) + } + } + + #[cfg(feature = "serde")] + impl<'de> serde::Deserialize<'de> for $name { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + struct Visitor {} + impl<'v> serde::de::Visitor<'v> for Visitor { + type Value = $name; + + fn expecting( + &self, + formatter: &mut core::fmt::Formatter, + ) -> core::fmt::Result { + formatter.write_str( + "Expecting native-endian bytes for deserializing \ + endian-aware type", + ) + } + fn visit_bytes(self, v: &[u8]) -> Result + where + E: serde::de::Error, + { + let v = <$prim>::from_ne_bytes(match v.try_into() { + Ok(v) => v, + Err(_) => { + return Err(serde::de::Error::custom( + "Could not convert bytes to primitive \ + type's `from_ne_bytes`", + )) + } + }); + + Ok($name::from_native(v)) + } + } + deserializer.deserialize_bytes(Visitor {}) + } + } + }; +}