use std::u16; use anyhow::{Ok, Result}; //pub type BytesRef = AsRef; pub trait Pushable { fn push_u8(&mut self, byte: &u8) -> Result<()>; fn push_vec(&mut self, bytes: Vec) -> Result<()>; fn push_slice(&mut self, bytes: &[u8]) -> Result<()>; } impl Pushable for Vec { fn push_u8(&mut self, byte: &u8) -> Result<()> { // TODO: push can panic. Return Err instead of panicing. self.push(byte.to_owned()); Ok(()) } fn push_vec(&mut self, mut bytes: Vec) -> Result<()> { // TODO: append can panic. Return Err instead of panicing. self.append(&mut bytes); Ok(()) } fn push_slice(&mut self, bytes: &[u8]) -> Result<()> { // TODO: extend can also panic. Return Err instead of panicing. // https://doc.rust-lang.org/src/alloc/vec/mod.rs.html#2970 rustdoc 1.77.1 (7cf61ebde 2024-03-27) // http://web.archive.org/web/20240324062202/doc.rust-lang.org/src/alloc/vec/mod.rs.html#2970 self.extend(bytes); Ok(()) } } pub trait Poppable { fn try_pop_be(&mut self) -> Result; fn try_pop_le(&mut self) -> Result; fn try_pop_ne(&mut self) -> Result; } impl Poppable for &[u8] { fn try_pop_be(&mut self) -> Result { Ok(T::pop_be_from(self)?) } fn try_pop_le(&mut self) -> Result { Ok(T::pop_le_from(self)?) } fn try_pop_ne(&mut self) -> Result { Ok(T::pop_ne_from(self)?) } } pub trait PopFromBE { fn pop_be_from(source: &mut &[u8]) -> Result where Self: Sized; fn push_be_into(&self, dest: &mut T) -> Result<()>; } pub trait PopFromLE { fn pop_le_from(source: &mut &[u8]) -> Result where Self: Sized; fn push_le_into(&self, dest: &mut T) -> Result<()>; } pub trait PopFromNE { fn pop_ne_from(source: &mut &[u8]) -> Result where Self: Sized; fn push_ne_into(&self, dest: &mut T) -> Result<()>; } // // Impl PopFromNE, PopFromLE, PopFromBE for core primitive types // impl PopFromNE for u8 { fn pop_ne_from(source: &mut &[u8]) -> Result where Self: Sized, { const SIZE: usize = std::mem::size_of::(); if source.len() < SIZE { anyhow::bail!("Buffer too small to pop u8"); } let value = source[0]; *source = &source[SIZE..]; Ok(value) } fn push_ne_into(&self, dest: &mut T) -> Result<()> { dest.push_u8(self) } } impl PopFromLE for u8 { fn pop_le_from(source: &mut &[u8]) -> Result where Self: Sized, { u8::pop_ne_from(source) } fn push_le_into(&self, dest: &mut T) -> Result<()> { dest.push_u8(self) } } impl PopFromBE for u8 { fn pop_be_from(source: &mut &[u8]) -> Result where Self: Sized, { let x = u8::from_be(u8::pop_ne_from(source)?); Ok(x) } fn push_be_into(&self, dest: &mut T) -> Result<()> { dest.push_u8(self) } } macro_rules! core_impl_pop_ne { ($int_type: ident) => { impl PopFromNE for $int_type { fn pop_ne_from(source: &mut &[u8]) -> Result where Self: Sized, { const SIZE: usize = std::mem::size_of::<$int_type>(); if source.len() < SIZE { anyhow::bail!("Buffer too small to pop {}", stringify!($int_type)); } let value = $int_type::from_ne_bytes(source[..SIZE].try_into()?); *source = &source[SIZE..]; Ok(value) } fn push_ne_into(&self, dest: &mut T) -> Result<()> { dest.push_slice(&self.to_ne_bytes()) } } }; } macro_rules! int_impl_pop_non_ne { ($int_type: ident) => { impl PopFromLE for $int_type { fn pop_le_from(source: &mut &[u8]) -> Result where Self: Sized, { Ok(Self::from_le(Self::pop_ne_from(source)?)) } fn push_le_into(&self, dest: &mut T) -> Result<()> { dest.push_slice(&self.to_le_bytes()) } } impl PopFromBE for $int_type { fn pop_be_from(source: &mut &[u8]) -> Result where Self: Sized, { Ok(Self::from_be(Self::pop_ne_from(source)?)) } fn push_be_into(&self, dest: &mut T) -> Result<()> { dest.push_slice(&self.to_be_bytes()) } } }; } macro_rules! flt_impl_pop_non_ne { ($flt_type: ident) => { impl PopFromLE for $flt_type { fn pop_le_from(source: &mut &[u8]) -> Result where Self: Sized, { const SIZE: usize = std::mem::size_of::<$flt_type>(); if source.len() < SIZE { anyhow::bail!("Buffer to small to pop $flt_type"); } let value = $flt_type::from_le_bytes(source[..SIZE].try_into()?); *source = &source[SIZE..]; Ok(value) } fn push_le_into(&self, dest: &mut T) -> Result<()> { dest.push_slice(&self.to_le_bytes()) } } impl PopFromBE for $flt_type { fn pop_be_from(source: &mut &[u8]) -> Result where Self: Sized, { const SIZE: usize = std::mem::size_of::<$flt_type>(); if source.len() < SIZE { anyhow::bail!("Buffer to small to pop $flt_type"); } let value = $flt_type::from_be_bytes(source[..SIZE].try_into()?); *source = &source[SIZE..]; Ok(value) } fn push_be_into(&self, dest: &mut T) -> Result<()> { dest.push_slice(&self.to_be_bytes()) } } }; } core_impl_pop_ne!(u16); core_impl_pop_ne!(u32); core_impl_pop_ne!(u64); core_impl_pop_ne!(u128); core_impl_pop_ne!(usize); core_impl_pop_ne!(i16); core_impl_pop_ne!(i32); core_impl_pop_ne!(i64); core_impl_pop_ne!(i128); core_impl_pop_ne!(isize); int_impl_pop_non_ne!(u16); int_impl_pop_non_ne!(u32); int_impl_pop_non_ne!(u64); int_impl_pop_non_ne!(u128); int_impl_pop_non_ne!(usize); int_impl_pop_non_ne!(i16); int_impl_pop_non_ne!(i32); int_impl_pop_non_ne!(i64); int_impl_pop_non_ne!(i128); int_impl_pop_non_ne!(isize); core_impl_pop_ne!(f32); flt_impl_pop_non_ne!(f32); core_impl_pop_ne!(f64); flt_impl_pop_non_ne!(f64);