use std::convert::TryInto;
#[derive(Clone, Debug)]
pub struct Reader<'a> {
data: &'a [u8],
offset: usize,
}
impl<'a> Reader<'a> {
#[inline]
pub fn new(data: &'a [u8]) -> Self {
Self { data, offset: 0 }
}
#[inline]
pub fn new_at(data: &'a [u8], offset: usize) -> Self {
Self { data, offset }
}
#[inline]
pub fn tail(&self) -> Option<&'a [u8]> {
self.data.get(self.offset..)
}
#[inline]
pub fn offset(&self) -> usize {
self.offset
}
#[inline]
pub fn read<T: Readable<'a>>(&mut self) -> Option<T> {
T::read(self)
}
#[inline]
pub fn peak<T: Readable<'a>>(&mut self) -> Option<T> {
let mut r = self.clone();
T::read(&mut r)
}
#[inline]
pub fn read_bytes(&mut self, len: usize) -> Option<&'a [u8]> {
let v = self.data.get(self.offset..self.offset + len)?;
self.offset += len;
Some(v)
}
#[inline]
pub fn read_array16<T: Readable<'a>>(
&mut self,
count: u16,
) -> Option<LazyArray16<'a, T>> {
let len = usize::from(count) * T::SIZE;
self.read_bytes(len).map(LazyArray16::new)
}
#[inline]
pub fn skip<T: Readable<'a>>(&mut self) {
self.skip_bytes(T::SIZE);
}
#[inline]
pub fn at_end(&self) -> bool {
self.offset >= self.data.len()
}
#[inline]
pub fn jump(&mut self, offset: usize) {
self.offset = offset;
}
#[inline]
pub fn skip_bytes(&mut self, n: usize) {
self.read_bytes(n);
}
}
pub trait Readable<'a>: Sized {
const SIZE: usize;
fn read(r: &mut Reader<'a>) -> Option<Self>;
}
impl<const N: usize> Readable<'_> for [u8; N] {
const SIZE: usize = u8::SIZE * N;
fn read(r: &mut Reader) -> Option<Self> {
Some(r.read_bytes(N)?.try_into().unwrap_or([0; N]))
}
}
impl Readable<'_> for u8 {
const SIZE: usize = 1;
fn read(r: &mut Reader) -> Option<Self> {
r.read::<[u8; 1]>().map(Self::from_be_bytes)
}
}
impl Readable<'_> for u16 {
const SIZE: usize = 2;
fn read(r: &mut Reader) -> Option<Self> {
r.read::<[u8; 2]>().map(Self::from_be_bytes)
}
}
impl Readable<'_> for i16 {
const SIZE: usize = 2;
fn read(r: &mut Reader) -> Option<Self> {
r.read::<[u8; 2]>().map(Self::from_be_bytes)
}
}
impl Readable<'_> for u32 {
const SIZE: usize = 4;
fn read(r: &mut Reader) -> Option<Self> {
r.read::<[u8; 4]>().map(Self::from_be_bytes)
}
}
impl Readable<'_> for i32 {
const SIZE: usize = 4;
fn read(r: &mut Reader) -> Option<Self> {
r.read::<[u8; 4]>().map(Self::from_be_bytes)
}
}
#[derive(Clone, Copy)]
pub struct LazyArray16<'a, T> {
data: &'a [u8],
data_type: core::marker::PhantomData<T>,
}
impl<T> Default for LazyArray16<'_, T> {
#[inline]
fn default() -> Self {
LazyArray16 { data: &[], data_type: core::marker::PhantomData }
}
}
impl<'a, T: Readable<'a>> LazyArray16<'a, T> {
#[inline]
pub fn new(data: &'a [u8]) -> Self {
LazyArray16 { data, data_type: core::marker::PhantomData }
}
#[inline]
pub fn get(&self, index: u16) -> Option<T> {
if index < self.len() {
let start = usize::from(index) * T::SIZE;
let end = start + T::SIZE;
self.data
.get(start..end)
.map(Reader::new)
.and_then(|mut r| T::read(&mut r))
} else {
None
}
}
#[inline]
pub fn len(&self) -> u16 {
(self.data.len() / T::SIZE) as u16
}
}
impl<'a, T: Readable<'a> + core::fmt::Debug + Copy> core::fmt::Debug
for LazyArray16<'a, T>
{
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
f.debug_list().entries(*self).finish()
}
}
impl<'a, T: Readable<'a>> IntoIterator for LazyArray16<'a, T> {
type Item = T;
type IntoIter = LazyArrayIter16<'a, T>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
LazyArrayIter16 { data: self, index: 0 }
}
}
#[derive(Clone, Copy)]
#[allow(missing_debug_implementations)]
pub struct LazyArrayIter16<'a, T> {
data: LazyArray16<'a, T>,
index: u16,
}
impl<'a, T: Readable<'a>> Default for LazyArrayIter16<'a, T> {
#[inline]
fn default() -> Self {
LazyArrayIter16 { data: LazyArray16::new(&[]), index: 0 }
}
}
impl<'a, T: Readable<'a>> Iterator for LazyArrayIter16<'a, T> {
type Item = T;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.index += 1;
self.data.get(self.index - 1)
}
#[inline]
fn count(self) -> usize {
usize::from(self.data.len().saturating_sub(self.index))
}
}