use core::fmt::Debug;
use crate::layout::{Abi, BytesOf};
use crate::{Error, Result};
mod array;
pub use array::{Array, ByteArray};
mod slice;
pub use slice::Slice;
mod chunk;
pub use chunk::Chunk;
mod span;
pub use span::Span;
pub unsafe trait Source: BytesOf {
type Slice: ?Sized + Debug + Eq + PartialEq;
type Array<const LEN: usize>: Array<LEN>;
fn read_slice(&self, size: usize) -> Result<&Self::Slice>;
fn read_slice_at(&self, offset: usize, size: usize) -> Result<&Self::Slice>;
fn read_chunk<const LEN: usize>(&self) -> Result<Self::Array<LEN>>;
fn read_chunk_at<const N: usize>(&self, offset: usize) -> Result<Self::Array<N>>;
fn source_len(&self) -> usize;
}
pub unsafe trait Buf: Source {
#[inline]
fn align_with<T: Abi>(&self) -> usize {
<*const Self>::from(self).cast::<u8>().addr() & (T::ALIGN - 1)
}
#[inline]
fn is_aligned_with<T: Abi>(&self) -> bool {
self.align_with::<T>() == 0
}
}
unsafe impl<T> Buf for T where T: Source {}
unsafe impl Source for [u8] {
type Array<const N: usize> = Chunk<N>;
type Slice = [u8];
#[inline]
fn read_slice(&self, size: usize) -> Result<&Self::Slice> {
crate::read_slice_bytes!(self, size)
}
#[inline]
fn read_slice_at(&self, offset: usize, size: usize) -> Result<&Self::Slice> {
crate::read_slice_bytes!(self, offset, size)
}
#[inline]
fn read_chunk_at<const LEN: usize>(&self, offset: usize) -> Result<Self::Array<LEN>> {
let span = Span::new(offset, LEN);
let span_size = span.len();
debug_assert_eq!(self[..LEN].len(), span_size);
let source_len = self.source_len();
if source_len < span_size {
return Err(crate::Error::out_of_bounds(span_size, source_len));
}
let bytes = unsafe {
let data = self.as_ptr().add(span.start());
core::slice::from_raw_parts(data, source_len - span.start())
};
let Ok(chunk) = Chunk::from_bytes(bytes) else {
return Err(Error::size_mismatch(LEN, source_len));
};
debug_assert!(chunk.len() == offset);
Ok(chunk)
}
#[inline]
fn read_chunk<const N: usize>(&self) -> Result<Self::Array<N>> {
crate::read_chunk_bytes!(self, N)
}
#[inline]
fn source_len(&self) -> usize {
self.len()
}
}
unsafe impl<'a, T: Abi> Source for &'a [T] {
type Slice = [u8];
type Array<const N: usize> = Chunk<N>;
#[inline]
fn read_slice(&self, size: usize) -> Result<&Self::Slice> {
crate::read_slice_bytes!(self, size)
}
#[inline]
fn read_slice_at(&self, offset: usize, size: usize) -> Result<&Self::Slice> {
crate::read_slice_bytes!(self, offset, size)
}
#[inline]
fn read_chunk<const N: usize>(&self) -> Result<Self::Array<N>> {
crate::read_chunk_bytes!(self, N)
}
#[inline]
fn read_chunk_at<const LEN: usize>(&self, offset: usize) -> Result<Self::Array<LEN>> {
let span = Span::new(offset, LEN);
let span_size = span.len();
debug_assert_eq!(self[..LEN].len(), span_size);
let source_len = self.source_len();
if source_len < span_size {
return Err(crate::Error::out_of_bounds(span_size, source_len));
}
let bytes = unsafe {
let data = self.as_ptr().add(span.start());
core::slice::from_raw_parts(data, source_len - span.start())
};
let Ok(chunk) = Chunk::from_bytes(bytes.bytes_of()) else {
return Err(Error::size_mismatch(LEN, source_len));
};
debug_assert!(chunk.len() == offset);
Ok(chunk)
}
#[inline]
fn source_len(&self) -> usize {
self.len()
}
}
unsafe impl<const N: usize> Source for [u8; N] {
type Slice = [u8];
type Array<const LEN: usize> = Chunk<LEN>;
#[inline]
fn read_slice(&self, size: usize) -> Result<&Self::Slice> {
crate::read_slice_bytes!(self, size)
}
#[inline]
fn read_slice_at(&self, offset: usize, size: usize) -> Result<&Self::Slice> {
crate::read_slice_bytes!(self, offset, size)
}
#[inline]
fn read_chunk_at<const LEN: usize>(&self, offset: usize) -> Result<Self::Array<LEN>> {
crate::read_chunk_bytes!(self, offset, LEN)
}
#[inline]
fn read_chunk<const LEN: usize>(&self) -> Result<Self::Array<LEN>> {
crate::read_chunk_bytes!(self, LEN)
}
#[inline]
fn source_len(&self) -> usize {
self.len()
}
}
unsafe impl<'source> Source for Slice<'source> {
type Array<const LEN: usize> = Chunk<LEN>;
type Slice = [u8];
#[inline]
fn read_slice_at(&self, offset: usize, size: usize) -> crate::Result<&Self::Slice> {
crate::read_slice_bytes!(self, offset, size)
}
#[inline]
fn read_slice(&self, size: usize) -> crate::Result<&Self::Slice> {
crate::read_slice_bytes!(self, size)
}
#[inline]
fn read_chunk_at<const N: usize>(&self, offset: usize) -> crate::Result<Self::Array<N>> {
crate::read_chunk_bytes!(self, offset, N)
}
#[inline]
fn read_chunk<const N: usize>(&self) -> crate::Result<Self::Array<N>> {
crate::read_chunk_bytes!(self, N)
}
#[inline]
fn source_len(&self) -> usize {
self.len()
}
}
unsafe impl<const N: usize> Source for Chunk<N> {
type Array<const LEN: usize> = Chunk<LEN>;
type Slice = [u8];
#[inline]
fn source_len(&self) -> usize {
self.as_bytes().len()
}
#[inline]
fn read_slice_at(&self, offset: usize, size: usize) -> Result<&Self::Slice> {
let span = Span::new(offset, size);
if self.source_len() < span.len() {
Err(Error::out_of_bounds(span.len(), self.source_len()))
} else {
unsafe {
let data = self.as_ptr_offset(span.start());
Ok(core::slice::from_raw_parts(data, self.source_len() - span.start()))
}
}
}
#[inline]
fn read_chunk_at<const LEN: usize>(&self, offset: usize) -> Result<Self::Array<LEN>> {
Chunk::<LEN>::from_bytes_at(self.as_bytes(), offset)
}
#[inline]
fn read_slice(&self, size: usize) -> Result<&Self::Slice> {
let span = Span::new(0, size);
if self.source_len() < span.len() {
Err(Error::out_of_bounds(span.len(), self.source_len()))
} else {
Ok(unsafe { self.as_bytes().get_unchecked(span.as_range()) })
}
}
#[inline]
fn read_chunk<const LEN: usize>(&self) -> Result<Self::Array<LEN>> {
Chunk::from_bytes(self.as_bytes())
}
}