use {
crate::error::read_length_encoding_overflow,
core::{
mem::{self, MaybeUninit, transmute},
ptr,
slice::{from_raw_parts, from_raw_parts_mut},
},
thiserror::Error,
};
#[derive(Debug, Clone, Copy)]
#[repr(u8)]
pub enum BorrowKind {
CallSite,
Backing,
BackingMut,
}
impl BorrowKind {
#[inline]
pub const fn mask(self) -> u8 {
1u8 << (self as u8)
}
}
impl core::fmt::Display for BorrowKind {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
BorrowKind::CallSite => f.write_str("call-site scoped borrows"),
BorrowKind::Backing => f.write_str("borrows extending past the call site"),
BorrowKind::BackingMut => f.write_str("mutable borrows extending past the call site"),
}
}
}
#[derive(Error, Debug)]
pub enum ReadError {
#[error("Attempting to read {0} bytes")]
ReadSizeLimit(usize),
#[error("Unsupported borrow operation: reader does not support {0}")]
UnsupportedBorrow(BorrowKind),
#[cfg(feature = "std")]
#[error(transparent)]
Io(#[from] std::io::Error),
}
pub type ReadResult<T> = core::result::Result<T, ReadError>;
#[cold]
pub const fn read_size_limit(len: usize) -> ReadError {
ReadError::ReadSizeLimit(len)
}
#[inline(always)]
pub(super) const fn transpose<const N: usize, T>(
src: &mut MaybeUninit<[T; N]>,
) -> &mut [MaybeUninit<T>; N] {
unsafe { transmute(src) }
}
pub unsafe trait Reader<'a> {
const BORROW_KINDS: u8 = 0;
#[inline]
fn supports_borrow(&self, kind: BorrowKind) -> bool {
Self::BORROW_KINDS & kind.mask() != 0
}
#[inline(always)]
fn take_array<const N: usize>(&mut self) -> ReadResult<[u8; N]> {
let mut ar = MaybeUninit::<[u8; N]>::uninit();
self.copy_into_uninit_slice(transpose(&mut ar))?;
Ok(unsafe { ar.assume_init() })
}
#[inline(always)]
fn take_byte(&mut self) -> ReadResult<u8> {
Ok(self.take_array::<1>()?[0])
}
#[expect(unused_variables)]
fn take_borrowed(&mut self, len: usize) -> ReadResult<&'a [u8]> {
Err(ReadError::UnsupportedBorrow(BorrowKind::Backing))
}
#[expect(unused_variables)]
fn take_borrowed_mut(&mut self, len: usize) -> ReadResult<&'a mut [u8]> {
Err(ReadError::UnsupportedBorrow(BorrowKind::BackingMut))
}
#[expect(unused_variables)]
fn take_scoped(&mut self, len: usize) -> ReadResult<&[u8]> {
Err(ReadError::UnsupportedBorrow(BorrowKind::CallSite))
}
#[expect(unused_variables)]
#[inline(always)]
unsafe fn as_trusted_for(&mut self, n_bytes: usize) -> ReadResult<impl Reader<'a>> {
Ok(self)
}
#[inline]
unsafe fn as_trusted_for_seq(
&mut self,
len: usize,
size: usize,
) -> Result<impl Reader<'a>, crate::error::ReadError> {
let Some(window) = len.checked_mul(size) else {
return Err(read_length_encoding_overflow("usize::MAX"));
};
Ok(unsafe { self.as_trusted_for(window) }?)
}
#[inline(always)]
fn by_ref(&mut self) -> impl Reader<'a> {
self
}
fn copy_into_slice(&mut self, dst: &mut [u8]) -> ReadResult<()>;
#[inline(always)]
fn copy_into_uninit_slice(&mut self, dst: &mut [MaybeUninit<u8>]) -> ReadResult<()> {
dst.fill(MaybeUninit::new(0));
let dst = unsafe { transmute::<&mut [MaybeUninit<u8>], &mut [u8]>(dst) };
self.copy_into_slice(dst)
}
#[inline]
unsafe fn copy_into_t<T>(&mut self, dst: &mut MaybeUninit<T>) -> ReadResult<()> {
let dst = unsafe {
from_raw_parts_mut(dst.as_mut_ptr().cast::<MaybeUninit<u8>>(), size_of::<T>())
};
self.copy_into_uninit_slice(dst)
}
#[inline]
unsafe fn copy_into_slice_t<T>(&mut self, dst: &mut [MaybeUninit<T>]) -> ReadResult<()> {
let len = size_of_val(dst);
let dst = unsafe { from_raw_parts_mut(dst.as_mut_ptr().cast::<MaybeUninit<u8>>(), len) };
self.copy_into_uninit_slice(dst)
}
}
unsafe impl<'a, R: Reader<'a> + ?Sized> Reader<'a> for &mut R {
const BORROW_KINDS: u8 = R::BORROW_KINDS;
#[inline(always)]
fn supports_borrow(&self, kind: BorrowKind) -> bool {
(**self).supports_borrow(kind)
}
#[inline(always)]
fn by_ref(&mut self) -> impl Reader<'a> {
&mut **self
}
#[inline(always)]
fn take_array<const N: usize>(&mut self) -> ReadResult<[u8; N]> {
(*self).take_array()
}
#[inline(always)]
fn take_scoped(&mut self, len: usize) -> ReadResult<&[u8]> {
(*self).take_scoped(len)
}
#[inline(always)]
fn take_borrowed(&mut self, len: usize) -> ReadResult<&'a [u8]> {
(*self).take_borrowed(len)
}
#[inline(always)]
fn take_borrowed_mut(&mut self, len: usize) -> ReadResult<&'a mut [u8]> {
(*self).take_borrowed_mut(len)
}
#[inline(always)]
fn take_byte(&mut self) -> ReadResult<u8> {
(*self).take_byte()
}
#[inline(always)]
unsafe fn as_trusted_for(&mut self, n_bytes: usize) -> ReadResult<impl Reader<'a>> {
unsafe { (*self).as_trusted_for(n_bytes) }
}
#[inline(always)]
unsafe fn as_trusted_for_seq(
&mut self,
len: usize,
size: usize,
) -> Result<impl Reader<'a>, crate::error::ReadError> {
unsafe { (*self).as_trusted_for_seq(len, size) }
}
#[inline(always)]
fn copy_into_slice(&mut self, dst: &mut [u8]) -> ReadResult<()> {
(*self).copy_into_slice(dst)
}
#[inline(always)]
fn copy_into_uninit_slice(&mut self, dst: &mut [MaybeUninit<u8>]) -> ReadResult<()> {
(*self).copy_into_uninit_slice(dst)
}
#[inline(always)]
unsafe fn copy_into_t<T>(&mut self, dst: &mut MaybeUninit<T>) -> ReadResult<()> {
unsafe { (*self).copy_into_t(dst) }
}
#[inline(always)]
unsafe fn copy_into_slice_t<T>(&mut self, dst: &mut [MaybeUninit<T>]) -> ReadResult<()> {
unsafe { (*self).copy_into_slice_t(dst) }
}
}
#[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 {
#[inline(always)]
fn by_ref(&mut self) -> impl Writer {
self
}
fn finish(&mut self) -> WriteResult<()> {
Ok(())
}
fn write(&mut self, src: &[u8]) -> WriteResult<()>;
#[expect(unused_variables)]
#[inline(always)]
unsafe fn as_trusted_for(&mut self, n_bytes: usize) -> WriteResult<impl Writer> {
struct TrustedDefault<'a, W: ?Sized> {
inner: &'a mut W,
}
impl<W: Writer + ?Sized> Writer for TrustedDefault<'_, W> {
#[inline(always)]
fn write(&mut self, src: &[u8]) -> WriteResult<()> {
self.inner.write(src)
}
#[inline(always)]
unsafe fn write_slice_t<T>(&mut self, src: &[T]) -> WriteResult<()> {
unsafe { self.inner.write_slice_t(src) }
}
#[inline(always)]
unsafe fn write_t<T: ?Sized>(&mut self, src: &T) -> WriteResult<()> {
unsafe { self.inner.write_t(src) }
}
#[inline(always)]
fn by_ref(&mut self) -> impl Writer {
TrustedDefault { inner: self.inner }
}
#[inline(always)]
unsafe fn as_trusted_for(&mut self, n_bytes: usize) -> WriteResult<impl Writer> {
Ok(TrustedDefault { inner: self.inner })
}
#[inline(always)]
fn finish(&mut self) -> WriteResult<()> {
Ok(())
}
}
Ok(TrustedDefault { inner: self })
}
#[inline]
unsafe fn write_t<T: ?Sized>(&mut self, src: &T) -> WriteResult<()> {
let src = unsafe { 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 = unsafe { from_raw_parts(src.as_ptr().cast::<u8>(), len) };
self.write(src)?;
Ok(())
}
}
impl<W: Writer + ?Sized> Writer for &mut W {
#[inline(always)]
fn by_ref(&mut self) -> impl Writer {
&mut **self
}
#[inline(always)]
fn finish(&mut self) -> WriteResult<()> {
(*self).finish()
}
#[inline(always)]
fn write(&mut self, src: &[u8]) -> WriteResult<()> {
(*self).write(src)
}
#[inline(always)]
unsafe fn as_trusted_for(&mut self, n_bytes: usize) -> WriteResult<impl Writer> {
unsafe { (*self).as_trusted_for(n_bytes) }
}
#[inline(always)]
unsafe fn write_t<T: ?Sized>(&mut self, src: &T) -> WriteResult<()> {
unsafe { (*self).write_t(src) }
}
#[inline(always)]
unsafe fn write_slice_t<T>(&mut self, src: &[T]) -> WriteResult<()> {
unsafe { (*self).write_slice_t(src) }
}
}
mod cursor;
pub mod slice;
#[cfg(feature = "std")]
pub mod std_read;
#[cfg(feature = "std")]
pub mod std_write;
#[cfg(feature = "alloc")]
mod vec;
pub use cursor::Cursor;
#[cfg(test)]
pub(crate) mod test_util;