use core::{convert::Infallible, marker::PhantomData};
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct UnexpectedEnd;
impl core::fmt::Display for UnexpectedEnd {
#[inline]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str("UnexpectedEnd")
}
}
pub trait Flavor<'de>: 'de {
type Remainder: 'de;
type Source: 'de;
type PopError: core::fmt::Debug + core::fmt::Display;
type FinalizeError: core::fmt::Debug + core::fmt::Display;
fn pop(&mut self) -> Result<u8, Self::PopError>;
fn size_hint(&self) -> Option<usize> {
None
}
fn try_take_n(&mut self, ct: usize) -> Result<&'de [u8], Self::PopError>;
fn try_take_n_temp<'a>(&'a mut self, ct: usize) -> Result<&'a [u8], Self::PopError>
where
'de: 'a,
{
self.try_take_n(ct)
}
fn finalize(self) -> Result<Self::Remainder, Self::FinalizeError>;
}
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];
type PopError = UnexpectedEnd;
type FinalizeError = Infallible;
#[inline]
fn pop(&mut self) -> Result<u8, Self::PopError> {
if self.cursor == self.end {
Err(UnexpectedEnd)
} 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], Self::PopError> {
let remain = (self.end as usize) - (self.cursor as usize);
if remain < ct {
Err(UnexpectedEnd)
} 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], Infallible> {
let remain = (self.end as usize) - (self.cursor as usize);
unsafe { Ok(core::slice::from_raw_parts(self.cursor, remain)) }
}
}
#[cfg(feature = "std")]
pub mod io {
use crate::de_flavors::UnexpectedEnd;
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], UnexpectedEnd> {
let remain = (self.end as usize) - (self.cursor as usize);
let buff = if remain < ct {
return Err(UnexpectedEnd);
} 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], UnexpectedEnd> {
let remain = (self.end as usize) - (self.cursor as usize);
let buff = if remain < ct {
return Err(UnexpectedEnd);
} else {
unsafe { core::slice::from_raw_parts_mut(self.cursor, ct) }
};
Ok(buff)
}
fn complete(self) -> &'de mut [u8] {
let remain = (self.end as usize) - (self.cursor as usize);
unsafe { core::slice::from_raw_parts_mut(self.cursor, remain) }
}
}
#[allow(clippy::module_inception)]
#[cfg(feature = "std")]
pub mod io {
use super::super::Flavor;
use super::SlidingBuffer;
use crate::de_flavors::UnexpectedEnd;
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];
type PopError = UnexpectedEnd;
type FinalizeError = core::convert::Infallible;
#[inline]
fn pop(&mut self) -> Result<u8, UnexpectedEnd> {
let mut val = [0; 1];
self.reader
.read_exact(&mut val)
.map_err(|_| UnexpectedEnd)?;
Ok(val[0])
}
#[inline]
fn size_hint(&self) -> Option<usize> {
None
}
#[inline]
fn try_take_n(&mut self, ct: usize) -> Result<&'de [u8], UnexpectedEnd> {
let buff = self.buff.take_n(ct)?;
self.reader.read_exact(buff).map_err(|_| UnexpectedEnd)?;
Ok(buff)
}
#[inline]
fn try_take_n_temp<'a>(&'a mut self, ct: usize) -> Result<&'a [u8], UnexpectedEnd>
where
'de: 'a,
{
let buff = self.buff.take_n_temp(ct)?;
self.reader.read_exact(buff).map_err(|_| UnexpectedEnd)?;
Ok(buff)
}
fn finalize(self) -> Result<(T, &'de mut [u8]), core::convert::Infallible> {
Ok((self.reader, self.buff.complete()))
}
}
#[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));
}
}
}
}