use std::borrow::Borrow;
use std::panic::Location;
use super::endian::{BigEndian, EndianAgnostic, LittleEndian, NativeEndian};
use super::Reader;
use crate::Result;
pub trait Parser: Reader {
#[track_caller]
#[inline]
fn u8(&mut self) -> Result<u8> {
let mut buffer = [0u8; 1];
self.read_into_tracked(&mut buffer, Location::caller())?;
Ok(buffer[0])
}
fn eu16<E: EndianAgnostic>(&mut self, caller: &'static Location) -> Result<u16> {
let mut buffer = [0u8; 2];
self.read_into_tracked(&mut buffer, caller)?;
Ok(E::u16_from_bytes(&buffer))
}
fn eu32<E: EndianAgnostic>(&mut self, caller: &'static Location) -> Result<u32> {
let mut buffer = [0u8; 4];
self.read_into_tracked(&mut buffer, caller)?;
Ok(E::u32_from_bytes(&buffer))
}
#[track_caller]
#[inline]
fn u16(&mut self) -> Result<u16> {
self.eu16::<NativeEndian>(Location::caller())
}
#[track_caller]
#[inline]
fn u32(&mut self) -> Result<u32> {
self.eu32::<NativeEndian>(Location::caller())
}
#[track_caller]
#[inline]
fn bu16(&mut self) -> Result<u16> {
self.eu16::<BigEndian>(Location::caller())
}
#[track_caller]
#[inline]
fn bu32(&mut self) -> Result<u32> {
self.eu32::<BigEndian>(Location::caller())
}
#[track_caller]
#[inline]
fn lu16(&mut self) -> Result<u16> {
self.eu16::<LittleEndian>(Location::caller())
}
#[track_caller]
#[inline]
fn lu32(&mut self) -> Result<u32> {
self.eu32::<LittleEndian>(Location::caller())
}
#[track_caller]
fn str<const L: usize, E: ParseStringEncoding>(&mut self) -> Result<String> {
let mut buffer = [0u8; L];
self.read_into_tracked(&mut buffer, Location::caller())?;
E::parse_str(buffer)
}
#[track_caller]
#[inline]
fn u8_array<const L: usize>(&mut self) -> Result<[u8; L]> {
self.read_buffer_of_tracked::<u8, L>(Location::caller())
}
#[inline]
fn eu16_array<E: EndianAgnostic, const L: usize>(
&mut self,
caller: &'static Location,
) -> Result<[u16; L]> {
let mut buf = self.read_buffer_of_tracked::<u16, L>(caller)?;
for value in buf.iter_mut().take(L) {
*value = E::u16_from_native(*value);
}
Ok(buf)
}
#[track_caller]
#[inline]
fn bu16_array<const L: usize>(&mut self) -> Result<[u16; L]> {
self.eu16_array::<BigEndian, L>(Location::caller())
}
#[track_caller]
#[inline]
fn lu16_array<const L: usize>(&mut self) -> Result<[u16; L]> {
self.eu16_array::<LittleEndian, L>(Location::caller())
}
#[inline]
fn eu32_array<E: EndianAgnostic, const L: usize>(
&mut self,
caller: &'static Location,
) -> Result<[u32; L]> {
let mut buf = self.read_buffer_of_tracked::<u32, L>(caller)?;
for value in buf.iter_mut().take(L) {
*value = E::u32_from_native(*value);
}
Ok(buf)
}
#[track_caller]
#[inline]
fn bu32_array<const L: usize>(&mut self) -> Result<[u32; L]> {
self.eu32_array::<BigEndian, L>(Location::caller())
}
#[track_caller]
#[inline]
fn lu32_array<const L: usize>(&mut self) -> Result<[u32; L]> {
self.eu32_array::<LittleEndian, L>(Location::caller())
}
}
impl<Base: Reader> Parser for Base {}
pub trait ParseStringEncoding {
fn parse_str<I>(data: I) -> Result<String>
where
I: IntoIterator,
I::Item: Borrow<u8> + Sized;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn u8() {
let mut data: &[u8] = &[0x01, 0x02, 0x03, 0x04];
assert_eq!(data.u8().unwrap(), 0x01);
assert_eq!(data.u8().unwrap(), 0x02);
assert_eq!(data.u8().unwrap(), 0x03);
assert_eq!(data.u8().unwrap(), 0x04);
}
#[test]
fn u16() {
let mut data: &[u8] = &[0x01, 0x02, 0x01, 0x02];
assert_eq!(data.bu16().unwrap(), 0x0102);
assert_eq!(data.lu16().unwrap(), 0x0201);
}
#[test]
fn u32() {
let mut data: &[u8] = &[0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04];
assert_eq!(data.bu32().unwrap(), 0x01020304);
assert_eq!(data.lu32().unwrap(), 0x04030201);
}
#[test]
fn u8_array() {
let mut data: &[u8] = &[0x01, 0x02, 0x03, 0x04];
assert_eq!(data.u8_array::<4>().unwrap(), [
0x01, 0x02, 0x03, 0x04
]);
}
#[test]
fn u16_array() {
let mut data: &[u8] = &[0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04];
assert_eq!(data.bu16_array::<2>().unwrap(), [
0x0102, 0x0304,
]);
assert_eq!(data.lu16_array::<2>().unwrap(), [
0x0201, 0x0403,
]);
}
#[test]
fn u32_array() {
let mut data: &[u8] = &[
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
0x07, 0x08,
];
assert_eq!(data.bu32_array::<2>().unwrap(), [
0x01020304, 0x05060708
]);
assert_eq!(data.lu32_array::<2>().unwrap(), [
0x04030201, 0x08070605
]);
}
}