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 } pub fn fraction_f64(&self) -> f64 { self.fraction() as f64 / 65536.0 }
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 } pub fn fraction_f64(&self) -> f64 { self.fraction() as f64 / 16384.0 }
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<DateTime<Utc>, 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)
}
}
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<T: Pod>(&self, offset: usize) -> &'a T {
bytemuck::from_bytes(&self.bytes()[offset..offset + size_of::<T>()])
}
fn array<T: Pod>(&self, offset: usize, count: usize) -> &'a [T] {
bytemuck::cast_slice(&self.bytes()[offset..offset + size_of::<T>() * 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 }
}
#[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<Item = u16> + '_ { (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()
}
}
#[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<Item = i16> + '_ { (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()
}
}
#[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<Item = u32> + '_ { (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()
}
}