use crate::serialize::reader::*;
pub struct BufReader<'r> {
data: &'r [u8],
pos: usize,
}
macro_rules! read_int {
[ $($read:ident($nbytes:expr): $ty:ty),* $(,)? ] => { $(
#[inline]
fn $read(&mut self) -> ReadResult<$ty> {
let input = self.get_input($nbytes)?;
let mut bytes = [0u8; $nbytes];
unsafe { core::ptr::copy_nonoverlapping(input.as_ptr(), bytes.as_mut_ptr(), $nbytes) };
let n = <$ty>::from_be_bytes(bytes);
Ok(n)
}
)* };
}
impl<'a> BufReader<'a> {
pub fn new(data: &'a [u8]) -> Self {
let pos = 0;
Self { data, pos }
}
pub fn position(&self) -> usize {
self.pos
}
pub fn remaining(&self) -> usize {
self.data.len() - self.pos
}
pub fn remaining_slice(&self) -> &'a [u8] {
&self.data[self.pos..]
}
#[inline]
fn get_input(&mut self, requested: usize) -> ReadResult<&'a [u8]> {
let Some(extent) = self
.pos
.checked_add(requested)
.filter(|&e| e <= self.data.len())
else {
let remaining: usize = self.data.len() - self.pos;
return Err(ReadError::source_empty(requested, remaining));
};
let buf = unsafe { self.data.get_unchecked(self.pos..extent) };
self.pos = extent;
Ok(buf)
}
}
unsafe impl<'r> Reader<'r> for BufReader<'r> {
#[inline]
fn read_opaque_fixed(&mut self, len: usize) -> ReadResult<&'r [u8]> {
let rem = len % 4;
if rem == 0 {
return self.get_input(len);
}
let padlen = 4 - rem;
let combined = len.checked_add(padlen).ok_or_else(|| {
ReadError::source_empty(usize::MAX, self.data.len() - self.pos)
})?;
let buf = self.get_input(combined)?;
let payload = unsafe { buf.get_unchecked(..len) };
#[cfg(not(feature = "permissive"))]
if unsafe { buf.get_unchecked(len..) }.iter().any(|&b| b != 0) {
return Err(ReadError::non_zero_padding());
}
Ok(payload)
}
#[inline]
fn read_opaque_variable(&mut self, max: u32) -> ReadResult<&'r [u8]> {
let len = self.read_u32()?;
if len > max {
return Err(ReadError::max_length_exceeded());
}
self.read_opaque_fixed(len as usize)
}
#[inline]
fn read_i16(&mut self) -> ReadResult<i16> {
let n = self.read_i32()?;
#[cfg(not(feature = "permissive"))]
if n < i16::MIN as i32 || n > i16::MAX as i32 {
return Err(ReadError::integer_out_of_range());
}
Ok(n as i16)
}
#[inline]
fn read_u16(&mut self) -> ReadResult<u16> {
let n = self.read_u32()?;
#[cfg(not(feature = "permissive"))]
if n < u16::MIN as u32 || n > u16::MAX as u32 {
return Err(ReadError::integer_out_of_range());
}
Ok(n as u16)
}
read_int! [
read_u64(8): u64,
read_u32(4): u32,
read_i64(8): i64,
read_i32(4): i32,
];
#[inline]
fn read_f32(&mut self) -> ReadResult<f32> {
let input = self.get_input(4)?;
let mut bytes = [0u8; 4];
unsafe { core::ptr::copy_nonoverlapping(input.as_ptr(), bytes.as_mut_ptr(), 4) };
Ok(f32::from_be_bytes(bytes))
}
#[inline]
fn read_f64(&mut self) -> ReadResult<f64> {
let input = self.get_input(8)?;
let mut bytes = [0u8; 8];
unsafe { core::ptr::copy_nonoverlapping(input.as_ptr(), bytes.as_mut_ptr(), 8) };
Ok(f64::from_be_bytes(bytes))
}
}