From 51666b629c6e9a0e2a57df40201b5f1a39ad809a Mon Sep 17 00:00:00 2001 From: Lucas Schumacher Date: Tue, 2 Apr 2024 21:29:02 -0400 Subject: [PATCH] first commit --- .gitignore | 2 + Cargo.toml | 11 + poppable-derive/Cargo.toml | 13 + poppable-derive/src/lib.rs | 8 + src/lib.rs | 543 +++++++++++++++++++++++++++++++++++++ 5 files changed, 577 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 poppable-derive/Cargo.toml create mode 100644 poppable-derive/src/lib.rs create mode 100644 src/lib.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..96ef6c0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +Cargo.lock diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..f2a7459 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,11 @@ +workspace = { members = ["poppable-derive"] } +[package] +name = "poppable" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +anyhow = "1.0.81" +poppable-derive = { path = "poppable-derive"} diff --git a/poppable-derive/Cargo.toml b/poppable-derive/Cargo.toml new file mode 100644 index 0000000..20e2cdb --- /dev/null +++ b/poppable-derive/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "poppable-derive" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +quote = "1.0.35" +syn = "2.0.57" + +[lib] +proc_macro = true diff --git a/poppable-derive/src/lib.rs b/poppable-derive/src/lib.rs new file mode 100644 index 0000000..e9e9307 --- /dev/null +++ b/poppable-derive/src/lib.rs @@ -0,0 +1,8 @@ +use proc_macro::TokenStream; +use syn::DeriveInput; + +#[proc_macro_derive(PushPop)] +pub fn pushpop_derive_macro(item: TokenStream) -> TokenStream { + let _ast: DeriveInput = syn::parse(item).unwrap(); + todo!() +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..e0ae2e1 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,543 @@ +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()) + } +}