use crate::region::{AllocOrd, Pull, RegionBuffer, RegionError, Seed};
use crate::frame::FrameError;
use core::mem::MaybeUninit;
#[inline]
pub fn get<T>(bearer: &mut impl DecodeBearer) -> Result<T, DecodeError>
where
T: Decode,
{
let mut slot = MaybeUninit::<T>::uninit();
T::decode(bearer, &mut slot)?;
Ok(unsafe {
slot.assume_init()
})
}
#[derive(Debug, thiserror::Error)]
pub enum ReadError {
#[error("Requested length out of bounds")]
OutOfBounds,
#[cfg(feature = "std")]
#[error(transparent)]
Io(#[from] std::io::Error),
}
pub type ReadResult<T> = Result<T, ReadError>;
pub trait Reader {
fn read_borrow(&self, n: usize) -> ReadResult<&[u8]>;
fn advance(&mut self, n: usize);
fn read_borrow_const<const N: usize>(&self) -> ReadResult<[u8; N]> {
let mut buf = [0u8; N];
buf.copy_from_slice(self.read_borrow(N)?);
Ok(buf)
}
}
impl Reader for &[u8] {
fn read_borrow(&self, n: usize) -> ReadResult<&[u8]> {
self.get(..n).ok_or(ReadError::OutOfBounds)
}
#[inline]
fn advance(&mut self, n: usize) {
*self = self
.get(n..)
.expect("Attempt to advance a Reader with overflow")
}
}
impl Reader for &mut [u8] {
fn read_borrow(&self, n: usize) -> ReadResult<&[u8]> {
self.get(..n).ok_or(ReadError::OutOfBounds)
}
#[inline]
fn advance(&mut self, n: usize) {
*self = core::mem::take(self)
.get_mut(n..)
.expect("Attempt to advance a Reader with overflow")
}
}
mod private {
pub trait Sealed {}
impl<R: super::Reader> Sealed for super::StreamDecoder<R> {}
}
pub trait DecodeBearer: private::Sealed {
fn read(&mut self, n: usize) -> Result<&[u8], RegionError>;
}
pub struct StreamDecoder<R>
where
R: Reader,
{
region_buffer: RegionBuffer,
authority: Pull<R>,
}
impl<R> StreamDecoder<R>
where
R: Reader,
{
pub fn new(src: R, seed: Seed, ord: AllocOrd) -> Result<Self, RegionError> {
let mut bearer = Self {
region_buffer: RegionBuffer::new(ord.cap()),
authority: Pull::new(src, seed),
};
bearer.region_buffer.pass(&mut bearer.authority)?;
Ok(bearer)
}
pub fn relocate(&mut self, src: R) -> Result<(), RegionError> {
self.relocate_with_seed(src, self.authority.seed())
}
pub fn relocate_with_seed(&mut self, src: R, seed: Seed) -> Result<(), RegionError> {
self.authority = Pull::new(src, seed);
self.region_buffer.pass(&mut self.authority)
}
}
impl<R> DecodeBearer for StreamDecoder<R>
where
R: Reader,
{
#[inline]
fn read(&mut self, n: usize) -> Result<&[u8], RegionError> {
if self.region_buffer.remaining_len() < n {
self.region_buffer.swap();
self.region_buffer.pass(&mut self.authority)?;
}
self.region_buffer.read(n).ok_or(RegionError::OutOfBounds)
}
}
#[derive(Debug, thiserror::Error)]
pub enum DecodeError {
#[error("Frame decoding error: \"{0}\"")]
FrameError(#[from] FrameError),
#[error("Decode bearer error: \"{0}\"")]
BearerError(#[from] RegionError),
#[error("Invalid pattern")]
InvalidPattern,
#[error("{0}")]
Other(&'static str),
}
pub unsafe trait Decode
where
Self: Sized,
{
fn decode(
bearer: &mut impl DecodeBearer,
dst: &mut MaybeUninit<Self>,
) -> Result<(), DecodeError>;
}