Skip to content

Commit

Permalink
generate Packable implementations for primitive numbers + default to …
Browse files Browse the repository at this point in the history
…big-endian packing
  • Loading branch information
N8BWert committed Oct 5, 2024
1 parent b6d4e02 commit eefd214
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 1 deletion.
3 changes: 2 additions & 1 deletion ncomm-utils/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ repository.workspace = true
default = ["std"]
nostd = []
alloc = []
std = []
std = []
little-endian = []
103 changes: 103 additions & 0 deletions ncomm-utils/src/packing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,106 @@ pub trait Packable: Sized {
/// Unpack a given piece of data from an array of bytes
fn unpack(data: &[u8]) -> Result<Self, PackingError>;
}

#[cfg(feature = "little-endian")]
macro_rules! packable_primitive {
($primitive_name: ident, $length: literal) => {
impl Packable for $primitive_name {
fn len() -> usize {
$length as usize
}

fn pack(self, buffer: &mut [u8]) -> Result<(), PackingError> {
if buffer.len() < Self::len() {
return Err(PackingError::InvalidBufferSize);
}

buffer[..Self::len()].copy_from_slice(&self.to_le_bytes()[..]);
Ok(())
}

fn unpack(data: &[u8]) -> Result<Self, PackingError> {
if data.len() < Self::len() {
return Err(PackingError::InvalidBufferSize);
}

Ok(Self::from_le_bytes(data[..Self::len()].try_into().unwrap()))
}
}
};
}

#[cfg(not(feature = "little-endian"))]
macro_rules! packable_primitive {
($primitive_name: ident, $length: literal) => {
impl Packable for $primitive_name {
fn len() -> usize {
$length as usize
}

fn pack(self, buffer: &mut [u8]) -> Result<(), PackingError> {
if buffer.len() < Self::len() {
return Err(PackingError::InvalidBufferSize);
}

buffer[..Self::len()].copy_from_slice(&self.to_be_bytes()[..]);
Ok(())
}

fn unpack(data: &[u8]) -> Result<Self, PackingError> {
if data.len() < Self::len() {
return Err(PackingError::InvalidBufferSize);
}

Ok(Self::from_be_bytes(data[..Self::len()].try_into().unwrap()))
}
}
};
}

packable_primitive!(u8, 1);
packable_primitive!(u16, 2);
packable_primitive!(u32, 4);
packable_primitive!(u64, 8);
packable_primitive!(u128, 16);
packable_primitive!(usize, 8);
packable_primitive!(i8, 1);
packable_primitive!(i16, 2);
packable_primitive!(i32, 4);
packable_primitive!(i64, 8);
packable_primitive!(i128, 16);
packable_primitive!(isize, 8);
packable_primitive!(f32, 4);
packable_primitive!(f64, 8);

#[cfg(test)]
mod tests {
use super::*;

macro_rules! test_primitive_packing {
($primitive: ident, $buffer_length: literal, $value: literal, $test_name: ident) => {
#[test]
fn $test_name() {
let mut buffer = [0u8; $buffer_length as usize];
assert!($value.pack(&mut buffer).is_ok());
println!("buffer: {:?}", buffer);
assert_eq!($value, $primitive::unpack(&buffer).unwrap());
}
};
}

test_primitive_packing!(u8, 1, 129u8, test_u8_packing);
test_primitive_packing!(u16, 2, 129u16, test_u16_packing);
test_primitive_packing!(u32, 4, 129u32, test_u32_packing);
test_primitive_packing!(u64, 8, 129u64, test_u64_packing);
test_primitive_packing!(u128, 16, 129u128, test_u128_packing);
test_primitive_packing!(usize, 16, 129usize, test_usize_packing);
test_primitive_packing!(i8, 1, 15i8, test_i8_packing);
test_primitive_packing!(i16, 2, 129i16, test_i16_packing);
test_primitive_packing!(i32, 4, 129i32, test_i32_packing);
test_primitive_packing!(i64, 8, 129i64, test_i64_packing);
test_primitive_packing!(i128, 16, 129i128, test_i128_packing);
test_primitive_packing!(isize, 16, 129isize, test_isize_packing);
test_primitive_packing!(f32, 4, 2.01f32, test_f32_packing);
test_primitive_packing!(f64, 8, 2.01f64, test_f64_packing);
}

0 comments on commit eefd214

Please sign in to comment.