diff --git a/source/postcard/Cargo.toml b/source/postcard/Cargo.toml index 7a4e9b8c..729afafa 100644 --- a/source/postcard/Cargo.toml +++ b/source/postcard/Cargo.toml @@ -61,10 +61,6 @@ optional = true version = "3.0.1" optional = true -[dependencies.paste] -version = "1.0.12" -optional = true - [features] default = ["heapless-cas"] @@ -80,7 +76,7 @@ use-std = ["serde/std", "alloc"] heapless-cas = ["heapless", "dep:heapless", "heapless/cas"] alloc = ["serde/alloc", "embedded-io-04?/alloc", "embedded-io-06?/alloc"] use-defmt = ["defmt"] -use-crc = ["crc", "paste"] +use-crc = ["crc"] # Experimental features! # @@ -89,5 +85,4 @@ experimental-derive = ["postcard-derive"] crc = ["dep:crc"] defmt = ["dep:defmt"] heapless = ["dep:heapless"] -paste = ["dep:paste"] postcard-derive = ["dep:postcard-derive"] diff --git a/source/postcard/src/de/flavors.rs b/source/postcard/src/de/flavors.rs index cb079932..cc46d6fb 100644 --- a/source/postcard/src/de/flavors.rs +++ b/source/postcard/src/de/flavors.rs @@ -5,7 +5,7 @@ //! //! 1. The source medium of the deserialization, e.g. whether the data is serialized from a `[u8]` slice, or some other container //! 2. The format of the deserialization, such as if the original data is encoded in a COBS format, contains a CRC32 checksum -//! appended to the message, etc. +//! appended to the message, etc. //! //! Flavors are implemented using the [`Flavor`] trait, which acts as a "middleware" for retrieving the bytes before they //! are passed to `serde` for deserialization @@ -458,7 +458,6 @@ pub mod crc { use crate::Deserializer; use crate::Error; use crate::Result; - use paste::paste; /// Manages CRC modifications as a flavor. pub struct CrcModifier<'de, B, W> @@ -482,94 +481,96 @@ pub mod crc { } macro_rules! impl_flavor { - ($( $int:ty ),*) => { - $( - paste! { - impl<'de, B> Flavor<'de> for CrcModifier<'de, B, $int> - where - B: Flavor<'de>, - { - type Remainder = B::Remainder; - - type Source = B::Source; - - #[inline] - fn pop(&mut self) -> Result { - match self.flav.pop() { - Ok(byte) => { - self.digest.update(&[byte]); - Ok(byte) - } - e @ Err(_) => e, - } + ($int:ty, $from_bytes:ident, $take_from_bytes:ident) => { + impl<'de, B> Flavor<'de> for CrcModifier<'de, B, $int> + where + B: Flavor<'de>, + { + type Remainder = B::Remainder; + type Source = B::Source; + + #[inline] + fn pop(&mut self) -> Result { + match self.flav.pop() { + Ok(byte) => { + self.digest.update(&[byte]); + Ok(byte) } + e @ Err(_) => e, + } + } - #[inline] - fn size_hint(&self) -> Option { - self.flav.size_hint() - } + #[inline] + fn size_hint(&self) -> Option { + self.flav.size_hint() + } - #[inline] - fn try_take_n(&mut self, ct: usize) -> Result<&'de [u8]> { - match self.flav.try_take_n(ct) { - Ok(bytes) => { - self.digest.update(bytes); - Ok(bytes) - } - e @ Err(_) => e, - } + #[inline] + fn try_take_n(&mut self, ct: usize) -> Result<&'de [u8]> { + match self.flav.try_take_n(ct) { + Ok(bytes) => { + self.digest.update(bytes); + Ok(bytes) } + e @ Err(_) => e, + } + } - fn finalize(mut self) -> Result { - match self.flav.try_take_n(core::mem::size_of::<$int>()) { - Ok(prev_crc_bytes) => match self.flav.finalize() { - Ok(remainder) => { - let crc = self.digest.finalize(); - let le_bytes = prev_crc_bytes - .try_into() - .map_err(|_| Error::DeserializeBadEncoding)?; - let prev_crc = <$int>::from_le_bytes(le_bytes); - if crc == prev_crc { - Ok(remainder) - } else { - Err(Error::DeserializeBadCrc) - } - } - e @ Err(_) => e, - }, - Err(e) => Err(e), + fn finalize(mut self) -> Result { + match self.flav.try_take_n(core::mem::size_of::<$int>()) { + Ok(prev_crc_bytes) => match self.flav.finalize() { + Ok(remainder) => { + let crc = self.digest.finalize(); + let le_bytes = prev_crc_bytes + .try_into() + .map_err(|_| Error::DeserializeBadEncoding)?; + let prev_crc = <$int>::from_le_bytes(le_bytes); + if crc == prev_crc { + Ok(remainder) + } else { + Err(Error::DeserializeBadCrc) + } } - } + e @ Err(_) => e, + }, + Err(e) => Err(e), } + } + } - /// Deserialize a message of type `T` from a byte slice with a Crc. The unused portion (if any) - /// of the byte slice is not returned. - pub fn []<'a, T>(s: &'a [u8], digest: Digest<'a, $int>) -> Result - where - T: Deserialize<'a>, - { - let flav = CrcModifier::new(Slice::new(s), digest); - let mut deserializer = Deserializer::from_flavor(flav); - let r = T::deserialize(&mut deserializer)?; - let _ = deserializer.finalize()?; - Ok(r) - } + /// Deserialize a message of type `T` from a byte slice with a Crc. The unused portion (if any) + /// of the byte slice is not returned. + pub fn $from_bytes<'a, T>(s: &'a [u8], digest: Digest<'a, $int>) -> Result + where + T: Deserialize<'a>, + { + let flav = CrcModifier::new(Slice::new(s), digest); + let mut deserializer = Deserializer::from_flavor(flav); + let r = T::deserialize(&mut deserializer)?; + let _ = deserializer.finalize()?; + Ok(r) + } - /// Deserialize a message of type `T` from a byte slice with a Crc. The unused portion (if any) - /// of the byte slice is returned for further usage - pub fn []<'a, T>(s: &'a [u8], digest: Digest<'a, $int>) -> Result<(T, &'a [u8])> - where - T: Deserialize<'a>, - { - let flav = CrcModifier::new(Slice::new(s), digest); - let mut deserializer = Deserializer::from_flavor(flav); - let t = T::deserialize(&mut deserializer)?; - Ok((t, deserializer.finalize()?)) - } - } - )* + /// Deserialize a message of type `T` from a byte slice with a Crc. The unused portion (if any) + /// of the byte slice is returned for further usage + pub fn $take_from_bytes<'a, T>( + s: &'a [u8], + digest: Digest<'a, $int>, + ) -> Result<(T, &'a [u8])> + where + T: Deserialize<'a>, + { + let flav = CrcModifier::new(Slice::new(s), digest); + let mut deserializer = Deserializer::from_flavor(flav); + let t = T::deserialize(&mut deserializer)?; + Ok((t, deserializer.finalize()?)) + } }; } - impl_flavor![u8, u16, u32, u64, u128]; + impl_flavor!(u8, from_bytes_u8, take_from_bytes_u8); + impl_flavor!(u16, from_bytes_u16, take_from_bytes_u16); + impl_flavor!(u32, from_bytes_u32, take_from_bytes_u32); + impl_flavor!(u64, from_bytes_u64, take_from_bytes_u64); + impl_flavor!(u128, from_bytes_u128, take_from_bytes_u128); } diff --git a/source/postcard/src/ser/flavors.rs b/source/postcard/src/ser/flavors.rs index 7bca90ef..069fb0b2 100644 --- a/source/postcard/src/ser/flavors.rs +++ b/source/postcard/src/ser/flavors.rs @@ -585,7 +585,6 @@ pub mod crc { use crate::serialize_with_flavor; use crate::Result; - use paste::paste; /// Manages CRC modifications as a flavor. pub struct CrcModifier<'a, B, W> @@ -609,80 +608,81 @@ pub mod crc { } macro_rules! impl_flavor { - ($( $int:ty ),*) => { - $( - paste! { - impl<'a, B> Flavor for CrcModifier<'a, B, $int> - where - B: Flavor, - { - type Output = ::Output; - - #[inline(always)] - fn try_push(&mut self, data: u8) -> Result<()> { - self.digest.update(&[data]); - self.flav.try_push(data) - } - - fn finalize(mut self) -> Result { - let crc = self.digest.finalize(); - for byte in crc.to_le_bytes() { - self.flav.try_push(byte)?; - } - self.flav.finalize() - } - } + ($int:ty, $to_slice:ident, $to_vec:ident, $to_allocvec:ident) => { + impl<'a, B> Flavor for CrcModifier<'a, B, $int> + where + B: Flavor, + { + type Output = ::Output; + + #[inline(always)] + fn try_push(&mut self, data: u8) -> Result<()> { + self.digest.update(&[data]); + self.flav.try_push(data) + } - /// Serialize a `T` to the given slice, with the resulting slice containing - /// data followed by a CRC. The CRC bytes are included in the output buffer. - /// - /// When successful, this function returns the slice containing the - /// serialized and encoded message. - pub fn []<'a, T>( - value: &T, - buf: &'a mut [u8], - digest: Digest<'_, $int>, - ) -> Result<&'a mut [u8]> - where - T: Serialize + ?Sized, - { - serialize_with_flavor(value, CrcModifier::new(Slice::new(buf), digest)) + fn finalize(mut self) -> Result { + let crc = self.digest.finalize(); + for byte in crc.to_le_bytes() { + self.flav.try_push(byte)?; } + self.flav.finalize() + } + } - /// Serialize a `T` to a `heapless::Vec`, with the `Vec` containing - /// data followed by a CRC. The CRC bytes are included in the output `Vec`. - #[cfg(feature = "heapless")] - #[cfg_attr(docsrs, doc(cfg(feature = "heapless")))] - pub fn []( - value: &T, - digest: Digest<'_, $int>, - ) -> Result> - where - T: Serialize + ?Sized, - { - use super::HVec; - - serialize_with_flavor(value, CrcModifier::new(HVec::default(), digest)) - } + /// Serialize a `T` to the given slice, with the resulting slice containing + /// data followed by a CRC. The CRC bytes are included in the output buffer. + /// + /// When successful, this function returns the slice containing the + /// serialized and encoded message. + pub fn $to_slice<'a, T>( + value: &T, + buf: &'a mut [u8], + digest: Digest<'_, $int>, + ) -> Result<&'a mut [u8]> + where + T: Serialize + ?Sized, + { + serialize_with_flavor(value, CrcModifier::new(Slice::new(buf), digest)) + } - /// Serialize a `T` to a `heapless::Vec`, with the `Vec` containing - /// data followed by a CRC. The CRC bytes are included in the output `Vec`. - #[cfg(feature = "alloc")] - #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] - pub fn [](value: &T, digest: Digest<'_, $int>) -> Result> - where - T: Serialize + ?Sized, - { - use super::AllocVec; - - serialize_with_flavor(value, CrcModifier::new(AllocVec::new(), digest)) - } - } - )* + /// Serialize a `T` to a `heapless::Vec`, with the `Vec` containing + /// data followed by a CRC. The CRC bytes are included in the output `Vec`. + #[cfg(feature = "heapless")] + #[cfg_attr(docsrs, doc(cfg(feature = "heapless")))] + pub fn $to_vec( + value: &T, + digest: Digest<'_, $int>, + ) -> Result> + where + T: Serialize + ?Sized, + { + use super::HVec; + serialize_with_flavor(value, CrcModifier::new(HVec::default(), digest)) + } + + /// Serialize a `T` to a `heapless::Vec`, with the `Vec` containing + /// data followed by a CRC. The CRC bytes are included in the output `Vec`. + #[cfg(feature = "alloc")] + #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] + pub fn $to_allocvec( + value: &T, + digest: Digest<'_, $int>, + ) -> Result> + where + T: Serialize + ?Sized, + { + use super::AllocVec; + serialize_with_flavor(value, CrcModifier::new(AllocVec::new(), digest)) + } }; } - impl_flavor![u8, u16, u32, u64, u128]; + impl_flavor!(u8, to_slice_u8, to_vec_u8, to_allocvec_u8); + impl_flavor!(u16, to_slice_u16, to_vec_u16, to_allocvec_u16); + impl_flavor!(u32, to_slice_u32, to_vec_u32, to_allocvec_u32); + impl_flavor!(u64, to_slice_u64, to_vec_u64, to_allocvec_u64); + impl_flavor!(u128, to_slice_u128, to_vec_u128, to_allocvec_u128); } /// The `Size` flavor is a measurement flavor, which accumulates the number of bytes needed to