Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ license = "MIT"
[dependencies]
lightpack-derive = { version = "0.2.9", path = "lightpack-derive" }
byteorder = { workspace = true }
pastey = "0.2"

[workspace]
members = [
Expand Down
128 changes: 40 additions & 88 deletions src/pack.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! The [`Pack`] trait and primitive implementations.

use byteorder::ByteOrder;
use pastey::paste;

use crate::Size;

Expand All @@ -10,67 +11,37 @@ pub trait Pack: Size {
fn pack<B>(&self, buffer: &mut [u8]) where B: ByteOrder;
}

// TODO: Abstract over this with a macro
macro_rules! impl_pack_number {
($t:ty) => {
impl Pack for $t {
fn pack<B>(&self, buffer: &mut [u8]) where B: ByteOrder {
paste!{ B::[<write_$t>](buffer, *self) }
}
}
};
}

impl Pack for u8 {
fn pack<B>(&self, buffer: &mut [u8]) where B: ByteOrder {
buffer[0] = *self;
}
}

impl Pack for u16 {
fn pack<B>(&self, buffer: &mut [u8]) where B: ByteOrder {
B::write_u16(buffer, *self);
}
}

impl Pack for u32 {
fn pack<B>(&self, buffer: &mut [u8]) where B: ByteOrder {
B::write_u32(buffer, *self);
}
}

impl Pack for u64 {
fn pack<B>(&self, buffer: &mut [u8]) where B: ByteOrder {
B::write_u64(buffer, *self);
}
}
impl_pack_number!(u16);
impl_pack_number!(u32);
impl_pack_number!(u64);

impl Pack for i8 {
fn pack<B>(&self, buffer: &mut [u8]) where B: ByteOrder {
buffer[0] = *self as u8;
}
}

impl Pack for i16 {
fn pack<B>(&self, buffer: &mut [u8]) where B: ByteOrder {
B::write_i16(buffer, *self);
}
}

impl Pack for i32 {
fn pack<B>(&self, buffer: &mut [u8]) where B: ByteOrder {
B::write_i32(buffer, *self);
}
}

impl Pack for i64 {
fn pack<B>(&self, buffer: &mut [u8]) where B: ByteOrder {
B::write_i64(buffer, *self);
}
}

impl Pack for f32 {
fn pack<B>(&self, buffer: &mut [u8]) where B: ByteOrder {
B::write_f32(buffer, *self)
}
}
impl_pack_number!(i16);
impl_pack_number!(i32);
impl_pack_number!(i64);

impl Pack for f64 {
fn pack<B>(&self, buffer: &mut [u8]) where B: ByteOrder {
B::write_f64(buffer, *self)
}
}
impl_pack_number!(f32);
impl_pack_number!(f64);

impl Pack for bool {
fn pack<B>(&self, buffer: &mut [u8]) where B: ByteOrder {
Expand All @@ -84,49 +55,30 @@ impl Pack for char {
}
}

// TODO: Abstract over the tuple size with a macro

impl Pack for () {
fn pack<B>(&self, _buffer: &mut [u8]) where B: ByteOrder {
// Do nothing
}
}

impl<T0> Pack for (T0,) where T0: Pack {
fn pack<B>(&self, buffer: &mut [u8]) where B: ByteOrder {
self.0.pack::<B>(buffer);
}
}

impl<T0, T1> Pack for (T0, T1) where T0: Pack, T1: Pack {
fn pack<B>(&self, buffer: &mut [u8]) where B: ByteOrder {
self.0.pack::<B>(buffer);
let buffer = &mut buffer[T0::SIZE..];
self.1.pack::<B>(buffer);
}
}

impl<T0, T1, T2> Pack for (T0, T1, T2) where T0: Pack, T1: Pack, T2: Pack {
fn pack<B>(&self, buffer: &mut [u8]) where B: ByteOrder {
self.0.pack::<B>(buffer);
let buffer = &mut buffer[T0::SIZE..];
self.1.pack::<B>(buffer);
let buffer = &mut buffer[T1::SIZE..];
self.2.pack::<B>(buffer);
}
macro_rules! impl_pack_tuple {
($($idx:tt),*) => {
paste! {
impl<$([<T$idx>],)*> Pack for ($([<T$idx>],)*)
where
$([<T$idx>]: Pack,)*
{
#[allow(unused)] // because we generate one more "let buffer = ..." statement than we need
fn pack<B>(&self, buffer: &mut [u8]) where B: ByteOrder {
$(
self.$idx.pack::<B>(buffer);
let buffer = &mut buffer[[<T$idx>]::SIZE..];
)*
}
}
}
};
}

impl<T0, T1, T2, T3> Pack for (T0, T1, T2, T3) where T0: Pack, T1: Pack, T2: Pack, T3: Pack {
fn pack<B>(&self, buffer: &mut [u8]) where B: ByteOrder {
self.0.pack::<B>(buffer);
let buffer = &mut buffer[T0::SIZE..];
self.1.pack::<B>(buffer);
let buffer = &mut buffer[T1::SIZE..];
self.2.pack::<B>(buffer);
let buffer = &mut buffer[T2::SIZE..];
self.3.pack::<B>(buffer);
}
}
impl_pack_tuple!();
impl_pack_tuple!(0);
impl_pack_tuple!(0, 1);
impl_pack_tuple!(0, 1, 2);
impl_pack_tuple!(0, 1, 2, 3);

impl<T> Pack for &T where T: Pack {
fn pack<B>(&self, buffer: &mut [u8]) where B: ByteOrder {
Expand Down
101 changes: 44 additions & 57 deletions src/size.rs
Original file line number Diff line number Diff line change
@@ -1,80 +1,67 @@
//! The [`Size`] trait and primitive implementations.

use core::mem::size_of;
use pastey::paste;

/// Types that have an encoded size.
pub trait Size {
/// The type's encoded size in bytes.
const SIZE: usize;
}

impl Size for u8 {
const SIZE: usize = 1;
}

impl Size for u16 {
const SIZE: usize = 2;
macro_rules! impl_size_primitive {
($t:ty) => {
impl Size for $t {
const SIZE: usize = size_of::<$t>();
}
};
}

impl Size for u32 {
const SIZE: usize = 4;
}

impl Size for u64 {
const SIZE: usize = 8;
}
impl_size_primitive!(u8);
impl_size_primitive!(u16);
impl_size_primitive!(u32);
impl_size_primitive!(u64);

impl Size for i8 {
const SIZE: usize = 1;
}
impl_size_primitive!(i8);
impl_size_primitive!(i16);
impl_size_primitive!(i32);
impl_size_primitive!(i64);

impl Size for i16 {
const SIZE: usize = 2;
}
impl_size_primitive!(f32);
impl_size_primitive!(f64);

impl Size for i32 {
const SIZE: usize = 4;
}
impl_size_primitive!(bool);

impl Size for i64 {
const SIZE: usize = 8;
}
impl_size_primitive!(char);

impl Size for f32 {
const SIZE: usize = 4;
}
impl_size_primitive!(());

impl Size for f64 {
const SIZE: usize = 8;
macro_rules! sum {
($e:expr, $($es:expr),+) => {
$e + sum!($($es),+)
};
($e:expr) => {
$e
}
}

impl Size for bool {
const SIZE: usize = 1;
macro_rules! impl_size_tuple {
($($idx:tt),+) => {
paste! {
impl<$([<T$idx>],)*> Size for ($([<T$idx>],)+)
where
$([<T$idx>]: Size,)+
{
const SIZE: usize = sum!($( [<T$idx>]::SIZE ),*);
}
}
};
}

impl Size for char {
const SIZE: usize = 4;
}

impl Size for () {
const SIZE: usize = 0;
}

// TODO: Abstract over the tuple size with a macro

impl<T1> Size for (T1,) where T1: Size {
const SIZE: usize = T1::SIZE;
}

impl<T1, T2> Size for (T1, T2) where T1: Size, T2: Size {
const SIZE: usize = T1::SIZE + T2::SIZE;
}

impl<T1, T2, T3> Size for (T1, T2, T3) where T1: Size, T2: Size, T3: Size {
const SIZE: usize = T1::SIZE + T2::SIZE + T3::SIZE;
}

impl<T1, T2, T3, T4> Size for (T1, T2, T3, T4) where T1: Size, T2: Size, T3: Size, T4: Size {
const SIZE: usize = T1::SIZE + T2::SIZE + T3::SIZE + T4::SIZE;
}
impl_size_tuple!(0);
impl_size_tuple!(0, 1);
impl_size_tuple!(0, 1, 2);
impl_size_tuple!(0, 1, 2, 3);

impl<T> Size for &T where T: Size {
const SIZE: usize = T::SIZE;
Expand Down
Loading
Loading