use std::borrow::Cow;
use crate::{
checkpoint::Checkpoint,
error::{ReadError, ReadResult},
};
pub mod checkpoint;
pub trait Read<'data> {
fn peek_byte(&mut self) -> ReadResult<u8>;
fn advance(&mut self, n: usize) -> ReadResult<()>;
fn read_byte(&mut self) -> ReadResult<u8>;
fn read_slice(&mut self, len: usize) -> ReadResult<Cow<'data, [u8]>>;
fn read_array<const N: usize>(&mut self) -> ReadResult<Cow<'data, [u8; N]>>;
#[inline]
fn checkpoint<'a>(&'a mut self) -> Checkpoint<'a, 'data, Self>
where
Self: Sized,
{
Checkpoint {
inner: self,
amt_read: 0,
_boo: Default::default(),
}
}
}
#[derive(Debug)]
pub struct DepthAwareReader<'data, R: Read<'data>> {
reader: R,
limit: usize,
depth: usize,
_marker: std::marker::PhantomData<&'data ()>,
}
impl<'data, R: Read<'data>> DepthAwareReader<'data, R> {
pub const DEFAULT_LIMIT: usize = 256;
#[inline(always)]
pub fn from_reader(reader: R) -> Self {
Self {
reader,
limit: Self::DEFAULT_LIMIT,
depth: 0,
_marker: Default::default(),
}
}
#[inline(always)]
pub fn from_reader_with_limit(reader: R, limit: usize) -> Self {
Self {
reader,
limit,
depth: 0,
_marker: Default::default(),
}
}
#[inline(always)]
pub fn enter(&mut self) -> ReadResult<DepthAwareReaderGuard<'_, 'data, R>> {
self.depth += 1;
if self.depth <= self.limit {
Ok(DepthAwareReaderGuard::new(self))
} else {
Err(ReadError::AllowedDepthOverflow {
depth: self.depth,
limit: self.limit,
})
}
}
}
pub struct DepthAwareReaderGuard<'a, 'data, R: Read<'data>> {
reader: &'a mut DepthAwareReader<'data, R>,
accumulated_depth: usize,
}
impl<'a, 'data, R: Read<'data>> DepthAwareReaderGuard<'a, 'data, R> {
#[inline]
fn new(rdr: &'a mut DepthAwareReader<'data, R>) -> Self {
Self {
reader: rdr,
accumulated_depth: 1,
}
}
#[inline]
pub fn enter(mut self) -> ReadResult<Self> {
self.reader.depth += 1;
self.accumulated_depth += 1;
if self.reader.depth <= self.reader.limit {
Ok(self)
} else {
Err(ReadError::AllowedDepthOverflow {
depth: self.reader.depth,
limit: self.reader.limit,
})
}
}
}
impl<'a, 'data, R: Read<'data>> Drop for DepthAwareReaderGuard<'a, 'data, R> {
#[inline(always)]
fn drop(&mut self) {
self.reader.depth -= self.accumulated_depth;
}
}
impl<'data, R: Read<'data>> Read<'data> for DepthAwareReader<'data, R> {
#[inline(always)]
fn peek_byte(&mut self) -> ReadResult<u8> {
self.reader.peek_byte()
}
#[inline(always)]
fn advance(&mut self, n: usize) -> ReadResult<()> {
self.reader.advance(n)
}
#[inline(always)]
fn read_byte(&mut self) -> ReadResult<u8> {
self.reader.read_byte()
}
#[inline(always)]
fn read_slice<'a>(&'a mut self, len: usize) -> ReadResult<Cow<'data, [u8]>> {
self.reader.read_slice(len)
}
#[inline(always)]
fn read_array<const N: usize>(&mut self) -> ReadResult<Cow<'data, [u8; N]>> {
self.reader.read_array()
}
}
impl<'data> Read<'data> for &'data [u8] {
#[inline]
fn peek_byte(&mut self) -> ReadResult<u8> {
if self.is_empty() {
return Err(ReadError::IoError(std::io::ErrorKind::UnexpectedEof));
}
Ok(unsafe { *self.as_ptr() })
}
#[inline]
fn advance(&mut self, n: usize) -> ReadResult<()> {
if n > self.len() {
return Err(ReadError::IoError(std::io::ErrorKind::UnexpectedEof));
}
*self = unsafe { std::slice::from_raw_parts(self.as_ptr().add(n), self.len() - n) };
Ok(())
}
#[inline]
fn read_byte(&mut self) -> ReadResult<u8> {
if self.is_empty() {
return Err(ReadError::IoError(std::io::ErrorKind::UnexpectedEof));
}
let ptr = self.as_ptr();
let b = unsafe { *ptr };
*self = unsafe { std::slice::from_raw_parts(ptr.add(1), self.len() - 1) };
Ok(b)
}
#[inline]
fn read_slice<'a>(&'a mut self, len: usize) -> ReadResult<Cow<'data, [u8]>> {
let Some((start, end)) = self.split_at_checked(len) else {
return Err(ReadError::IoError(std::io::ErrorKind::UnexpectedEof));
};
*self = end;
Ok(Cow::Borrowed(start))
}
#[inline]
fn read_array<const N: usize>(&mut self) -> ReadResult<Cow<'data, [u8; N]>> {
let Some((start, end)) = self.split_at_checked(N) else {
return Err(ReadError::IoError(std::io::ErrorKind::UnexpectedEof));
};
*self = end;
Ok(Cow::Borrowed(unsafe { &*start.as_ptr().cast() }))
}
}
#[derive(Debug)]
#[repr(transparent)]
pub struct StdReader<R: std::io::Read>(std::io::BufReader<R>);
impl<R: std::io::Read> StdReader<R> {
#[inline(always)]
pub fn new(buf_reader: std::io::BufReader<R>) -> Self {
Self::from(buf_reader)
}
#[inline(always)]
pub fn into_inner(self) -> std::io::BufReader<R> {
self.0
}
#[inline]
fn require_buffer_filled(&mut self, len: usize) -> Result<(), std::io::ErrorKind> {
if self.0.buffer().len() >= len {
return Ok(());
}
use std::io::BufRead as _;
let buf = self.0.fill_buf().map_err(|e| e.kind())?;
if buf.len() >= len {
Ok(())
} else {
Err(std::io::ErrorKind::UnexpectedEof)
}
}
}
impl<R: std::io::Read> From<std::io::BufReader<R>> for StdReader<R> {
#[inline(always)]
fn from(value: std::io::BufReader<R>) -> Self {
Self(value)
}
}
impl<'data, T: std::io::Read> Read<'data> for StdReader<T> {
#[inline]
fn peek_byte(&mut self) -> ReadResult<u8> {
self.require_buffer_filled(1).map_err(ReadError::IoError)?;
let b = unsafe { *self.0.buffer().as_ptr() };
Ok(b)
}
#[inline]
fn advance(&mut self, n: usize) -> ReadResult<()> {
use std::io::BufRead as _;
self.0.consume(n);
Ok(())
}
#[inline]
fn read_byte(&mut self) -> ReadResult<u8> {
use std::io::Read as _;
let mut b = 0u8;
self.0.read_exact(std::slice::from_mut(&mut b))?;
Ok(b)
}
#[inline]
fn read_slice<'a>(&'a mut self, len: usize) -> ReadResult<Cow<'data, [u8]>> {
use std::io::Read as _;
let mut buf = vec![0; len];
self.0.read_exact(&mut buf)?;
Ok(Cow::Owned(buf))
}
#[inline]
fn read_array<const N: usize>(&mut self) -> ReadResult<Cow<'data, [u8; N]>> {
use std::io::Read as _;
let mut arr = [0; N];
self.0.read_exact(&mut arr)?;
Ok(Cow::Owned(arr))
}
}
impl<T: std::io::Read> std::io::Read for StdReader<T> {
#[inline(always)]
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
self.0.read(buf)
}
}
impl<T: std::io::Read> std::io::Seek for StdReader<T>
where
T: std::io::Seek,
{
#[inline(always)]
fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
self.0.seek(pos)
}
}
impl<T: std::io::BufRead> std::io::BufRead for StdReader<T> {
#[inline(always)]
fn fill_buf(&mut self) -> std::io::Result<&[u8]> {
self.0.fill_buf()
}
#[inline(always)]
fn consume(&mut self, amount: usize) {
self.0.consume(amount)
}
}