use super::Alignment;
use crate::TypedValue;
use std::ffi::CStr;
impl<'a> TypedValue<'a> {
fn parse_fix_sized_data<T: Sized + 'static, F: Fn(&'a [T]) -> TypedValue<'a>>(
cursor: &'a [u8],
count: usize,
f: F,
) -> Option<(TypedValue, &'a [u8])> {
if count * std::mem::size_of::<T>() > cursor.len() {
return None;
}
Some((
f(unsafe { std::slice::from_raw_parts(&cursor[0] as *const u8 as *const T, count) }),
&cursor[std::mem::size_of::<T>() * count..],
))
}
fn parse_typed_value(cursor: &'a [u8], count: usize) -> Option<(TypedValue<'a>, &'a [u8])> {
use TypedValue::*;
match cursor[0] {
b'c' => Self::parse_fix_sized_data(&cursor[1..], count, I8),
b'C' | b'A' => Self::parse_fix_sized_data(&cursor[1..], count, U8),
b's' => Self::parse_fix_sized_data(&cursor[1..], count, I16),
b'S' => Self::parse_fix_sized_data(&cursor[1..], count, U16),
b'i' => Self::parse_fix_sized_data(&cursor[1..], count, I32),
b'I' => Self::parse_fix_sized_data(&cursor[1..], count, U32),
b'f' => Self::parse_fix_sized_data(&cursor[1..], count, F),
_ => None,
}
}
fn parse_aux_data(cursor: &'a [u8]) -> Option<(TypedValue<'a>, &'a [u8])> {
match cursor.get(0)? {
b'H' | b'Z' => {
let value = unsafe { CStr::from_ptr(&cursor[1..] as *const _ as *const i8) };
let length = value.to_bytes().len();
Some((TypedValue::Str(value), &cursor[2 + length..]))
}
b'B' => {
let size =
u32::from_le_bytes([cursor[1], cursor[2], cursor[3], cursor[4]]) as usize;
Self::parse_typed_value(&cursor[5..], size)
}
_ => Self::parse_typed_value(cursor, 1),
}
}
}
pub struct AuxDataIter<'a> {
data: &'a [u8],
offset: usize,
}
impl<'a> Iterator for AuxDataIter<'a> {
type Item = ([u8; 2], TypedValue<'a>);
fn next(&mut self) -> Option<Self::Item> {
if self.offset + 2 > self.data.len() {
return None;
}
let label = [self.data[self.offset], self.data[self.offset + 1]];
let (data, rem) = TypedValue::parse_aux_data(&self.data[self.offset + 2..])?;
let new_offset = self.data.len() - rem.len();
self.offset = new_offset;
Some((label, data))
}
}
impl<'a> Alignment<'a> {
pub fn aux_iter(&self) -> AuxDataIter {
AuxDataIter {
data: self.raw_aux(),
offset: 0,
}
}
}