Skip to main content

bytestruct

Macro bytestruct 

Source
macro_rules! bytestruct {
    (
        $(#[$meta:meta])*
        $vis:vis struct $name:ident ([$unit:tt; $N:tt]) {
            $(
                $field_vis:vis $field_name:ident: $field_type:tt = $bits:tt
            ),* $(,)?
        }
    ) => { ... };
    (
        $(#[$meta:meta])*
        $vis:vis struct $name:ident ([$unit:tt; $N:tt]) {
            $field_vis:vis $field_name:ident : ($field_type:ty) = @unroll($count:tt)
        }
    ) => { ... };
    (
        $(#[$meta:meta])*
        $vis:vis struct $name:ident ([$unit:tt; $N:tt]) {
            $field_vis:vis $field_name:ident : ($field_type:ty) = @unroll_signed($count:tt)
        }
    ) => { ... };
    (
        $(#[$meta:meta])*
        $vis:vis struct $name:ident ($N:tt) {
            $(
                $field_vis:vis $field_name:ident: $field_type:tt = $bits:tt
            ),* $(,)?
        }
    ) => { ... };
    (@impl_conversions $name:ident, 1) => { ... };
    (@impl_conversions $name:ident, 2) => { ... };
    (@impl_conversions $name:ident, 3) => { ... };
    (@impl_conversions $name:ident, 4) => { ... };
    (@impl_conversions $name:ident, 5) => { ... };
    (@impl_conversions $name:ident, 6) => { ... };
    (@impl_conversions $name:ident, 7) => { ... };
    (@impl_conversions $name:ident, 8) => { ... };
    (@impl_conversions $name:ident, 16) => { ... };
    (@impl_conversions $name:ident, $N:expr) => { ... };
    (@impl_wide_conv $name:ident, $N:tt, $prim:ty, $to_name:ident, $from_name:ident, $($idx:literal)*) => { ... };
    (@impl_fields $name:ident, $prim:ty, $shift:expr, ) => { ... };
    (@impl_fields $name:ident, $prim:ty, $shift:expr, $field_vis:vis $field_name:ident bool $bits:tt $($rest:tt)*) => { ... };
    (@impl_fields $name:ident, $prim:ty, $shift:expr, $field_vis:vis $field_name:ident u8 $bits:tt $($rest:tt)*) => { ... };
    (@impl_fields $name:ident, $prim:ty, $shift:expr, $field_vis:vis $field_name:ident u16 $bits:tt $($rest:tt)*) => { ... };
    (@impl_fields $name:ident, $prim:ty, $shift:expr, $field_vis:vis $field_name:ident u32 $bits:tt $($rest:tt)*) => { ... };
    (@impl_fields $name:ident, $prim:ty, $shift:expr, $field_vis:vis $field_name:ident u64 $bits:tt $($rest:tt)*) => { ... };
    (@impl_fields $name:ident, $prim:ty, $shift:expr, $field_vis:vis $field_name:ident u128 $bits:tt $($rest:tt)*) => { ... };
    (@impl_fields $name:ident, $prim:ty, $shift:expr, $field_vis:vis $field_name:ident i8 $bits:tt $($rest:tt)*) => { ... };
    (@impl_fields $name:ident, $prim:ty, $shift:expr, $field_vis:vis $field_name:ident i16 $bits:tt $($rest:tt)*) => { ... };
    (@impl_fields $name:ident, $prim:ty, $shift:expr, $field_vis:vis $field_name:ident i32 $bits:tt $($rest:tt)*) => { ... };
    (@impl_fields $name:ident, $prim:ty, $shift:expr, $field_vis:vis $field_name:ident i64 $bits:tt $($rest:tt)*) => { ... };
    (@impl_fields $name:ident, $prim:ty, $shift:expr, $field_vis:vis $field_name:ident i128 $bits:tt $($rest:tt)*) => { ... };
    (@impl_int $name:ident, $prim:ty, $shift:expr, $field_vis:vis $field_name:ident $field_type:tt $bits:tt $($rest:tt)*) => { ... };
    (@impl_signed_int $name:ident, $prim:ty, $shift:expr, $field_vis:vis $field_name:ident $field_type:tt $bits:tt $($rest:tt)*) => { ... };
    (@impl_typed_conversions $name:ident, $unit:tt, $N:tt) => { ... };
    (@route_conversions $name:ident, $unit:tt, 1) => { ... };
    (@route_conversions $name:ident, $unit:tt, 2) => { ... };
    (@route_conversions $name:ident, $unit:tt, 3) => { ... };
    (@route_conversions $name:ident, $unit:tt, 4) => { ... };
    (@route_conversions $name:ident, $unit:tt, 5) => { ... };
    (@route_conversions $name:ident, $unit:tt, 6) => { ... };
    (@route_conversions $name:ident, $unit:tt, 7) => { ... };
    (@route_conversions $name:ident, $unit:tt, 8) => { ... };
    (@route_conversions $name:ident, $unit:tt, 9) => { ... };
    (@route_conversions $name:ident, $unit:tt, 10) => { ... };
    (@route_conversions $name:ident, $unit:tt, 11) => { ... };
    (@route_conversions $name:ident, $unit:tt, 12) => { ... };
    (@route_conversions $name:ident, $unit:tt, 13) => { ... };
    (@route_conversions $name:ident, $unit:tt, 14) => { ... };
    (@route_conversions $name:ident, $unit:tt, 15) => { ... };
    (@route_conversions $name:ident, $unit:tt, 16) => { ... };
    (@route_conversions $name:ident, $unit:tt, $any:expr) => { ... };
    (@impl_typed_uX_methods $name:ident, u8, 1) => { ... };
    (@impl_typed_uX_methods $name:ident, u8, 2) => { ... };
    (@impl_typed_uX_methods $name:ident, u8, 3) => { ... };
    (@impl_typed_uX_methods $name:ident, u8, 4) => { ... };
    (@impl_typed_uX_methods $name:ident, u8, 5) => { ... };
    (@impl_typed_uX_methods $name:ident, u8, 6) => { ... };
    (@impl_typed_uX_methods $name:ident, u8, 7) => { ... };
    (@impl_typed_uX_methods $name:ident, u8, 8) => { ... };
    (@impl_typed_uX_methods $name:ident, u8, 9) => { ... };
    (@impl_typed_uX_methods $name:ident, u8, 10) => { ... };
    (@impl_typed_uX_methods $name:ident, u8, 11) => { ... };
    (@impl_typed_uX_methods $name:ident, u8, 12) => { ... };
    (@impl_typed_uX_methods $name:ident, u8, 13) => { ... };
    (@impl_typed_uX_methods $name:ident, u8, 14) => { ... };
    (@impl_typed_uX_methods $name:ident, u8, 15) => { ... };
    (@impl_typed_uX_methods $name:ident, u8, 16) => { ... };
    (@impl_typed_uX_methods $name:ident, u16, 1) => { ... };
    (@impl_typed_uX_methods $name:ident, u16, 2) => { ... };
    (@impl_typed_uX_methods $name:ident, u16, 3) => { ... };
    (@impl_typed_uX_methods $name:ident, u16, 4) => { ... };
    (@impl_typed_uX_methods $name:ident, u16, 5) => { ... };
    (@impl_typed_uX_methods $name:ident, u16, 6) => { ... };
    (@impl_typed_uX_methods $name:ident, u16, 7) => { ... };
    (@impl_typed_uX_methods $name:ident, u16, 8) => { ... };
    (@impl_typed_uX_methods $name:ident, u32, 1) => { ... };
    (@impl_typed_uX_methods $name:ident, u32, 2) => { ... };
    (@impl_typed_uX_methods $name:ident, u32, 3) => { ... };
    (@impl_typed_uX_methods $name:ident, u32, 4) => { ... };
    (@impl_typed_uX_methods $name:ident, u64, 1) => { ... };
    (@impl_typed_uX_methods $name:ident, u64, 2) => { ... };
    (@impl_typed_uX_methods $name:ident, u128, 1) => { ... };
    (@impl_u8_methods $name:ident) => { ... };
    (@impl_u16_methods $name:ident) => { ... };
    (@impl_u32_methods $name:ident) => { ... };
    (@impl_u64_methods $name:ident) => { ... };
    (@impl_u128_methods $name:ident) => { ... };
    (@impl_typed_fields $name:ident, $unit:tt, $prim:ty, $shift:expr, $field_vis:vis $field_name:ident ($field_type:ty) = @unroll($count:tt) $($rest:tt)*) => { ... };
    (@impl_typed_fields $name:ident, $unit:tt, $prim:ty, $shift:expr, $field_vis:vis $field_name:ident ($field_type:ty) = @unroll_signed($count:tt) $($rest:tt)*) => { ... };
    (@impl_typed_fields $name:ident, $unit:tt, $prim:ty, $shift:expr, ) => { ... };
    (@impl_typed_fields $name:ident, $unit:tt, $prim:ty, $shift:expr, $field_vis:vis $field_name:ident bool $bits:tt $($rest:tt)*) => { ... };
    (@impl_typed_fields $name:ident, $unit:tt, $prim:ty, $shift:expr, $field_vis:vis $field_name:ident u8 $bits:tt $($rest:tt)*) => { ... };
    (@impl_typed_fields $name:ident, $unit:tt, $prim:ty, $shift:expr, $field_vis:vis $field_name:ident u16 $bits:tt $($rest:tt)*) => { ... };
    (@impl_typed_fields $name:ident, $unit:tt, $prim:ty, $shift:expr, $field_vis:vis $field_name:ident u32 $bits:tt $($rest:tt)*) => { ... };
    (@impl_typed_fields $name:ident, $unit:tt, $prim:ty, $shift:expr, $field_vis:vis $field_name:ident u64 $bits:tt $($rest:tt)*) => { ... };
    (@impl_typed_fields $name:ident, $unit:tt, $prim:ty, $shift:expr, $field_vis:vis $field_name:ident u128 $bits:tt $($rest:tt)*) => { ... };
    (@impl_typed_fields $name:ident, $unit:tt, $prim:ty, $shift:expr, $field_vis:vis $field_name:ident i8 $bits:tt $($rest:tt)*) => { ... };
    (@impl_typed_fields $name:ident, $unit:tt, $prim:ty, $shift:expr, $field_vis:vis $field_name:ident i16 $bits:tt $($rest:tt)*) => { ... };
    (@impl_typed_fields $name:ident, $unit:tt, $prim:ty, $shift:expr, $field_vis:vis $field_name:ident i32 $bits:tt $($rest:tt)*) => { ... };
    (@impl_typed_fields $name:ident, $unit:tt, $prim:ty, $shift:expr, $field_vis:vis $field_name:ident i64 $bits:tt $($rest:tt)*) => { ... };
    (@impl_typed_fields $name:ident, $unit:tt, $prim:ty, $shift:expr, $field_vis:vis $field_name:ident i128 $bits:tt $($rest:tt)*) => { ... };
    (@impl_typed_int $name:ident, $unit:tt, $prim:ty, $shift:expr, $field_vis:vis $field_name:ident $field_type:tt $bits:tt $($rest:tt)*) => { ... };
    (@impl_typed_signed_int $name:ident, $unit:tt, $prim:ty, $shift:expr, $field_vis:vis $field_name:ident $field_type:tt $bits:tt $($rest:tt)*) => { ... };
    (@impl_typed_fields $name:ident, $unit:tt, $prim:ty, $shift:expr, $field_vis:vis $field_name:ident ($field_type:ty) $bits:tt $($rest:tt)*) => { ... };
    (@impl_typed_fields $name:ident, $unit:tt, $prim:ty, $shift:expr, $field_vis:vis $field_name:ident $field_type:tt $bits:tt $($rest:tt)*) => { ... };
    (@read_typed_prim $arr:expr, $unit:tt, $prim:ty, $shift:expr, $bits:tt) => { ... };
    (@write_typed_prim $arr:expr, $unit:tt, $prim:ty, $shift:expr, $bits:tt, $val:expr) => { ... };
    (@unroll_typed_read $arr:expr, $unit:tt, $prim:ty, $idx:expr, 1, $offset:expr, $bits:expr) => { ... };
    (@unroll_typed_read $arr:expr, $unit:tt, $prim:ty, $idx:expr, 2, $offset:expr, $bits:expr) => { ... };
    (@unroll_typed_read $arr:expr, $unit:tt, $prim:ty, $idx:expr, 3, $offset:expr, $bits:expr) => { ... };
    (@unroll_typed_read $arr:expr, $unit:tt, $prim:ty, $idx:expr, 4, $offset:expr, $bits:expr) => { ... };
    (@unroll_typed_read $arr:expr, $unit:tt, $prim:ty, $idx:expr, 5, $offset:expr, $bits:expr) => { ... };
    (@unroll_typed_read $arr:expr, $unit:tt, $prim:ty, $idx:expr, 6, $offset:expr, $bits:expr) => { ... };
    (@unroll_typed_read $arr:expr, $unit:tt, $prim:ty, $idx:expr, 7, $offset:expr, $bits:expr) => { ... };
    (@unroll_typed_read $arr:expr, $unit:tt, $prim:ty, $idx:expr, 8, $offset:expr, $bits:expr) => { ... };
    (@unroll_typed_read $arr:expr, $unit:tt, $prim:ty, $idx:expr, $any:expr, $offset:expr, $bits:expr) => { ... };
    (@unroll_typed_write $arr:expr, $unit:tt, $prim:ty, $idx:expr, $count:tt, $offset:expr, $bits:expr, $val:expr) => { ... };
    (@unroll_typed_write_fresh $arr:expr, $unit:tt, $prim:ty, $idx:expr, $count:tt, $offset:expr, $bits:expr, $val:expr) => { ... };
    (@unroll_typed_write_raw $arr:expr, $unit:tt, $prim:ty, $idx:expr, 1, $full:expr) => { ... };
    (@unroll_typed_write_raw $arr:expr, $unit:tt, $prim:ty, $idx:expr, 2, $full:expr) => { ... };
    (@unroll_typed_write_raw $arr:expr, $unit:tt, $prim:ty, $idx:expr, 3, $full:expr) => { ... };
    (@unroll_typed_write_raw $arr:expr, $unit:tt, $prim:ty, $idx:expr, 4, $full:expr) => { ... };
    (@unroll_typed_write_raw $arr:expr, $unit:tt, $prim:ty, $idx:expr, 5, $full:expr) => { ... };
    (@unroll_typed_write_raw $arr:expr, $unit:tt, $prim:ty, $idx:expr, 6, $full:expr) => { ... };
    (@unroll_typed_write_raw $arr:expr, $unit:tt, $prim:ty, $idx:expr, 7, $full:expr) => { ... };
    (@unroll_typed_write_raw $arr:expr, $unit:tt, $prim:ty, $idx:expr, 8, $full:expr) => { ... };
    (@unroll_typed_write_raw $arr:expr, $unit:tt, $prim:ty, $idx:expr, $any:expr, $full:expr) => { ... };
    (@impl_fields $name:ident, $prim:ty, $shift:expr, $field_vis:vis $field_name:ident ($field_type:ty) $bits:tt $($rest:tt)*) => { ... };
    (@impl_fields $name:ident, $prim:ty, $shift:expr, $field_vis:vis $field_name:ident $field_type:tt $bits:tt $($rest:tt)*) => { ... };
    (@read_localized_prim $arr:expr, $shift:expr, $bits:tt) => { ... };
    (@write_localized_prim $arr:expr, $shift:expr, $bits:tt, $val:expr) => { ... };
}
Expand description

A unique declarative macro for generating bitfields backed by fixed-size byte arrays.

Unlike standard bitfield libraries that restrict storage to primitives (u8-u128), bytestruct allows array-backed storage ([u8; 1-16]) while maintaining register-wide optimization through “Acting Primitives”.

This macro generates a struct wrapping [u8; N]. It uses an internal “acting primitive” (u32, u64, or u128) based on $N$ to perform efficient bitwise operations.

§Examples

§Cross-Boundary Packing in a Byte Array

use bitcraft::bytestruct;

bytestruct! {
    // Packs fields into a 5-byte (40-bit) storage array.
    pub struct NetworkPacket([u8; 5]) {
        pub version: u8 = 4,         // Bits 0-3
        pub is_encrypted: bool = 1,  // Bit 4
        pub payload_id: u32 = 24,    // Bits 5-28 (crosses 3 byte boundaries!)
        pub checksum: u16 = 11,      // Bits 29-39 (crosses 2 byte boundaries!)
    }
}

let mut packet = NetworkPacket::default()
    .with_version(4)
    .with_is_encrypted(true)
    .with_payload_id(0xABCDEF);

assert_eq!(packet.version(), 4);
assert!(packet.is_encrypted());
assert_eq!(packet.payload_id(), 0xABCDEF);

// The raw array perfectly packs these bits densely
let raw: [u8; 5] = packet.to_array();

§Advanced Typed Storage ([u16; N], [u32; N]) & Signed Fields

bytestruct! natively supports generic integer array types, which enables creating large dense multi-element bitfields with highly efficient memory bounds.

use bitcraft::bytestruct;

bytestruct! {
    // A 128-bit wrapper stored as four `u32` blocks.
    pub struct HugeStorage([u32; 4]) {
        pub header: u16 = 16,
        pub sensor_val: i32 = 20, // A 20-bit signed field (-524,288 to 524,287)
        pub hash: u64 = 64,       // 64-bit contiguous field crossing u32 boundaries
        // ... other fields filling the 128 bits ...
    }
}

let mut mem = HugeStorage::default();
mem.set_sensor_val(-400_000);
assert_eq!(mem.sensor_val(), -400_000);

§Implementation Details

bytestruct! uses an advanced “Token-Tree (TT) Muncher” pattern coupled with dynamic type resolution via the hidden BitenumType trait. It completely unrolls array reads and writes into single-primitive logic.

For instance, if you define a 5-byte array ([u8; 5]), bytestruct! computes the total number of bits (40 bits). Through crate::Bits<40>, the Rust type system dynamically resolves the “Acting Primitive” to u64. All internal field getters and setters will seamlessly load the required array slice into a u64 register, perform the bitwise logic, and write the bytes back without branching.