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 size_hint(&self) -> Option<usize> {
None
}
fn try_take_n(&mut self, ct: usize) -> Result<&'de [u8]>;
fn try_take_n_temp<'a>(&'a mut self, ct: usize) -> Result<&'a [u8]>
where
'de: 'a,
{
self.try_take_n(ct)
}
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 {
let range = sli.as_ptr_range();
Self {
cursor: range.start,
end: range.end,
_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 size_hint(&self) -> Option<usize> {
Some((self.end as usize) - (self.cursor as usize))
}
#[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-04",
feature = "embedded-io-06",
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 {
let range = sli.as_mut_ptr_range();
Self {
cursor: range.start,
end: range.end,
_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)
}
#[inline]
fn take_n_temp(&mut self, ct: usize) -> Result<&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);
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(any(feature = "embedded-io-04", feature = "embedded-io-06"))]
pub mod eio {
use super::super::Flavor;
use super::SlidingBuffer;
use crate::{Error, Result};
pub struct EIOReader<'de, T>
where
T: crate::eio::Read,
{
reader: T,
buff: SlidingBuffer<'de>,
}
impl<'de, T> EIOReader<'de, T>
where
T: crate::eio::Read,
{
pub 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: crate::eio::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_exact(&mut val)
.map_err(|_| Error::DeserializeUnexpectedEnd)?;
Ok(val[0])
}
#[inline]
fn size_hint(&self) -> Option<usize> {
None
}
#[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)
}
#[inline]
fn try_take_n_temp<'a>(&'a mut self, ct: usize) -> Result<&'a [u8]>
where
'de: 'a,
{
let buff = self.buff.take_n_temp(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(test)]
mod tests {
use super::*;
#[test]
fn test_pop() {
let mut reader = EIOReader::new(&[0xAA, 0xBB, 0xCC][..], &mut []);
assert_eq!(reader.pop(), Ok(0xAA));
assert_eq!(reader.pop(), Ok(0xBB));
assert_eq!(reader.pop(), Ok(0xCC));
assert_eq!(reader.pop(), Err(Error::DeserializeUnexpectedEnd));
}
#[test]
fn test_try_take_n() {
let mut buf = [0; 8];
let mut reader = EIOReader::new(&[0xAA, 0xBB, 0xCC, 0xDD, 0xEE][..], &mut buf);
assert_eq!(reader.try_take_n(2), Ok(&[0xAA, 0xBB][..]));
assert_eq!(reader.try_take_n(2), Ok(&[0xCC, 0xDD][..]));
assert_eq!(reader.try_take_n(2), Err(Error::DeserializeUnexpectedEnd));
}
}
}
#[allow(clippy::module_inception)]
#[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 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_exact(&mut val)
.map_err(|_| Error::DeserializeUnexpectedEnd)?;
Ok(val[0])
}
#[inline]
fn size_hint(&self) -> Option<usize> {
None
}
#[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)
}
#[inline]
fn try_take_n_temp<'a>(&'a mut self, ct: usize) -> Result<&'a [u8]>
where
'de: 'a,
{
let buff = self.buff.take_n_temp(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(test)]
mod tests {
use super::*;
#[test]
fn test_pop() {
let mut reader = IOReader::new(&[0xAA, 0xBB, 0xCC][..], &mut []);
assert_eq!(reader.pop(), Ok(0xAA));
assert_eq!(reader.pop(), Ok(0xBB));
assert_eq!(reader.pop(), Ok(0xCC));
assert_eq!(reader.pop(), Err(Error::DeserializeUnexpectedEnd));
}
#[test]
fn test_try_take_n() {
let mut buf = [0; 8];
let mut reader = IOReader::new(&[0xAA, 0xBB, 0xCC, 0xDD, 0xEE][..], &mut buf);
assert_eq!(reader.try_take_n(2), Ok(&[0xAA, 0xBB][..]));
assert_eq!(reader.try_take_n(2), Ok(&[0xCC, 0xDD][..]));
assert_eq!(reader.try_take_n(2), Err(Error::DeserializeUnexpectedEnd));
}
}
}
}
#[cfg(feature = "use-crc")]
#[cfg_attr(docsrs, 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;
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, $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 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<'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<'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, 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);
}