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 Generated Functions:
- Conversion between a sized u8 array and the rust structure you define.
- Peek and Set functions that allow the field to be accessed or overwritten within a sized u8 array.
For example we can define a data structure with 5 total bytes as:
- a field named one will be the first 3 bits.
- a field named two will be the next 19 bits.
- a field named six will be the next 14 bits.
- a field named four will be the next 4 bits.
// Users code
use bondrewd::*;
#[derive(Bitfields)]
#[bondrewd(default_endianness = "be")]
struct SimpleExample {
#[bondrewd(bit_length = 3)]
one: u8,
#[bondrewd(bit_length = 19)]
two: u32,
#[bondrewd(bit_length = 14)]
six: u16,
#[bondrewd(bit_length = 4)]
four: u8,
}
ⓘ
// Generated Code
impl Bitfields<5usize> for SimpleExample {
const BIT_SIZE: usize = 40usize;
fn into_bytes(self) -> [u8; 5usize] { .. }
fn from_bytes([u8; 5usize]) -> Self { .. }
}
impl SimpleExample {
pub fn peek_one(&[u8; 5usize]) -> u8 { .. }
pub fn peek_two(&[u8; 5usize]) -> u32 { .. }
pub fn peek_six(&[u8; 5usize]) -> u16 { .. }
pub fn peek_four(&[u8; 5usize]) -> u8 { .. }
pub fn set_one(&mut [u8; 5usize], u8) { .. }
pub fn set_two(&mut [u8; 5usize], u32) { .. }
pub fn set_six(&mut [u8; 5usize], u16) { .. }
pub fn set_four(&mut [u8; 5usize], u8) { .. }
}
Supported Field Types
- All primitives other than usize and isize (i believe ambiguous sizing is bad for this type of work).
- Enums which implement the BitfieldEnum trait in bondrewd.
- Structs which implement the Bitfield trait in bondrewd.
Struct Attributes
default_endianness = {"le" or "be"}
describes a default endianness for primitive fields.read_from = {"msb0" or "lsb0"}
defines bit positioning. which end of the byte array to start at.enforce_bytes = {BYTES}
defines a required resulting BIT_SIZE divided by 8 of the structure in condensed form.enforce_bits = {BYTES}
defines a required resulting BIT_SIZE of the structure in condensed form.enforce_full_bytes
defines that the resulting BIT_SIZE is required to be a multiple of 8.reverse
defines that the entire byte array should be reversed before reading. no runtime cost.
Field Attributes
bit_length = {BITS}
define the total amount of bits to use when condensed.byte_length = {BYTES}
define the total amount of bytes to use when condensed.endianness = {"le" or "be"}
define per field endianess.block_bit_length = {BITS}
describes a bit length for the entire array dropping lower indexes first. (default array type)block_byte_length = {BYTES}
describes a byte length for the entire array dropping lower indexes first. (default array type)element_bit_length = {BITS}
describes a bit length for each element of an array.element_byte_length = {BYTES}
describes a byte length for each element of an array.enum_primitive = "u8"
defines the size of the enum. the BitfieldEnum currently only supports u8.struct_size = {SIZE}
defines the field as a struct which implements the Bitfield trait and the BYTE_SIZE const defined in said trait.reserve
defines that this field should be ignored in from and into bytes functions.- /!Untested!\
bits = "RANGE"
- define the bit indexes yourself rather than let the proc macro figure it out. using a rust range in quotes.
Crate Features:
slice_fns
generates slice functions:fn peek_slice_{field}(&[u8]) -> Result<{field_type}, BondrewdSliceError> {}
fn set_slice_{field}(&mut [u8], {field_type}) -> Result<(), 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 SimpleFull {
one: u8,
two: u32,
six: u16,
four: u8,
}
impl Bitfields<5usize> for SimpleFull {
const BIT_SIZE: usize = 40usize;
fn into_bytes(self) -> [u8; 5usize] {
let mut output_byte_buffer: [u8; 5usize] = [0u8; 5usize];
output_byte_buffer[0usize] |= ((self.one as u8) << 5usize) & 224u8;
let two_bytes = (self.two.rotate_left(2u32)).to_be_bytes();
output_byte_buffer[0usize] |= two_bytes[1usize] & 31u8;
output_byte_buffer[1usize] |= two_bytes[2usize];
output_byte_buffer[2usize] |= two_bytes[3usize] & 252u8;
let six_bytes = (self.six.rotate_right(4u32)).to_be_bytes();
output_byte_buffer[2usize] |= six_bytes[0usize] & 3u8;
output_byte_buffer[3usize] |= six_bytes[1usize];
output_byte_buffer[4usize] |= six_bytes[0] & 240u8;
output_byte_buffer[4usize] |= ((self.four as u8) << 0usize) & 15u8;
output_byte_buffer
}
fn from_bytes(mut input_byte_buffer: [u8; 5usize]) -> Self {
let one = Self::peek_one(&input_byte_buffer);
let two = Self::peek_two(&input_byte_buffer);
let six = Self::peek_six(&input_byte_buffer);
let four = Self::peek_four(&input_byte_buffer);
Self {
one,
two,
six,
four,
}
}
}
impl SimpleFull {
#[inline]
pub fn peek_one(input_byte_buffer: &[u8; 5usize]) -> u8 {
((input_byte_buffer[0usize] & 224u8) >> 5usize) as u8
}
#[inline]
pub fn peek_two(input_byte_buffer: &[u8; 5usize]) -> u32 {
u32::from_be_bytes({
let mut two_bytes: [u8; 4usize] = [0u8; 4usize];
two_bytes[1usize] = input_byte_buffer[0usize] & 31u8;
two_bytes[2usize] |= input_byte_buffer[1usize];
two_bytes[3usize] |= input_byte_buffer[2usize] & 252u8;
two_bytes
})
.rotate_right(2u32)
}
#[inline]
pub fn peek_six(input_byte_buffer: &[u8; 5usize]) -> u16 {
u16::from_be_bytes({
let mut six_bytes: [u8; 2usize] = [0u8; 2usize];
six_bytes[0usize] = input_byte_buffer[2usize] & 3u8;
six_bytes[1usize] |= input_byte_buffer[3usize];
six_bytes[0] |= input_byte_buffer[4usize] & 240u8;
six_bytes
})
.rotate_left(4u32)
}
#[inline]
pub fn peek_four(input_byte_buffer: &[u8; 5usize]) -> u8 {
((input_byte_buffer[4usize] & 15u8) >> 0usize) as u8
}
#[inline]
pub fn set_one(output_byte_buffer: &mut [u8; 5usize], one: u8) {
output_byte_buffer[0usize] &= 31u8;
output_byte_buffer[0usize] |= ((one as u8) << 5usize) & 224u8;
}
#[inline]
pub fn set_two(output_byte_buffer: &mut [u8; 5usize], two: u32) {
output_byte_buffer[0usize] &= 224u8;
output_byte_buffer[2usize] &= 3u8;
let two_bytes = (two.rotate_left(2u32)).to_be_bytes();
output_byte_buffer[0usize] |= two_bytes[1usize] & 31u8;
output_byte_buffer[1usize] |= two_bytes[2usize];
output_byte_buffer[2usize] |= two_bytes[3usize] & 252u8;
}
#[inline]
pub fn set_six(output_byte_buffer: &mut [u8; 5usize], six: u16) {
output_byte_buffer[2usize] &= 252u8;
output_byte_buffer[3usize] = 0u8;
output_byte_buffer[4usize] &= 15u8;
let six_bytes = (six.rotate_right(4u32)).to_be_bytes();
output_byte_buffer[2usize] |= six_bytes[0usize] & 3u8;
output_byte_buffer[3usize] |= six_bytes[1usize];
output_byte_buffer[4usize] |= six_bytes[0] & 240u8;
}
#[inline]
pub fn set_four(output_byte_buffer: &mut [u8; 5usize], four: u8) {
output_byte_buffer[4usize] &= 240u8;
output_byte_buffer[4usize] |= ((four as u8) << 0usize) & 15u8;
}
}
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.