[−][src]Crate modular_bitfield
Provides macros to support bitfield structs allowing for modular use of bit-enums.
The mainly provided macros are #[bitfield]
for structs and
#[derive(BitfieldSpecifier)]
for enums that shall be usable
within bitfield structs.
There are preset bitfield specifiers such as B1
, B2
,..,B64
that allow for easy bitfield usage in structs very similar to how
they work in C or C++.
- Performance of the macro generated code is as fast as its hand-written alternative.
- Compile-time checks allow for safe usage of bitfield structs and enums.
Showcase
use modular_bitfield::prelude::*; // Works with aliases - just for the showcase. type Vitamin = B12; /// Bitfield struct with 32 bits in total. #[bitfield] #[derive(Debug, PartialEq, Eq)] pub struct Example { a: bool, // Uses 1 bit b: B9, // Uses 9 bits c: Vitamin, // Uses 12 bits, works with aliases. #[bits = 3] // Optional, asserts at compiletime that `DeliveryMode` uses 3 bits. d: DeliveryMode, // Uses 3 bits e: B7, // Uses 7 bits } /// Enums that derive from `BitfieldSpecifier` /// can also be used within bitfield structs /// as shown above. #[derive(BitfieldSpecifier, Debug, PartialEq)] pub enum DeliveryMode { Fixed = 1, Lowest, SMI, RemoteRead, NMI, Init = 0, Startup = 6, External, } fn main() { let mut example = Example::new(); // Assert that everything is inizialized to 0. assert_eq!(example.get_a(), false); assert_eq!(example.get_b(), 0); assert_eq!(example.get_c(), 0); assert_eq!(example.get_d(), DeliveryMode::Init); assert_eq!(example.get_e(), 0); // Modify the bitfields. example.set_a(true); example.set_b(0b0001_1111_1111_u16); // Uses `u16` example.set_c(42_u16); // Uses `u16` example.set_d(DeliveryMode::Startup); example.set_e(1); // Uses `u8` // Assert the previous modifications. assert_eq!(example.get_a(), true); assert_eq!(example.get_b(), 0b0001_1111_1111_u16); assert_eq!(example.get_c(), 42); assert_eq!(example.get_d(), DeliveryMode::Startup); assert_eq!(example.get_e(), 1_u8); // Safe API allows for better testing assert_eq!(example.set_e_checked(200), Err(Error::OutOfBounds)); // Can convert from and to bytes. assert_eq!(example.to_bytes(), &[255, 171, 128, 3]); use std::convert::TryFrom as _; let copy = Example::try_from(example.to_bytes()).unwrap(); assert_eq!(example, copy); }
Generated Structure
From David Tolnay's procedural macro workshop:
The macro conceptualizes given structs as a sequence of bits 0..N. The bits are grouped into fields in the order specified by the struct written by the user.
The #[bitfield]
attribute rewrites the caller's struct into a private byte array representation
with public getter and setter methods for each field.
The total number of bits N is required to be a multiple of 8: This is checked at compile time.
Example
The following invocation builds a struct with a total size of 32 bits or 4 bytes.
It places field a
in the least significant bit of the first byte,
field b
in the next three least significant bits,
field c
in the remaining four most significant bits of the first byte,
and field d
spanning the next three bytes.
use modular_bitfield::prelude::*; #[bitfield] pub struct MyFourBytes { a: B1, b: B3, c: B4, d: B24, }
least significant bit of third byte
┊ most significant
┊ ┊
┊ ┊
║ first byte ║ second byte ║ third byte ║ fourth byte ║
╟───────────────╫───────────────╫───────────────╫───────────────╢
║▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒ ▒║
╟─╫─────╫───────╫───────────────────────────────────────────────╢
║a║ b ║ c ║ d ║
┊ ┊
┊ ┊
least significant bit of d most significant
Modules
prelude | The prelude: |
specifiers | The default set of predefined specifiers. |
Enums
Error | Error that can be encountered operating on bitfields. |
Traits
Specifier | Trait implemented by all bitfield specifiers. |
Attribute Macros
bitfield | Attribute applicable to structs that turns them into bitfield structs. |
Derive Macros
BitfieldSpecifier |