use crate::{Error, Result};
use core::marker::PhantomData;
pub trait Flavor<'de>: 'de {
type Remainder: 'de;
type Source: 'de;
fn pop(&mut self) -> Result<u8>;
fn try_take_n(&mut self, ct: usize) -> Result<&'de [u8]>;
fn finalize(self) -> Result<Self::Remainder>;
}
pub struct Slice<'de> {
pub(crate) cursor: *const u8,
pub(crate) end: *const u8,
pub(crate) _pl: PhantomData<&'de [u8]>,
}
impl<'de> Slice<'de> {
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> {
if self.cursor == self.end {
Err(Error::DeserializeUnexpectedEnd)
} else {
unsafe {
let res = Ok(*self.cursor);
self.cursor = self.cursor.add(1);
res
}
}
}
#[inline]
fn try_take_n(&mut self, ct: usize) -> Result<&'de [u8]> {
let remain = (self.end as usize) - (self.cursor as usize);
if remain < ct {
Err(Error::DeserializeUnexpectedEnd)
} else {
unsafe {
let sli = core::slice::from_raw_parts(self.cursor, ct);
self.cursor = self.cursor.add(ct);
Ok(sli)
}
}
}
fn finalize(self) -> Result<&'de [u8]> {
let remain = (self.end as usize) - (self.cursor as usize);
unsafe { Ok(core::slice::from_raw_parts(self.cursor, remain)) }
}
}
#[cfg(any(feature = "embedded-io", feature = "use-std"))]
pub mod io {
use crate::{Error, Result};
use core::marker::PhantomData;
struct SlidingBuffer<'de> {
cursor: *mut u8,
end: *const u8,
_pl: PhantomData<&'de [u8]>,
}
impl<'de> SlidingBuffer<'de> {
pub fn new(sli: &'de mut [u8]) -> Self {
Self {
cursor: sli.as_mut_ptr(),
end: unsafe { sli.as_ptr().add(sli.len()) },
_pl: PhantomData,
}
}
#[inline]
fn take_n(&mut self, ct: usize) -> Result<&'de mut [u8]> {
let remain = (self.end as usize) - (self.cursor as usize);
let buff = if remain < ct {
return Err(Error::DeserializeUnexpectedEnd);
} else {
unsafe {
let sli = core::slice::from_raw_parts_mut(self.cursor, ct);
self.cursor = self.cursor.add(ct);
sli
}
};
Ok(buff)
}
fn complete(self) -> Result<&'de mut [u8]> {
let remain = (self.end as usize) - (self.cursor as usize);
unsafe { Ok(core::slice::from_raw_parts_mut(self.cursor, remain)) }
}
}
#[cfg(feature = "embedded-io")]
pub mod eio {
use super::super::Flavor;
use super::SlidingBuffer;
use crate::{Error, Result};
pub struct EIOReader<'de, T>
where
T: embedded_io::blocking::Read,
{
reader: T,
buff: SlidingBuffer<'de>,
}
impl<'de, T> EIOReader<'de, T>
where
T: embedded_io::blocking::Read,
{
pub(crate) fn new(reader: T, buff: &'de mut [u8]) -> Self {
Self {
reader,
buff: SlidingBuffer::new(buff),
}
}
}
impl<'de, T> Flavor<'de> for EIOReader<'de, T>
where
T: embedded_io::blocking::Read + 'de,
{
type Remainder = (T, &'de mut [u8]);
type Source = &'de [u8];
#[inline]
fn pop(&mut self) -> Result<u8> {
let mut val = [0; 1];
self.reader
.read(&mut val)
.map_err(|_| Error::DeserializeUnexpectedEnd)?;
Ok(val[0])
}
#[inline]
fn try_take_n(&mut self, ct: usize) -> Result<&'de [u8]> {
let buff = self.buff.take_n(ct)?;
self.reader
.read_exact(buff)
.map_err(|_| Error::DeserializeUnexpectedEnd)?;
Ok(buff)
}
fn finalize(self) -> Result<(T, &'de mut [u8])> {
let buf = self.buff.complete()?;
Ok((self.reader, buf))
}
}
}
#[cfg(feature = "use-std")]
pub mod io {
use super::super::Flavor;
use super::SlidingBuffer;
use crate::{Error, Result};
pub struct IOReader<'de, T>
where
T: std::io::Read,
{
reader: T,
buff: SlidingBuffer<'de>,
}
impl<'de, T> IOReader<'de, T>
where
T: std::io::Read,
{
pub(crate) fn new(reader: T, buff: &'de mut [u8]) -> Self {
Self {
reader,
buff: SlidingBuffer::new(buff),
}
}
}
impl<'de, T> Flavor<'de> for IOReader<'de, T>
where
T: std::io::Read + 'de,
{
type Remainder = (T, &'de mut [u8]);
type Source = &'de [u8];
#[inline]
fn pop(&mut self) -> Result<u8> {
let mut val = [0; 1];
self.reader
.read(&mut val)
.map_err(|_| Error::DeserializeUnexpectedEnd)?;
Ok(val[0])
}
#[inline]
fn try_take_n(&mut self, ct: usize) -> Result<&'de [u8]> {
let buff = self.buff.take_n(ct)?;
self.reader
.read_exact(buff)
.map_err(|_| Error::DeserializeUnexpectedEnd)?;
Ok(buff)
}
fn finalize(self) -> Result<(T, &'de mut [u8])> {
let buf = self.buff.complete()?;
Ok((self.reader, buf))
}
}
}
}
#[cfg(feature = "use-crc")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "use-crc")))]
pub mod crc {
use core::convert::TryInto;
use crc::Digest;
use crc::Width;
use serde::Deserialize;
use super::Flavor;
use super::Slice;
use crate::Deserializer;
use crate::Error;
use crate::Result;
use paste::paste;
pub struct CrcModifier<'de, B, W>
where
B: Flavor<'de>,
W: Width,
{
flav: B,
digest: Digest<'de, W>,
}
impl<'de, B, W> CrcModifier<'de, B, W>
where
B: Flavor<'de>,
W: Width,
{
pub fn new(bee: B, digest: Digest<'de, W>) -> Self {
Self { flav: bee, digest }
}
}
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,
}
}
#[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),
}
}
}
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)
}
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()?))
}
}
)*
};
}
impl_flavor![u8, u16, u32, u64, u128];
}