Bit-level packing and unpacking
Packing and unpacking bit-level structures is usually a programming tasks that needlessly reinvents the wheel. This library provides a meta-programming aproach, using attributes to document fields and how they should be packed. The resulting trait implementations provide safe packing, unpacking and runtime debugging formatters with per-field documentation generated for each structure.
Features
- Plain Rust structures, decorated with attributes
- MSB or LSB integers of user-defined bit widths
- Primitive enum code generation helper
- MSB or LSB bit positioning
- Documents the field’s packing table
- Runtime packing visualization
- Nested packed types
- Arrays
- Reserved fields
Sample packed structure
/// Control register, address 0xA0.
#[derive(PackedStruct, Debug, Copy, Clone, PartialEq)]
#[packed_struct(bit_numbering="msb0")]
pub struct ControlRegister {
/// Sensor's power mode
#[packed_field(bits="0:1", ty="enum")]
pub power_mode: PowerMode,
/// Voltage on the input. [mV]
#[packed_field(bits="3:7")]
pub voltage_milli_volts: Integer<u8, packed_bits::Bits5>,
/// Is the standby LED enabled?
#[packed_field(bits="8")]
pub standby_led_enabled: bool,
/// Which of the four gain stages are active
#[packed_field(bits="9:12")]
pub gain_stages: [bool; 4],
/// Reserved bits, always 1
#[packed_field(bits="13:15")]
pub _reserved: ReservedOnes<packed_bits::Bits3>,
/// Sensor's reading
#[packed_field(bits="16:31", endian="lsb")]
pub sensor_value: i16
}
#[derive(PrimitiveEnum, Debug, Copy, Clone, PartialEq)]
pub enum PowerMode {
/// The sensor is turned off
Off = 0,
/// The sensor can be triggered by an external source
Standby = 1,
/// Digital logic is on and waiting
LowPower = 2,
/// The sensor is enabled and turned on
On = 3
}
Usage
let reg = ControlRegister {
power_mode: PowerMode::LowPower,
voltage_milli_volts: 11.into(),
standby_led_enabled: true,
gain_stages: [true, true, false, false],
_reserved: Default::default(),
sensor_value: -1503
};
let packed: [u8; 4] = reg.pack();
let unpacked = ControlRegister::unpack(&[0x8B, 0xE7, 0x21, 0xFA]).unwrap();
Packing table in the documentation
Runtime display formatter
ControlRegister (4 bytes)
Decimal
[139, 231, 33, 250]
Hex
[0x8B, 0xE7, 0x21, 0xFA]
Binary
[0b10001011, 0b11100111, 0b00100001, 0b11111010]
power_mode | bits 0:1 | 0b10 | "LowPower"
voltage_milli_volts | bits 3:7 | 0b01011 | "11"
standby_led_enabled | bits 8:8 | 0b1 | "true"
gain_stages[0] | bits 9:9 | 0b1 | "true"
gain_stages[1] | bits 10:10 | 0b1 | "true"
gain_stages[2] | bits 11:11 | 0b0 | "false"
gain_stages[3] | bits 12:12 | 0b0 | "false"
_reserved | bits 13:15 | 0b111 | "Reserved - always 1"
sensor_value | bits 16:31 | 0b0010000111111010 | "-1503"