# capos-bitstruct: Rust structures with bitfields.
`bitstruct!` is a procedure macro that enables the definition of Rust
structures whose integer or boolean typed fields may be subdivided into
bitfields. bitstruct! is compatible with _any_ struct representation supported
by Rust.
Rust has many packages designed to add bitfield-like behavior to the language.
From the perspective of someone
## Overview
The macro passes the rust structure through to Rust without the bitfield
definitions, but implements getters, setters, and stream-style setters for the
bitfields _and_ their associated structure fields. Signed value types are
appropriately sign-extended by the getter.
Here's an excerpted example:
```rust
bitstruct! {
struct MultiField {
pub cw: u32 { // The control word has bitfields
swizzled: bool 1, // single bit field at bit 0
capType: u8 5, // 5 bit field at bit 1
_: u8 2 = 0, // 2 bit "hole" at bit 6
restrictions: u8 5, // value accepted/returned as u8
},
float_value: f32, // no bitfields => ordinary structure field
}
}
```
Types given at the bitfield level indicate the value type used by the accessors
and mutators, which may be a `bool`, any fixed-width integer type not larger
than the containing field type or numeric enum types that implement the
`core::convert::From` trait. Boolean bitfields occupy a single bit.
For each subdivided structure field, one or more bitfield definition blocks may
be specified. Each bitfield definition block specifies in sequence, from least
significant bit to most significant bit, a non-overlapping subdivision of the
containing field. Bits to be skipped are specified by using '\_' as the field
identifier. Additional blocks may be provided to specify _other_ possible
subdivisions of the containing field.
So, for example, an x86 data register might be described by:
```rust
bitstruct! {
/// x86 data register layout
struct X86DataReg {
pub eax: u32 {
al: u8 8,
ah: u8 8,
}, { // Separate block because this overlaps ah, al:
ax: u16 16,
},
}
}
```
## Initializers
Initializers can be provided for any bifield defined in the first bitfield
block. These are gathered by the proc-macro into a stream-style method
`init_bitstruct()` that can be called from `new()` or from your implementation
of the `Default` trait. `init_bitstruct()` first zeros the containing structure
field and then sets the defaults given for the individual fields. Bitfields
lacking a specified default value are initialized to zero.
Initializers are _only_ gathered for bitfields and the structure fields that
contain them. If no initializers are provided, the containing structure field is
initialized to zero if the `init_bitstruct()` function is called.
It is unspecified how the initialization is accomplished within
`init_bistruct()`. Logically, the struct field is initialized first, and then
any bitfields _in the first bitfield block_ are initialized. Given:
```rust
bitstruct! {
/// x86 data register layout
#[repr(C)]
struct X86DataReg {
pub eax: u32 {
al: u8 8 = 0x01,
ah: u8 8 = 0x11,
}, { // Separate block because this overlaps ah, al:
ax: u16 16,
},
}
}
```
It is _as if_ the initializers were performed by:
```
self
.set_eax(0)
.set_al(0x01)
.set_ah(0x11)
```
and the eventual `eax` value will be `0x00001101`.
## Reserved and Undefined Fields
Hardware vendors sometimes decide to reserve certain bitfields and specify their
values. This can be captured in a `bitstruct` with an initialized pad field in
the first initializer block. This should be done in the first initializer block.
Multiple pags can be declared.
Hardware vendors who have done a less diligent job of studying how good
specification is done are sometimes prone to define a bit sub-range as
undefined, meaning they won't tell you what the value should be but you return
whatever value they gave you when re-loading the applicable hardware register.
Best practice in this case is to define the _field_ holding this value using a
type that matches the register type, initialize the structure using the value
retrieved from the register, and declare a bitfield block using the (re-useable) name
`UNDEFINED` to mark where these bits appear.
The 80386 EFLAGS register uses both practices:
```rust
bitstruct! {}
#[allow(non_snake_case)]
#[repr(C)]
struct EFLAGS {
pub eflags: u32 {
CF: u32 1,
_ u32 1 = 1, // Intel-specified value
PF: u32 1,
UNDEFINED: u32 1, // Intel does not say
AF: u32 1,
UNDEFINED: u32 1,
ZF: u32 1,
SF: u32 1,
TF: u32 1,
IF: u32 1,
DF: u32 1,
OF: u32 1,
IOPL: u32 2,
NT: u32 1,
UNDEFINED: u32 1,
RF: u32 1,
VM: u32 1,
UNDEFINED: u32 14,
}, {
flags: u32 16, // legacy name on 80286
}
}
}
```
In this example the snake_case requirement has been enabled to allow
the bitfield names to match Intel's documentation exactly.
## Excluded Features
Many of the alternative bitfield packages offer the option to define fields
starting with the most significant bit (MSB) rather than the least significant
bit (LSB). The same result can be had in a `bitstruct` by ensuring that all bits
are specified in the bitfield block and then reversing their order of
occurrence.
## Missing Features
At the moment, bitstruct! cannot be applied to anonymous struct definitions.
The option to provide multiple bitfield blocks offers some of the flavor of a
union type. Our original use-case for bitstruct actually uses it in this way. I
expect that we will implement a mechanism for such guards in a future release of
`bitstruct`.
## Alternative Crates to Consider
A search on [crates.io](http://crates.io) for "bitfield" will return half a
dozen or more. In all of the cases I have exaamined, the approach taken by these
crates is to define bitfields over a single integer at a time. Several are
widely used and well regarded.
When a structure has many fields with bit sub-ranges, building them up by
defining seprate structure types for each field can generate a lot of program
text very quickly. Bitstruct can be used that way, but it is designed with a
better localized approach in mind. Ironically the result was simpler to
implement; once the `bitsruct!` macro has expanded its structure, the result is a
valid Rust structure with an `impl` block.
# Feedback
I receive an overwhelming amount of spam. Please feel free to open issues and
discussions on Github, and I will respond as I am able.