use crate::{
CpIndex,
error::{Error, Result},
};
#[derive(Debug, Clone, Copy)]
pub struct Cursor<'a>(&'a [u8]);
impl<'a> Cursor<'a> {
pub fn new(bytes: &'a [u8]) -> Self {
Self(bytes)
}
pub fn remaining(&self) -> &'a [u8] {
self.0
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
}
impl<'a> From<&'a [u8]> for Cursor<'a> {
fn from(value: &'a [u8]) -> Self {
Self::new(value)
}
}
macro_rules! read_int {
($($name:ident -> $type:ty),* $(,)?) => {$(
fn $name(&mut self) -> Result<$type> {
let mut buf = [0u8; size_of::<$type>()];
buf.copy_from_slice(self.read_bytes(size_of::<$type>())?);
Ok(<$type>::from_be_bytes(buf))
}
)*};
}
pub trait ReadBytes<'a> {
fn read_bytes(&mut self, len: usize) -> Result<&'a [u8]>;
fn read_rest(&mut self) -> &'a [u8];
read_int! {
read_u8 -> u8,
read_u16 -> u16,
read_u32 -> u32,
read_u64 -> u64,
read_i32 -> i32,
read_i64 -> i64,
}
fn read_f32(&mut self) -> Result<f32> {
Ok(f32::from_bits(self.read_u32()?))
}
fn read_f64(&mut self) -> Result<f64> {
Ok(f64::from_bits(self.read_u64()?))
}
fn repeat_by_u16<T>(&mut self, mut fun: impl FnMut(&mut Self) -> Result<T>) -> Result<Vec<T>>
where
Self: Sized,
{
let count = self.read_u16()?;
let mut items = Vec::with_capacity(count as usize);
for _ in 0..count {
items.push(fun(self)?);
}
Ok(items)
}
fn repeat_by_u8<T>(&mut self, mut fun: impl FnMut(&mut Self) -> Result<T>) -> Result<Vec<T>>
where
Self: Sized,
{
let count = self.read_u8()?;
let mut items = Vec::with_capacity(count as usize);
for _ in 0..count {
items.push(fun(self)?);
}
Ok(items)
}
fn read_indices(&mut self) -> Result<Vec<CpIndex>>
where
Self: Sized,
{
self.repeat_by_u16(|cursor| cursor.read_u16())
}
fn read_optional_index(&mut self) -> Result<Option<CpIndex>> {
let index = self.read_u16()?;
Ok((index != 0).then_some(index))
}
}
impl<'a> ReadBytes<'a> for Cursor<'a> {
fn read_bytes(&mut self, len: usize) -> Result<&'a [u8]> {
match self.0.split_at_checked(len) {
Some((head, tail)) => {
self.0 = tail;
Ok(head)
}
None => Err(Error::UnexpectedEof {
needed: len,
available: self.0.len(),
}),
}
}
fn read_rest(&mut self) -> &'a [u8] {
std::mem::take(&mut self.0)
}
}