use std::mem::size_of; use std::fmt::{ Debug, Formatter, Result as FmtResult }; use bytemuck::{ Zeroable, Pod }; use chrono::{ DateTime, Utc }; #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct Fixed(i16, u16); impl Fixed { pub const ZERO: Self = Self(0, 0); pub const ONE: Self = Self(1, 0); pub const fn integer(&self) -> i16 { self.0 } pub const fn fraction(&self) -> u16 { self.1 } pub fn fraction_f32(&self) -> f32 { self.fraction() as f32 / 65536.0 } // TODO is it faster to encode it myself? pub fn fraction_f64(&self) -> f64 { self.fraction() as f64 / 65536.0 } // TODO is it faster to encode it myself? pub fn as_f32(&self) -> f32 { self.integer() as f32 + self.fraction_f32() } pub fn as_f64(&self) -> f64 { self.integer() as f64 + self.fraction_f64() } } impl Debug for Fixed { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { write!(f, "{}", self.as_f32()) } } #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct F2Dot14(i16); impl F2Dot14 { pub const ZERO: Self = Self(0); pub const ONE: Self = Self(0x4000); pub const fn integer(&self) -> i16 { self.0 >> 14 } pub const fn fraction(&self) -> u16 { self.0 as u16 & 0x3FFF } pub fn fraction_f32(&self) -> f32 { self.fraction() as f32 / 16384.0 } // TODO is it faster to encode it myself? pub fn fraction_f64(&self) -> f64 { self.fraction() as f64 / 16384.0 } // TODO is it faster to encode it myself? pub fn as_f32(&self) -> f32 { self.integer() as f32 + self.fraction_f32() } pub fn as_f64(&self) -> f64 { self.integer() as f64 + self.fraction_f64() } } impl Debug for F2Dot14 { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { write!(f, "{}", self.as_f32()) } } pub type LongDateTime = Result, i64>; #[derive(Clone, Copy, Zeroable, Pod, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(transparent)] pub struct Tag([u8; 4]); impl Tag { pub const fn new(value: &[u8; 4]) -> Self { Self(*value) } } impl From<[u8; 4]> for Tag { fn from(value: [u8; 4]) -> Self { Self(value) } } impl AsRef<[u8; 4]> for Tag { fn as_ref(&self) -> &[u8; 4] { &self.0 } } impl Debug for Tag { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { write!(f, "{:?}", std::str::from_utf8(&self.0).unwrap()) } } #[derive(Clone, Copy)] pub struct Version16Dot16(pub u16, pub u16); impl Debug for Version16Dot16 { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { write!(f, "Version16Dot16({}, {})", self.0, self.1) } } // Random Access pub trait RandomAccess<'a> { fn bytes(&self) -> &'a [u8]; fn uint8(&self, offset: usize) -> u8 { u8::from_be_bytes(*self.item(offset)) } fn uint16(&self, offset: usize) -> u16 { u16::from_be_bytes(*self.item(offset)) } fn uint32(&self, offset: usize) -> u32 { u32::from_be_bytes(*self.item(offset)) } fn uint24(&self, offset: usize) -> u32 { let bytes: &[u8; 3] = self.item(offset); u32::from_be_bytes([0, bytes[0], bytes[1], bytes[2]]) } fn int8(&self, offset: usize) -> i8 { i8::from_be_bytes(*self.item(offset)) } fn int16(&self, offset: usize) -> i16 { i16::from_be_bytes(*self.item(offset)) } fn int32(&self, offset: usize) -> i32 { i32::from_be_bytes(*self.item(offset)) } fn fixed(&self, offset: usize) -> Fixed { let value = self.uint32(offset); Fixed((value >> 16) as i16, (value & 0xFFFF) as u16) } fn f2dot14(&self, offset: usize) -> F2Dot14 { F2Dot14(self.int16(offset)) } fn longdatetime(&self, offset: usize) -> LongDateTime { let timestamp = i64::from_be_bytes(*self.item(offset)); DateTime::from_timestamp(timestamp - 2082844800, 0).ok_or(timestamp) } fn tag(&self, offset: usize) -> &'a Tag { self.item(offset) } fn version16dot16(&self, offset: usize) -> Version16Dot16 { let value = self.uint32(offset); Version16Dot16((value >> 16) as u16, (value & 0xFFFF) as u16) } fn item(&self, offset: usize) -> &'a T { bytemuck::from_bytes(&self.bytes()[offset..offset + size_of::()]) } fn array(&self, offset: usize, count: usize) -> &'a [T] { bytemuck::cast_slice(&self.bytes()[offset..offset + size_of::() * count]) } fn uint16_array(&self, offset: usize, count: usize) -> U16Array<'a> { let end = offset + (count << 1); U16Array(&self.bytes()[offset..end]) } fn int16_array(&self, offset: usize, count: usize) -> I16Array<'a> { let end = offset + (count << 1); I16Array(&self.bytes()[offset..end]) } fn uint32_array(&self, offset: usize, count: usize) -> U32Array<'a> { let end = offset + (count << 2); U32Array(&self.bytes()[offset..end]) } } impl<'a> RandomAccess<'a> for &'a [u8] { fn bytes(&self) -> &'a [u8] { self } } // U16Array #[derive(Clone, Copy)] pub struct U16Array<'a>(&'a [u8]); impl<'a> RandomAccess<'a> for U16Array<'a> { fn bytes(&self) -> &'a [u8] { self.0 } } impl<'a> U16Array<'a> { pub fn len(&self) -> usize { self.0.len() >> 1 } pub fn is_empty(&self) -> bool { self.len() == 0 } pub fn get(&self, index: usize) -> u16 { self.0.uint16(index << 1) } pub fn iter(&self) -> impl ExactSizeIterator + '_ { (0..self.0.len()).step_by(2).map(|x| self.0.uint16(x)) } } impl<'a> Debug for U16Array<'a> { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { f.debug_list() .entries(self.iter()) .finish() } } // I16Array #[derive(Clone, Copy)] pub struct I16Array<'a>(&'a [u8]); impl<'a> RandomAccess<'a> for I16Array<'a> { fn bytes(&self) -> &'a [u8] { self.0 } } impl<'a> I16Array<'a> { pub fn len(&self) -> usize { self.0.len() >> 1 } pub fn is_empty(&self) -> bool { self.len() == 0 } pub fn get(&self, index: usize) -> i16 { self.0.int16(index << 1) } pub fn iter(&self) -> impl ExactSizeIterator + '_ { (0..self.0.len()).step_by(2).map(|x| self.0.int16(x)) } } impl<'a> Debug for I16Array<'a> { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { f.debug_list() .entries(self.iter()) .finish() } } // U32Array #[derive(Clone, Copy)] pub struct U32Array<'a>(&'a [u8]); impl<'a> RandomAccess<'a> for U32Array<'a> { fn bytes(&self) -> &'a [u8] { self.0 } } impl<'a> U32Array<'a> { pub fn len(&self) -> usize { self.0.len() >> 2 } pub fn is_empty(&self) -> bool { self.len() == 0 } pub fn get(&self, index: usize) -> u32 { self.0.uint32(index << 2) } pub fn iter(&self) -> impl ExactSizeIterator + '_ { (0..self.0.len()).step_by(4).map(|x| self.0.uint32(x)) } } impl<'a> Debug for U32Array<'a> { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { f.debug_list() .entries(self.iter()) .finish() } }