use core::{mem::MaybeUninit, usize};
pub trait UncheckedReader<'a>: Sized {
fn read_slice_unchecked(&mut self, size: usize) -> &'a [u8];
fn read_fixed_slice_unchecked<const N: usize>(&mut self) -> &'a [u8; N];
#[inline(always)]
fn read_unchecked<T: ReadDataUnchecked<'a>>(&mut self) -> T {
T::read_unchecked(self)
}
fn length(&self) -> usize;
}
pub trait UncheckedWriter: Sized {
fn write_slice_unchecked(&mut self, data: &[u8]);
#[inline(always)]
fn write_unchecked<T: WriteDataUnchecked>(&mut self, value: T) {
T::write_to_unchecked(value, self)
}
}
impl<'a> UncheckedReader<'a> for &'a [u8] {
#[inline(always)]
fn read_slice_unchecked(&mut self, size: usize) -> &'a [u8] {
let (data, remaining) = self.split_at(size);
*self = remaining;
data
}
#[inline(always)]
fn read_fixed_slice_unchecked<const N: usize>(&mut self) -> &'a [u8; N] {
let (data, remaining) = self.split_at(N);
*self = remaining;
data.first_chunk().unwrap()
}
fn length(&self) -> usize {
self.len()
}
}
impl<'a> UncheckedWriter for &'a mut [u8] {
#[inline(always)]
fn write_slice_unchecked(&mut self, data: &[u8]) {
let this = core::mem::take(self);
let (write_buffer, remaining) = this.split_at_mut(data.len());
*self = remaining;
write_buffer.copy_from_slice(data);
}
}
pub trait ReadDataUnchecked<'a>: Sized {
fn read_unchecked(reader: &mut impl UncheckedReader<'a>) -> Self;
}
pub trait WriteDataUnchecked {
fn write_to_unchecked(self, writer: &mut impl UncheckedWriter);
}
impl<'a, const N: usize> ReadDataUnchecked<'a> for [u8; N] {
#[inline(always)]
fn read_unchecked(reader: &mut impl UncheckedReader<'a>) -> Self {
let slice = reader.read_slice_unchecked(N);
unsafe { *slice.as_ptr().cast() }
}
}
impl<const N: usize> WriteDataUnchecked for [u8; N] {
fn write_to_unchecked(self, writer: &mut impl UncheckedWriter) {
writer.write_slice_unchecked(&self)
}
}
impl<'a, const N: usize> ReadDataUnchecked<'a> for [u16; N] {
fn read_unchecked(reader: &mut impl UncheckedReader<'a>) -> Self {
let mut read_buffer = reader.read_slice_unchecked(core::mem::size_of::<u16>() * N);
let mut write_buffer: [MaybeUninit<u16>; N] =
unsafe { MaybeUninit::uninit().assume_init() };
let read_ptr = &mut read_buffer;
for elem in write_buffer.iter_mut() {
elem.write(u16::read_unchecked(read_ptr));
}
unsafe { *write_buffer.as_ptr().cast() }
}
}
impl<const N: usize> WriteDataUnchecked for [u16; N] {
fn write_to_unchecked(self, writer: &mut impl UncheckedWriter) {
for v in self.iter() {
writer.write_unchecked(*v);
}
}
}
impl<'a> ReadDataUnchecked<'a> for u8 {
fn read_unchecked(reader: &mut impl UncheckedReader<'a>) -> Self {
reader.read_slice_unchecked(1)[0]
}
}
impl WriteDataUnchecked for u8 {
fn write_to_unchecked(self, writer: &mut impl UncheckedWriter) {
writer.write_slice_unchecked(&[self])
}
}
macro_rules! impl_read_write_data_unchecked {
($($t:ty),+) => {
$(
impl<'a> ReadDataUnchecked<'a> for $t {
#[inline(always)]
fn read_unchecked(reader: &mut impl UncheckedReader<'a>) -> $t {
let data = reader.read_unchecked();
<$t>::from_be_bytes(data)
}
}
impl WriteDataUnchecked for $t {
#[inline(always)]
fn write_to_unchecked(self, writer: &mut impl UncheckedWriter) {
let data = self.to_be_bytes();
writer.write_unchecked(data)
}
}
)*
};
}
impl_read_write_data_unchecked! {
u16,
u32,
u64
}