//! Binary data conversion utilities. use crate::durandal::err::*; use serde::Serialize; use std::{fmt, num::NonZeroU16}; #[doc(hidden)] macro_rules! rd_1 { // big endian (BE $b:ident $nam:ident u16 $n:expr) => { rd_1!($b u16::from_be_bytes, $nam 2 $n); }; (BE $b:ident $nam:ident i16 $n:expr) => { rd_1!($b i16::from_be_bytes, $nam 2 $n); }; (BE $b:ident $nam:ident u32 $n:expr) => { rd_1!($b u32::from_be_bytes, $nam 4 $n); }; (BE $b:ident $nam:ident i32 $n:expr) => { rd_1!($b i32::from_be_bytes, $nam 4 $n); }; (BE $b:ident $nam:ident as usize u16 $n:expr) => { rd_1!($b u16::from_be_bytes, $nam 2 $n); let $nam = $nam as usize; }; (BE $b:ident $nam:ident as usize u32 $n:expr) => { rd_1!($b u32::from_be_bytes, $nam 4 $n); let $nam = $nam as usize; }; (BE $b:ident $nam:ident Angle $n:expr) => { rd_1!($b u16::from_be_bytes, $nam 2 $n); let $nam = Angle::from_bits($nam); }; (BE $b:ident $nam:ident Fixed $n:expr) => { rd_1!($b u32::from_be_bytes, $nam 4 $n); let $nam = Fixed::from_bits($nam); }; (BE $b:ident $nam:ident Unit $n:expr) => { rd_1!($b u16::from_be_bytes, $nam 2 $n); let $nam = Unit::from_bits($nam); }; (BE $b:ident $nam:ident OptU16 $n:expr) => { rd_1!($b u16::from_be_bytes, $nam 2 $n); let $nam = OptU16::from_repr($nam); }; // little endian (LE $b:ident $nam:ident u16 $n:expr) => { rd_1!($b u16::from_le_bytes $nam 2 $n); }; (LE $b:ident $nam:ident i16 $n:expr) => { rd_1!($b i16::from_le_bytes $nam 2 $n); }; (LE $b:ident $nam:ident u32 $n:expr) => { rd_1!($b u32::from_le_bytes $nam 4 $n); }; (LE $b:ident $nam:ident i32 $n:expr) => { rd_1!($b i32::from_le_bytes $nam 4 $n); }; (LE $b:ident $nam:ident as usize u16 $n:expr) => { rd_1!($b u16::from_le_bytes $nam 2 $n); let $nam = $nam as usize; }; (LE $b:ident $nam:ident as usize u32 $n:expr) => { rd_1!($b u32::from_le_bytes $nam 4 $n); let $nam = $nam as usize; }; // generic endianness ($_:ident $b:ident $nam:ident u8 $n:expr) => { let $nam = $b[$n]; }; ($_:ident $b:ident $nam:ident array u8 $n:expr) => { let $nam = &$b[$n]; }; ($_:ident $b:ident $nam:ident i8 $n:expr) => { let $nam = $b[$n] as i8; }; ($_:ident $b:ident $nam:ident iden $n:expr) => { let $nam = [$b[$n], $b[$n + 1], $b[$n + 2], $b[$n + 3]]; }; ($_:ident $b:ident $nam:ident $f:ident $n:expr) => { let $nam = $f(&$b[$n])?; }; ($_:ident $b:ident $nam:ident nt $f:ident $n:expr) => { let $nam = $f(&$b[$n]); }; // worker - creates let statement ($b:ident $pth:path , $nam:ident 2 $n:expr) => { let $nam = $pth([$b[$n], $b[$n + 1]]); }; ($b:ident $pth:path , $nam:ident 4 $n:expr) => { let $nam = $pth([$b[$n], $b[$n + 1], $b[$n + 2], $b[$n + 3]]); }; } macro_rules! read_data { ( $sz:expr , $ty:ident in $b:ident => $( $nam:ident = $t:ident [ $n:expr ] $( $ex:ident )* ; )* ) => { if $b.len() < $sz { bail!("not enough data"); } $(rd_1!($ty $b $nam $($ex)* $t $n);)* }; } pub fn ident(b: &[u8]) -> Ident {[b[0], b[1], b[2], b[3]]} pub fn u32b(b: &[u8]) -> u32 {u32::from_be_bytes([b[0], b[1], b[2], b[3]])} pub fn u16b(b: &[u8]) -> u16 {u16::from_be_bytes([b[0], b[1]])} pub fn i32b(b: &[u8]) -> i32 {i32::from_be_bytes([b[0], b[1], b[2], b[3]])} pub fn i16b(b: &[u8]) -> i16 {i16::from_be_bytes([b[0], b[1]])} pub fn rd_array(b: &[u8], read: F) -> ResultS> where T: Sized, F: Fn(&[u8]) -> ResultS<(T, usize)> { let mut v = Vec::new(); let mut p = 0; while p < b.len() { let (r, s) = read(&b[p..])?; v.push(r); p += s; } Ok(v) } pub fn rd_ofstable(b: &[u8], mut p: usize, num: usize, read: F) -> ResultS> where T: Sized, F: Fn(&[u8]) -> ResultS { let mut v = Vec::with_capacity(num); for _ in 0..num { let ofs = u32b(&b[p..]) as usize; if ofs >= b.len() { bail!("not enough data"); } v.push(read(&b[ofs..])?); p += 4; } Ok(v) } impl OptU16 { /// Creates an `OptU16` from a `u16`. pub fn from_repr(n: u16) -> Self { if n == u16::max_value() { Self(None) } else { Self(NonZeroU16::new(n + 1)) } } /// Returns the `u16` representation of an `OptU16`. pub fn get_repr(&self) -> u16 { match self.0 { None => u16::max_value(), Some(n) => n.get() - 1, } } /// Returns the `Option` representation of an `OptU16`. pub fn get(&self) -> Option { match self.0 { None => None, Some(n) => Some(n.get() - 1), } } } impl fmt::Debug for OptU16 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.get() { None => write!(f, "None"), Some(n) => write!(f, "Some({})", n), } } } /// A four-character-code identifier. pub type Ident = [u8; 4]; /// An object identified by a `u16` which may be `u16::max_value()` to /// represent None. #[derive(Serialize)] pub struct OptU16(Option); // EOF