use {
core::{
mem::{self, transmute, MaybeUninit},
ptr,
slice::from_raw_parts,
},
thiserror::Error,
};
#[derive(Error, Debug)]
pub enum ReadError {
#[error("Attempting to read {0} bytes")]
ReadSizeLimit(usize),
#[error(
"Unsupported zero-copy operation: reader does not support deserializing zero-copy types"
)]
UnsupportedZeroCopy,
#[cfg(feature = "std")]
#[error(transparent)]
Io(#[from] std::io::Error),
}
pub type ReadResult<T> = core::result::Result<T, ReadError>;
#[cold]
const fn read_size_limit(len: usize) -> ReadError {
ReadError::ReadSizeLimit(len)
}
pub trait Reader<'a> {
type Trusted<'b>: Reader<'a>
where
Self: 'b;
fn fill_buf(&mut self, n_bytes: usize) -> ReadResult<&[u8]>;
fn fill_exact(&mut self, n_bytes: usize) -> ReadResult<&[u8]> {
let src = self.fill_buf(n_bytes)?;
if src.len() != n_bytes {
return Err(read_size_limit(n_bytes));
}
Ok(src)
}
fn fill_array<const N: usize>(&mut self) -> ReadResult<&[u8; N]> {
let src = self.fill_exact(N)?;
Ok(unsafe { &*src.as_ptr().cast::<[u8; N]>() })
}
#[inline]
fn borrow_exact(&mut self, len: usize) -> ReadResult<&'a [u8]> {
Self::borrow_exact_mut(self, len).map(|s| &*s)
}
#[expect(unused_variables)]
fn borrow_exact_mut(&mut self, len: usize) -> ReadResult<&'a mut [u8]> {
Err(ReadError::UnsupportedZeroCopy)
}
unsafe fn consume_unchecked(&mut self, amt: usize);
fn consume(&mut self, amt: usize) -> ReadResult<()>;
unsafe fn as_trusted_for(&mut self, n_bytes: usize) -> ReadResult<Self::Trusted<'_>>;
#[inline]
fn peek(&mut self) -> ReadResult<&u8> {
self.fill_buf(1)?.first().ok_or_else(|| read_size_limit(1))
}
#[inline]
fn copy_into_slice(&mut self, dst: &mut [MaybeUninit<u8>]) -> ReadResult<()> {
let src = self.fill_exact(dst.len())?;
unsafe {
ptr::copy_nonoverlapping(src.as_ptr().cast(), dst.as_mut_ptr(), dst.len());
self.consume_unchecked(dst.len());
}
Ok(())
}
#[inline]
fn copy_into_array<const N: usize>(
&mut self,
dst: &mut MaybeUninit<[u8; N]>,
) -> ReadResult<()> {
let src = self.fill_array::<N>()?;
unsafe {
ptr::copy_nonoverlapping(src, dst.as_mut_ptr(), 1);
self.consume_unchecked(N);
}
Ok(())
}
#[inline]
unsafe fn copy_into_t<T>(&mut self, dst: &mut MaybeUninit<T>) -> ReadResult<()> {
let src = self.fill_exact(size_of::<T>())?;
unsafe {
ptr::copy_nonoverlapping(src.as_ptr(), dst.as_mut_ptr().cast(), size_of::<T>());
self.consume_unchecked(size_of::<T>());
}
Ok(())
}
#[inline]
unsafe fn copy_into_slice_t<T>(&mut self, dst: &mut [MaybeUninit<T>]) -> ReadResult<()> {
let len = size_of_val(dst);
let bytes = self.fill_exact(len)?;
unsafe {
ptr::copy_nonoverlapping(bytes.as_ptr(), dst.as_mut_ptr().cast(), len);
self.consume_unchecked(len);
}
Ok(())
}
}
#[derive(Error, Debug)]
pub enum WriteError {
#[error("Attempting to write {0} bytes")]
WriteSizeLimit(usize),
#[cfg(feature = "std")]
#[error(transparent)]
Io(#[from] std::io::Error),
}
#[cold]
const fn write_size_limit(len: usize) -> WriteError {
WriteError::WriteSizeLimit(len)
}
pub type WriteResult<T> = core::result::Result<T, WriteError>;
pub trait Writer {
type Trusted<'a>: Writer
where
Self: 'a;
fn finish(&mut self) -> WriteResult<()> {
Ok(())
}
fn write(&mut self, src: &[u8]) -> WriteResult<()>;
unsafe fn as_trusted_for(&mut self, n_bytes: usize) -> WriteResult<Self::Trusted<'_>>;
#[inline]
unsafe fn write_t<T: ?Sized>(&mut self, src: &T) -> WriteResult<()> {
let src = from_raw_parts((src as *const T).cast::<u8>(), size_of_val(src));
self.write(src)?;
Ok(())
}
#[inline]
unsafe fn write_slice_t<T>(&mut self, src: &[T]) -> WriteResult<()> {
let len = size_of_val(src);
let src = from_raw_parts(src.as_ptr().cast::<u8>(), len);
self.write(src)?;
Ok(())
}
}
mod cursor;
mod slice;
#[cfg(feature = "alloc")]
mod vec;
pub use {cursor::Cursor, slice::*};