Skip to content
Merged
Show file tree
Hide file tree
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
7 changes: 1 addition & 6 deletions source/postcard/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,6 @@ optional = true
version = "3.0.1"
optional = true

[dependencies.paste]
version = "1.0.12"
optional = true

[features]
default = ["heapless-cas"]

Expand All @@ -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!
#
Expand All @@ -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"]
161 changes: 81 additions & 80 deletions source/postcard/src/de/flavors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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>
Expand All @@ -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<u8> {
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<u8> {
match self.flav.pop() {
Ok(byte) => {
self.digest.update(&[byte]);
Ok(byte)
}
e @ Err(_) => e,
}
}

#[inline]
fn size_hint(&self) -> Option<usize> {
self.flav.size_hint()
}
#[inline]
fn size_hint(&self) -> Option<usize> {
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<Self::Remainder> {
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<Self::Remainder> {
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 [<from_bytes_ $int>]<'a, T>(s: &'a [u8], digest: Digest<'a, $int>) -> Result<T>
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<T>
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 [<take_from_bytes_ $int>]<'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);
}
136 changes: 68 additions & 68 deletions source/postcard/src/ser/flavors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand All @@ -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 = <B as Flavor>::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<Self::Output> {
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 = <B as Flavor>::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 [<to_slice_ $int>]<'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<Self::Output> {
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<u8>`, 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_ $int>]<T, const B: usize>(
value: &T,
digest: Digest<'_, $int>,
) -> Result<heapless::Vec<u8, B>>
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<u8>`, 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_ $int>]<T>(value: &T, digest: Digest<'_, $int>) -> Result<alloc::vec::Vec<u8>>
where
T: Serialize + ?Sized,
{
use super::AllocVec;

serialize_with_flavor(value, CrcModifier::new(AllocVec::new(), digest))
}
}
)*
/// Serialize a `T` to a `heapless::Vec<u8>`, 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<T, const B: usize>(
value: &T,
digest: Digest<'_, $int>,
) -> Result<heapless::Vec<u8, B>>
where
T: Serialize + ?Sized,
{
use super::HVec;
serialize_with_flavor(value, CrcModifier::new(HVec::default(), digest))
}

/// Serialize a `T` to a `heapless::Vec<u8>`, 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<T>(
value: &T,
digest: Digest<'_, $int>,
) -> Result<alloc::vec::Vec<u8>>
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
Expand Down