Skip to content

Commit

Permalink
Big cargo fmt, and rework flavors to be more consistent
Browse files Browse the repository at this point in the history
  • Loading branch information
jamesmunns committed Jun 19, 2022
1 parent 55185cd commit 20a923e
Show file tree
Hide file tree
Showing 11 changed files with 321 additions and 181 deletions.
29 changes: 19 additions & 10 deletions src/de/deserializer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ use serde::de::{
// EnumAccess, MapAccess, VariantAccess
};

use crate::de::flavors::{Flavor, Slice};
use crate::error::{Error, Result};
use crate::varint::varint_max;
use core::marker::PhantomData;
use crate::de::flavors::{Flavor, Slice};

/// A structure for deserializing a postcard message. For now, Deserializer does not
/// implement the same Flavor interface as the serializer does, as messages are typically
Expand All @@ -22,25 +22,34 @@ pub struct Deserializer<'de, F: Flavor<'de>> {
_plt: PhantomData<&'de ()>,
}

impl<'de> Deserializer<'de, Slice<'de>> {
impl<'de, F> Deserializer<'de, F>
where
F: Flavor<'de> + 'de,
{
/// Obtain a Deserializer from a slice of bytes
pub fn from_bytes(input: &'de [u8]) -> Self {
pub fn from_flavor(flavor: F) -> Self {
Deserializer {
flavor: Slice {
cursor: input.as_ptr(),
end: unsafe { input.as_ptr().add(input.len()) },
_pl: PhantomData,
},
flavor,
_plt: PhantomData,
}
}

/// Return the remaining (unused) bytes in the Deserializer
pub fn remaining(self) -> Result<&'de [u8]> {
pub fn remaining(self) -> Result<F::Remainder> {
self.flavor.remaining()
}
}

impl<'de> Deserializer<'de, Slice<'de>> {
/// Obtain a Deserializer from a slice of bytes
pub fn from_bytes(input: &'de [u8]) -> Self {
Deserializer {
flavor: Slice::new(input),
_plt: PhantomData,
}
}
}

impl<'de, F: Flavor<'de>> Deserializer<'de, F> {
#[cfg(target_pointer_width = "32")]
#[inline(always)]
Expand Down Expand Up @@ -352,7 +361,7 @@ impl<'de, 'a, F: Flavor<'de>> de::Deserializer<'de> for &'a mut Deserializer<'de
}
let bytes: &'de [u8] = self.flavor.try_take_n(sz)?;
// we pass the character through string conversion because
// this handles transforming the array of code units to a
// this handles transforming the array of code units to a
// codepoint. we can't use char::from_u32() because it expects
// an already-processed codepoint.
let character = core::str::from_utf8(&bytes)
Expand Down
137 changes: 134 additions & 3 deletions src/de/flavors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@
//!
//! Docs TO-DO!
use crate::{Result, Error};
use crate::{Error, Result};
use core::marker::PhantomData;

/// TODO
pub trait Flavor<'de>: 'de {
/// TODO
type Remainder: 'de;
/// TODO
type Source: 'de;

/// TODO
fn pop(&mut self) -> Result<u8>;
Expand All @@ -27,8 +29,20 @@ pub struct Slice<'de> {
pub(crate) _pl: PhantomData<&'de [u8]>,
}

impl<'de> Slice<'de> {
/// TODO
pub fn new(sli: &'de [u8]) -> Self {
Self {
cursor: sli.as_ptr(),
end: unsafe { sli.as_ptr().add(sli.len()) },
_pl: PhantomData,
}
}
}

impl<'de> Flavor<'de> for Slice<'de> {
type Remainder = &'de [u8];
type Source = &'de [u8];

#[inline]
fn pop(&mut self) -> Result<u8> {
Expand Down Expand Up @@ -60,8 +74,125 @@ impl<'de> Flavor<'de> for Slice<'de> {
/// Return the remaining (unused) bytes in the Deserializer
fn remaining(self) -> Result<&'de [u8]> {
let remain = (self.end as usize) - (self.cursor as usize);
unsafe {
Ok(core::slice::from_raw_parts(self.cursor, remain))
unsafe { Ok(core::slice::from_raw_parts(self.cursor, remain)) }
}
}

// Write a terrible checksum implementation to make sure that we can effectively
// use the deserialization flavor. This is kept as a test (and not published)
// because an 8-bit checksum is not ACTUALLY useful for almost anything.
//
// You could certainly do something similar with a CRC32, cryptographic sig,
// or something else
#[cfg(test)]
mod test {
use super::*;
use serde::{Deserialize, Serialize};


struct Checksum<'de, F>
where
F: Flavor<'de> + 'de,
{
flav: F,
checksum: u8,
_plt: PhantomData<&'de ()>,
}

impl<'de, F> Checksum<'de, F>
where
F: Flavor<'de> + 'de,
{
pub fn from_flav(flav: F) -> Self {
Self {
flav,
checksum: 0,
_plt: PhantomData,
}
}
}

impl<'de, F> Flavor<'de> for Checksum<'de, F>
where
F: Flavor<'de> + 'de,
{
type Remainder = (<F as Flavor<'de>>::Remainder, u8);
type Source = F;

fn pop(&mut self) -> Result<u8> {
match self.flav.pop() {
Ok(u) => {
self.checksum = self.checksum.wrapping_add(u);
Ok(u)
}
Err(e) => Err(e),
}
}
fn try_take_n(&mut self, ct: usize) -> Result<&'de [u8]> {
match self.flav.try_take_n(ct) {
Ok(u) => {
u.iter().for_each(|u| {
self.checksum = self.checksum.wrapping_add(*u);
});
Ok(u)
}
Err(e) => Err(e),
}
}
fn remaining(self) -> Result<Self::Remainder> {
Ok((self.flav.remaining()?, self.checksum))
}
}

#[derive(Serialize, Deserialize, PartialEq, Eq, Debug)]
pub struct SomeData<'a> {
#[serde(borrow)]
sli: &'a [u8],
sts: &'a str,
foo: u64,
bar: u128,
}

#[test]
fn smoke() {
const EXPECTED: &[u8] = &[
4, 255, 1, 34, 51, 19, 116, 104, 105, 115, 32, 105, 115, 32, 97, 32, 103, 111, 111,
100, 32, 116, 101, 115, 116, 170, 213, 170, 213, 170, 213, 170, 213, 170, 1, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 127,
];

// Calculate simple 8-bit checksum
let mut check: u8 = 0;
EXPECTED.iter().for_each(|u| check = check.wrapping_add(*u));

let mut buf = [0u8; 256];
let data = SomeData {
sli: &[0xFF, 0x01, 0x22, 0x33],
sts: "this is a good test",
foo: (u64::MAX / 3) * 2,
bar: u128::MAX / 4,
};
let used = crate::to_slice(&data, &mut buf).unwrap();
assert_eq!(used, EXPECTED);
let used = used.len();

// Put the checksum at the end
buf[used] = check;

let mut deser = crate::de::Deserializer::from_flavor(Checksum::from_flav(Slice::new(&buf)));

let t = SomeData::<'_>::deserialize(&mut deser).unwrap();
assert_eq!(t, data);

// Normally, you'd probably expect the check
let (rem, cksm) = deser.remaining().unwrap();

// The pre-calculated checksum we stuffed at the end is the
// first "unused" byte
assert_eq!(rem[0], check);

// the one we calculated during serialization matches the
// pre-calculated one
assert_eq!(cksm, check);
}
}
39 changes: 20 additions & 19 deletions src/de/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,10 @@ where
#[cfg(test)]
mod test_heapless {
use super::*;
use crate::{
ser::to_vec,
varint::varint_max, to_vec_cobs,
};
use crate::{ser::to_vec, to_vec_cobs, varint::varint_max};
use core::fmt::Write;
use core::ops::Deref;
use heapless::{String, Vec, FnvIndexMap};
use heapless::{FnvIndexMap, String, Vec};
use serde::{Deserialize, Deserializer, Serialize, Serializer};

#[test]
Expand All @@ -89,7 +86,7 @@ mod test_heapless {

#[test]
fn de_u16() {
let output: Vec<u8, {varint_max::<u16>()}> = to_vec(&0xA5C7u16).unwrap();
let output: Vec<u8, { varint_max::<u16>() }> = to_vec(&0xA5C7u16).unwrap();
assert!(&[0xC7, 0xCB, 0x02] == output.deref());

let out: u16 = from_bytes(output.deref()).unwrap();
Expand All @@ -98,7 +95,7 @@ mod test_heapless {

#[test]
fn de_u32() {
let output: Vec<u8, {varint_max::<u32>()}> = to_vec(&0xCDAB3412u32).unwrap();
let output: Vec<u8, { varint_max::<u32>() }> = to_vec(&0xCDAB3412u32).unwrap();
assert_eq!(&[0x92, 0xE8, 0xAC, 0xED, 0x0C], output.deref());

let out: u32 = from_bytes(output.deref()).unwrap();
Expand All @@ -107,7 +104,7 @@ mod test_heapless {

#[test]
fn de_u64() {
let output: Vec<u8, {varint_max::<u64>()}> = to_vec(&0x1234_5678_90AB_CDEFu64).unwrap();
let output: Vec<u8, { varint_max::<u64>() }> = to_vec(&0x1234_5678_90AB_CDEFu64).unwrap();
assert!(&[0xEF, 0x9B, 0xAF, 0x85, 0x89, 0xCF, 0x95, 0x9A, 0x12] == output.deref());

let out: u64 = from_bytes(output.deref()).unwrap();
Expand All @@ -116,7 +113,8 @@ mod test_heapless {

#[test]
fn de_u128() {
let output: Vec<u8, {varint_max::<u128>()}> = to_vec(&0x1234_5678_90AB_CDEF_1234_5678_90AB_CDEFu128).unwrap();
let output: Vec<u8, { varint_max::<u128>() }> =
to_vec(&0x1234_5678_90AB_CDEF_1234_5678_90AB_CDEFu128).unwrap();
assert!(
&[
0xEF, 0x9B, 0xAF, 0x85, 0x89, 0xCF, 0x95, 0x9A, 0x92, 0xDE, 0xB7, 0xDE, 0x8A, 0x92,
Expand Down Expand Up @@ -157,11 +155,9 @@ mod test_heapless {

assert_eq!(
&[
0xCD, 0xD7, 0x02,
0xFE,
0xBA, 0xB9, 0xB7, 0xDE, 0x9A, 0xE4, 0x90, 0x9A, 0x92, 0xF4, 0xF2, 0xEE, 0xBC, 0xB5, 0xC8, 0xA1, 0xB4, 0x24,
0xBA, 0xB9, 0xB7, 0xDE, 0x9A, 0xE4, 0x90, 0x9A, 0x12,
0xAC, 0xD9, 0xB2, 0xE5, 0x0A
0xCD, 0xD7, 0x02, 0xFE, 0xBA, 0xB9, 0xB7, 0xDE, 0x9A, 0xE4, 0x90, 0x9A, 0x92, 0xF4,
0xF2, 0xEE, 0xBC, 0xB5, 0xC8, 0xA1, 0xB4, 0x24, 0xBA, 0xB9, 0xB7, 0xDE, 0x9A, 0xE4,
0x90, 0x9A, 0x12, 0xAC, 0xD9, 0xB2, 0xE5, 0x0A
],
output.deref()
);
Expand Down Expand Up @@ -252,13 +248,15 @@ mod test_heapless {
let out: BasicEnum = from_bytes(output.deref()).unwrap();
assert_eq!(out, BasicEnum::Bim);

let output: Vec<u8, {1 + varint_max::<u64>()}> = to_vec(&DataEnum::Bim(u64::max_value())).unwrap();
let output: Vec<u8, { 1 + varint_max::<u64>() }> =
to_vec(&DataEnum::Bim(u64::max_value())).unwrap();
assert_eq!(
&[0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01],
output.deref()
);

let output: Vec<u8, {1 + varint_max::<u16>()}> = to_vec(&DataEnum::Bib(u16::max_value())).unwrap();
let output: Vec<u8, { 1 + varint_max::<u16>() }> =
to_vec(&DataEnum::Bib(u16::max_value())).unwrap();
assert_eq!(&[0x00, 0xFF, 0xFF, 0x03], output.deref());
let out: DataEnum = from_bytes(output.deref()).unwrap();
assert_eq!(out, DataEnum::Bib(u16::max_value()));
Expand Down Expand Up @@ -382,7 +380,7 @@ mod test_heapless {

#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
pub struct TupleStruct((u8, u16));

#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
pub struct DualTupleStruct(u8, u16);

Expand All @@ -397,7 +395,7 @@ mod test_heapless {
assert_eq!(&[0xA0, 0xB4, 0x24], output.deref());
let out: TupleStruct = from_bytes(output.deref()).unwrap();
assert_eq!(out, TupleStruct((0xA0, 0x1234)));

let output: Vec<u8, 3> = to_vec(&DualTupleStruct(0xA0, 0x1234)).unwrap();
assert_eq!(&[0xA0, 0xB4, 0x24], output.deref());
let out: DualTupleStruct = from_bytes(output.deref()).unwrap();
Expand Down Expand Up @@ -465,7 +463,10 @@ mod test_heapless {
input.insert(0x03, 0x07).unwrap();
input.insert(0x04, 0x08).unwrap();
let output: Vec<u8, 100> = to_vec(&input).unwrap();
assert_eq!(&[0x04, 0x01, 0x05, 0x02, 0x06, 0x03, 0x07, 0x04, 0x08], output.deref());
assert_eq!(
&[0x04, 0x01, 0x05, 0x02, 0x06, 0x03, 0x07, 0x04, 0x08],
output.deref()
);
let out: FnvIndexMap<u8, u8, 4> = from_bytes(output.deref()).unwrap();
assert_eq!(input, out);
}
Expand Down
2 changes: 1 addition & 1 deletion src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ impl Display for Error {
DeserializeBadEncoding => "The original data was not well encoded",
SerdeSerCustom => "Serde Serialization Error",
SerdeDeCustom => "Serde Deserialization Error",
CollectStrError => "Error while processing `collect_str` during serialization"
CollectStrError => "Error while processing `collect_str` during serialization",
}
)
}
Expand Down
2 changes: 1 addition & 1 deletion src/fixint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ pub struct FixintLE<T: sealed::Fixed>(pub T);
pub struct FixintBE<T: sealed::Fixed>(pub T);

mod sealed {
pub trait Fixed { }
pub trait Fixed {}
}

macro_rules! impl_fixint {
Expand Down
10 changes: 5 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,8 @@
//! Licensed under either of
//!
//! - Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or
//! http://www.apache.org/licenses/LICENSE-2.0)
//! - MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
//! <http://www.apache.org/licenses/LICENSE-2.0>)
//! - MIT license ([LICENSE-MIT](LICENSE-MIT) or <http://opensource.org/licenses/MIT>)
//!
//! at your option.
//!
Expand All @@ -183,18 +183,18 @@
mod accumulator;
mod de;
mod error;
mod fixint;
mod ser;
mod varint;
mod fixint;

pub use accumulator::{CobsAccumulator, FeedResult};
pub use de::deserializer::Deserializer;
pub use de::flavors as de_flavors;
pub use de::{from_bytes, from_bytes_cobs, take_from_bytes, take_from_bytes_cobs};
pub use error::{Error, Result};
pub use ser::{serialize_with_flavor, serializer::Serializer, to_slice, to_slice_cobs};
pub use fixint::{FixintBE, FixintLE};
pub use ser::flavors as ser_flavors;
pub use de::flavors as de_flavors;
pub use ser::{serialize_with_flavor, serializer::Serializer, to_slice, to_slice_cobs};

#[cfg(feature = "heapless")]
pub use ser::{to_vec, to_vec_cobs};
Expand Down
Loading

0 comments on commit 20a923e

Please sign in to comment.