Skip to main content

Crate chapa

Crate chapa 

Source
Expand description

§chapa

Bitfield structs, batteries included!

chapa exposes a single attribute macro, bitfield, that turns an ordinary struct into a newtype backed by a single primitive. Every field maps to an exact range of bits and gets a generated getter, setter, and with_* builder.

§Features

  • MSB0 and LSB0 support: Naturally write bit orders as per datasheet
  • Enum fields: Use enums as bitfield fields with #[derive(BitEnum)]
  • Nested bitfields: Embed one bitfield struct inside another
  • Readonly fields: Suppress setter generation with readonly or a leading _ prefix
  • Aliases: Expose extra accessor names with alias = "name" or alias = ["a", "b"]
  • Overlays: Allow multiple logically distinct field groups to share the same bit range
  • Bitwise operators: &, |, ^, !, &=, |=, ^= with the backing storage type work directly on the struct
  • Bit extraction: extract_bits! masks a value to keep only the specified bit ranges

§Quick start

use chapa::bitfield;

// An 8-bit status register, bit 0 is the LSB
#[bitfield(u8, order = lsb0)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct StatusReg {
    #[bits(0)] enabled: bool,
    #[bits(1..=3)] mode: u8,
    #[bits(4..=7)] _reserved: u8, // Can be omitted; "_" makes it readonly
}

let r = StatusReg::new()
    .with_enabled(true)
    .with_mode(5);

assert_eq!(r.enabled(), true);
assert_eq!(r.mode(), 5);
assert_eq!(r.reserved(), 0); // accessible as `reserved`, not `_reserved`

§#[bitfield(...)] options

OptionRequiredDescription
u8 / u16 / u32 / u64 / u128YesBacking storage type
order = msb0 / order = lsb0YesBit numbering convention
width = NNoEffective logical width, must be <= storage width

§#[bits(...)] options

OptionDescription
NSingle bit at index N
N..=MInclusive range from bit N to bit M
N..MHalf-open range (equivalent to N..=(M-1))
readonlySuppress set_* and with_* generation
alias = "name"Generate additional accessor under name
alias = ["a","b"]Multiple aliases
overlay = "group"Allow overlap with fields in other overlay groups

§MSB-0 example

use chapa::bitfield;

// A 32-bit value where bit 0 is the most-significant bit
#[bitfield(u32, order = msb0)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct ControlWord {
    #[bits(0..=3)] opcode: u8,
    #[bits(4..=7)] dst: u8,
    #[bits(8..=31, readonly)] payload: u32,
}

let cw = ControlWord::new()
    .with_opcode(0xA)
    .with_dst(0x3);
assert_eq!(cw.raw(), 0xA300_0000);

§Enum fields

Use #[derive(BitEnum)] on an enum to automatically implement BitField, allowing it to be used as a bitfield field type. Copy and Clone are derived automatically.

Note: Invalid raw values map to the last variant.

use chapa::{bitfield, BitEnum};

#[derive(Debug, PartialEq, BitEnum)]
pub enum VideoFormat {
    Ntsc = 0,
    Pal = 1,
    Mpal = 2,
    Debug = 3,
}

#[bitfield(u16, order = lsb0)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct DisplayConfig {
    #[bits(0)] enable: bool,
    #[bits(1..=2)] fmt: VideoFormat,
}

let dc = DisplayConfig::new()
    .with_enable(true)
    .with_fmt(VideoFormat::Pal);
assert_eq!(dc.fmt(), VideoFormat::Pal);

§Nested bitfields

A field whose type implements BitField (i.e. any type annotated with #[bitfield]) can be used as a nested field.

use chapa::bitfield;

#[bitfield(u8, order = msb0, width = 4)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Nibble {
    #[bits(0..=1)] high: u8,
    #[bits(2..=3)] low: u8,
}

#[bitfield(u32, order = msb0)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Word {
    #[bits(0..=3)] top: Nibble,
    #[bits(28..=31)] bot: u8,
}

§Overlay groups

Fields in different overlay groups may share bit ranges. This is useful for instruction formats where the same bits are interpreted differently depending on other bits, such as instruction decoding or MMIO registers that change meaning based on encoded bits.

use chapa::bitfield;

#[bitfield(u32, order = msb0)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Instr {
    #[bits(0..=5)] opcode: u8,

    #[bits(6..=10,  overlay = "r_form")] rs: u8,
    #[bits(11..=15, overlay = "r_form")] ra: u8,
    #[bits(16..=20, overlay = "r_form")] rb: u8,

    #[bits(6..=10,  overlay = "i_form")] dst: u8,
    #[bits(11..=31, overlay = "i_form")] imm: u32,
}

§Bitwise operations

Every bitfield struct implements BitAnd, BitOr, BitXor, Not, BitAndAssign, BitOrAssign, and BitXorAssign against its backing storage type.

use chapa::bitfield;

#[bitfield(u32, order = msb0)]
#[derive(Copy, Clone, PartialEq, Debug)]
pub struct StatusReg {
    #[bits(0)] enabled: bool,
    #[bits(1..=7)] flags: u8,
}

const MASK: u32 = 0x0000_00FF;
let a = StatusReg::new().with_enabled(true);
let b: u32 = 0x0000_00AA;

let result = (a & !MASK) | (b & MASK); // result: StatusReg

§Bit extraction with extract_bits!

extract_bits! keeps only the specified bit positions from a value, zeroing all others. Bits can be single indices or inclusive ranges; the ordering and storage type are either supplied explicitly (for raw integers) or deduced from the struct’s BitField impl.

use chapa::{bitfield, extract_bits};

#[bitfield(u32, order = msb0)]
#[derive(Copy, Clone)]
pub struct Msr { /* ... */ }

let msr = Msr::from_raw(0xFFFF_FFFF);

// Struct form: ordering deduced; returns Msr with non-selected bits zeroed
let masked: Msr = extract_bits!(msr; 0..=0, 5..=9, 16..=31);

// Explicit form for raw integers: const-evaluated mask
let raw: u32 = extract_bits!(msb0 u32; 0xFFFF_FFFFu32; 0, 5..=9, 16..=31);
assert_eq!(raw, masked.raw());

See the extract_bits! documentation for full syntax details.

§Generated API

For a field foo: u8 spanning bits 4..=7 the macro generates:

ItemSignature
Constantpub const FOO_SHIFT: u32
Constantpub const FOO_MASK: StorageType
Getterpub const fn foo(&self) -> u8
Setterpub fn set_foo(&mut self, val: u8)
Builderpub const fn with_foo(self, val: u8) -> Self

Additionally, every struct implements the following traits:

TraitSignature
BitAndfn bitand(self, rhs: StorageType) -> Self
BitOrfn bitor(self, rhs: StorageType) -> Self
BitXorfn bitxor(self, rhs: StorageType) -> Self
Notfn not(self) -> Self
BitAndAssignfn bitand_assign(&mut self, rhs: StorageType)
BitOrAssignfn bitor_assign(&mut self, rhs: StorageType)
BitXorAssignfn bitxor_assign(&mut self, rhs: StorageType)

Re-exports§

pub use mask::lsb0_mask;
pub use mask::msb0_mask;

Modules§

mask
Utilities for masking raw integers by bit ranges.

Macros§

extract_bits
Keep only the specified bits from a value.

Traits§

BitField
Trait implemented by every struct produced by the bitfield macro and every enum annotated with #[derive(BitEnum)].
BitStorage
Trait for types that can be used as the backing storage of a bitfield.

Attribute Macros§

bitfield
The #[bitfield] attribute macro.

Derive Macros§

BitEnum
Derive macro that implements chapa::BitField for C-like enums.