Crate bondrewd_derive[][src]

Expand description

Fast and easy bitfield proc macro

Provides a proc macro for compressing a data structure with data which can be expressed with bit lengths that are not a power of Two.

Derive Bitfields

  • Implements the Bitfields trait which offers from\into bytes functions that are non-failable and convert the struct from/into sized u8 arrays ([u8; {total_bit_length * 8}]).
  • read and write functions that allow the field to be accessed or overwritten within a sized u8 array.
  • More information about how each field is handled (bit length, endianness, ..), as well as structure wide effects (bit position, default field endianness, ..), can be found on the Bitfields Derive page.

For example we can define a data structure with 7 total bytes as:

  • a boolean field named one will be the first bit.
  • a floating point field named two will be the next 32 bits. floats must be full sized currently.
  • a signed integer field named three will be the next 14 bits.
  • an unsigned integer field named four will be the next 6 bits.
// Users code
use bondrewd::*;
#[derive(Bitfields)]
#[bondrewd(default_endianness = "be")]
struct SimpleExample {
    // fields that are as expected do not require attributes.
    one: bool,
    two: f32,
    #[bondrewd(bit_length = 14)]
    three: i16,
    #[bondrewd(bit_length = 6)]
    four: u8,
}
// Generated Code
impl Bitfields<7usize> for SimpleExample {
    const BIT_SIZE: usize = 53usize;
    fn into_bytes(self) -> [u8; 7usize] { .. }
    fn from_bytes(mut input_byte_buffer: [u8; 7usize]) -> Self { .. }
}
impl SimpleExample {
    pub fn read_one(input_byte_buffer: &[u8; 7usize]) -> bool { .. }
    pub fn read_two(input_byte_buffer: &[u8; 7usize]) -> f32 { .. }
    pub fn read_three(input_byte_buffer: &[u8; 7usize]) -> i16 { .. }
    pub fn read_four(input_byte_buffer: &[u8; 7usize]) -> u8 { .. }
    pub fn write_one(output_byte_buffer: &mut [u8; 7usize], mut one: bool) { .. }
    pub fn write_two(output_byte_buffer: &mut [u8; 7usize], mut two: f32) { .. }
    pub fn write_three(output_byte_buffer: &mut [u8; 7usize], mut three: i16) { .. }
    pub fn write_four(output_byte_buffer: &mut [u8; 7usize], mut four: u8) { .. }
}

Derive BitfieldEnum

  • Implements the BitfieldEnum trait which offers from\into primitive functions that are non-failable and convert the enum from/into a primitive type (u8 is the only currently testing primitive).
  • more information about controlling the end result (define variant values, define a catch/invalid variant) can be found on the BitfieldEnum Derive page.
// Users code
use bondrewd::BitfieldEnum;
#[derive(BitfieldEnum)]
enum SimpleEnum {
    Zero,
    One,
    Six = 6,
    Two,
}
// Generated Struct Code
impl bondrewd::BitfieldEnum for SimpleEnum {
    type Primitive = u8;
    fn into_primitive(self) -> u8 {
        match self {
            Self::Zero => 0,
            Self::One => 1,
            Self::Six => 6,
            Self::Two => 2,
        }
    }
    fn from_primitive(input: u8) -> Self {
        match input {
            0 => Self::Zero,
            1 => Self::One,
            6 => Self::Six,
            _ => Self::Two,
        }
    }
}

Other Crate Features

  • slice_fns generates slice functions:
    • fn read_slice_{field}(&[u8]) -> [Result<{field_type}, bondrewd::BondrewdSliceError>] {}
    • fn set_slice_{field}(&mut [u8], {field_type}) -> [Result<(), bondrewd::BondrewdSliceError>] {}
  • hex_fns provided from/into hex functions like from/into bytes. the hex inputs/outputs are [u8;N] where N is double the calculated bondrewd STRUCT_SIZE. hex encoding and decoding is based off the hex crate’s from/into slice functions but with statically sized arrays so we could eliminate sizing errors.

Full Example Generated code

use bondrewd::*;
struct SimpleExample {
    one: bool,
    two: f32,
    three: i16,
    four: u8,
}
impl Bitfields<7usize> for SimpleExample {
    const BIT_SIZE: usize = 53usize;
    fn into_bytes(self) -> [u8; 7usize] {
        let mut output_byte_buffer: [u8; 7usize] = [0u8; 7usize];
        let one = self.one;
        output_byte_buffer[0usize] |= ((one as u8) << 7usize) & 128u8;
        let two = self.two;
        let two_bytes = (two.to_bits().rotate_right(1u32)).to_be_bytes();
        output_byte_buffer[0usize] |= two_bytes[0usize] & 127u8;
        output_byte_buffer[1usize] |= two_bytes[1usize];
        output_byte_buffer[2usize] |= two_bytes[2usize];
        output_byte_buffer[3usize] |= two_bytes[3usize];
        output_byte_buffer[4usize] |= two_bytes[0] & 128u8;
        let three = self.three;
        let three_bytes = (three.rotate_right(7u32)).to_be_bytes();
        output_byte_buffer[4usize] |= three_bytes[1usize] & 127u8;
        output_byte_buffer[5usize] |= three_bytes[0] & 254u8;
        let four = self.four;
        let four_bytes = (four.rotate_right(5u32)).to_be_bytes();
        output_byte_buffer[5usize] |= four_bytes[0usize] & 1u8;
        output_byte_buffer[6usize] |= four_bytes[0] & 248u8;
        output_byte_buffer
    }
    fn from_bytes(mut input_byte_buffer: [u8; 7usize]) -> Self {
        let one = Self::read_one(&input_byte_buffer);
        let two = Self::read_two(&input_byte_buffer);
        let three = Self::read_three(&input_byte_buffer);
        let four = Self::read_four(&input_byte_buffer);
        Self {
            one,
            two,
            three,
            four,
        }
    }
}
impl SimpleExample {
    #[inline]
    pub fn read_one(input_byte_buffer: &[u8; 7usize]) -> bool {
        ((input_byte_buffer[0usize] & 128u8) != 0)
    }
    #[inline]
    pub fn read_two(input_byte_buffer: &[u8; 7usize]) -> f32 {
        f32::from_bits(
            u32::from_be_bytes({
                let mut two_bytes: [u8; 4usize] = [0u8; 4usize];
                two_bytes[0usize] |= input_byte_buffer[0usize] & 127u8;
                two_bytes[1usize] |= input_byte_buffer[1usize];
                two_bytes[2usize] |= input_byte_buffer[2usize];
                two_bytes[3usize] |= input_byte_buffer[3usize];
                two_bytes[0] |= input_byte_buffer[4usize] & 128u8;
                two_bytes
            })
            .rotate_left(1u32),
        )
    }
    #[inline]
    pub fn read_three(input_byte_buffer: &[u8; 7usize]) -> i16 {
        i16::from_be_bytes({
            let mut three_bytes: [u8; 2usize] = if (input_byte_buffer[4usize] & 64u8) == 64u8 {
                [1u8, 128u8]
            } else {
                [0u8; 2usize]
            };
            three_bytes[1usize] |= input_byte_buffer[4usize] & 127u8;
            three_bytes[0] |= input_byte_buffer[5usize] & 254u8;
            three_bytes
        })
        .rotate_left(7u32)
    }
    #[inline]
    pub fn read_four(input_byte_buffer: &[u8; 7usize]) -> u8 {
        u8::from_be_bytes({
            let mut four_bytes: [u8; 1usize] = [0u8; 1usize];
            four_bytes[0usize] |= input_byte_buffer[5usize] & 1u8;
            four_bytes[0] |= input_byte_buffer[6usize] & 248u8;
            four_bytes
        })
        .rotate_left(5u32)
    }
    #[inline]
    pub fn write_one(output_byte_buffer: &mut [u8; 7usize], mut one: bool) {
        output_byte_buffer[0usize] &= 127u8;
        output_byte_buffer[0usize] |= ((one as u8) << 7usize) & 128u8;
    }
    #[inline]
    pub fn write_two(output_byte_buffer: &mut [u8; 7usize], mut two: f32) {
        output_byte_buffer[0usize] &= 128u8;
        output_byte_buffer[1usize] = 0u8;
        output_byte_buffer[2usize] = 0u8;
        output_byte_buffer[3usize] = 0u8;
        output_byte_buffer[4usize] &= 127u8;
        let two_bytes = (two.to_bits().rotate_right(1u32)).to_be_bytes();
        output_byte_buffer[0usize] |= two_bytes[0usize] & 127u8;
        output_byte_buffer[1usize] |= two_bytes[1usize];
        output_byte_buffer[2usize] |= two_bytes[2usize];
        output_byte_buffer[3usize] |= two_bytes[3usize];
        output_byte_buffer[4usize] |= two_bytes[0] & 128u8;
    }
    #[inline]
    pub fn write_three(output_byte_buffer: &mut [u8; 7usize], mut three: i16) {
        output_byte_buffer[4usize] &= 128u8;
        output_byte_buffer[5usize] &= 1u8;
        let three_bytes = (three.rotate_right(7u32)).to_be_bytes();
        output_byte_buffer[4usize] |= three_bytes[1usize] & 127u8;
        output_byte_buffer[5usize] |= three_bytes[0] & 254u8;
    }
    #[inline]
    pub fn write_four(output_byte_buffer: &mut [u8; 7usize], mut four: u8) {
        output_byte_buffer[5usize] &= 254u8;
        output_byte_buffer[6usize] &= 7u8;
        let four_bytes = (four.rotate_right(5u32)).to_be_bytes();
        output_byte_buffer[5usize] |= four_bytes[0usize] & 1u8;
        output_byte_buffer[6usize] |= four_bytes[0] & 248u8;
    }
}

Derive Macros

Generates an implementation of bondrewd::BitfieldEnum trait.

Generates an implementation of the bondrewd::Bitfield trait, as well as peek and set functions for direct sized u8 arrays access. this crate is designed so that attributes are only required for fields that are not what you would expect without the attribute. for example if you provide a u8 fields with no attributes, the field would be assumed to be the next 8 bits after the field before it. if a field of bool type without attributes is defined, the field would be assumed to be the next bit after the field before it.