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 // TODO: Create macro(s) for impls. Most of these impls are the same except for the the type name. // TODO: Impl for u128 and i128 // TODO: Impl for usize and isize // 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, { u8::pop_ne_from(source) } fn push_be_into(&self, dest: &mut T) -> Result<()> { dest.push_u8(self) } } // Impls for u16 impl PopFromNE for u16 { 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 u16"); } let value = u16::from_be_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()) } } impl PopFromLE for u16 { 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 u16 { 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()) } } //Impls for u32 impl PopFromNE for u32 { 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 u32"); } let value = u32::from_be_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()) } } impl PopFromLE for u32 { 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 u32 { 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()) } } //Impls for u64 impl PopFromNE for u64 { 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 u64"); } let value = u64::from_be_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()) } } impl PopFromLE for u64 { 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 u64 { 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()) } } impl PopFromNE for i8 { 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 i8"); } let value = source[0] as i8; *source = &source[SIZE..]; Ok(value) } fn push_ne_into(&self, dest: &mut T) -> Result<()> { dest.push_u8(&(*self as u8)) } } impl PopFromLE for i8 { fn pop_le_from(source: &mut &[u8]) -> Result where Self: Sized, { i8::pop_ne_from(source) } fn push_le_into(&self, dest: &mut T) -> Result<()> { self.push_ne_into(dest) } } impl PopFromBE for i8 { fn pop_be_from(source: &mut &[u8]) -> Result where Self: Sized, { i8::pop_ne_from(source) } fn push_be_into(&self, dest: &mut T) -> Result<()> { self.push_ne_into(dest) } } impl PopFromNE for i16 { 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 i16"); } let value = i16::from_be_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()) } } impl PopFromNE for i32 { 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 i32"); } let value = i32::from_be_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()) } } impl PopFromNE for i64 { 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 i64"); } let value = i64::from_be_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()) } } impl PopFromLE for i16 { 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 PopFromLE for i32 { 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 PopFromLE for i64 { 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 i16 { 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()) } } impl PopFromBE for i32 { 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()) } } impl PopFromBE for i64 { 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()) } } // // Floating Point // impl PopFromNE for f32 { 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 to small to pop f32"); } let value = f32::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()) } } impl PopFromLE for f32 { fn pop_le_from(source: &mut &[u8]) -> Result where Self: Sized, { const SIZE: usize = std::mem::size_of::(); if source.len() < SIZE { anyhow::bail!("Buffer to small to pop f32"); } let value = f32::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 f32 { fn pop_be_from(source: &mut &[u8]) -> Result where Self: Sized, { const SIZE: usize = std::mem::size_of::(); if source.len() < SIZE { anyhow::bail!("Buffer to small to pop f32"); } let value = f32::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()) } } impl PopFromNE for f64 { 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 to small to pop f64"); } let value = f64::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()) } } impl PopFromLE for f64 { fn pop_le_from(source: &mut &[u8]) -> Result where Self: Sized, { const SIZE: usize = std::mem::size_of::(); if source.len() < SIZE { anyhow::bail!("Buffer to small to pop f64"); } let value = f64::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 f64 { fn pop_be_from(source: &mut &[u8]) -> Result where Self: Sized, { const SIZE: usize = std::mem::size_of::(); if source.len() < SIZE { anyhow::bail!("Buffer to small to pop f64"); } let value = f64::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()) } }