chapa 0.5.0

Bitfield structs, batteries included!
Documentation
#![cfg(feature = "reflection")]

use chapa::{bitfield, BitEnum, EnumInfo, FieldInfo, FieldKind};

#[derive(Debug, PartialEq, Clone, Copy, BitEnum)]
pub enum Mode {
    Off = 0,
    On = 1,
    #[fallback]
    Reserved = 3,
}

#[bitfield(u8, order = lsb0)]
#[derive(Copy, Clone)]
pub struct Inner {
    #[bits(0..=1)]
    lo: u8,
    #[bits(2..=3)]
    hi: u8,
}

#[bitfield(u16, order = lsb0)]
#[derive(Copy, Clone)]
pub struct Reg {
    #[bits(0)]
    enabled: bool,
    #[bits(1..=2)]
    mode: Mode,
    #[bits(4..=7)]
    count: u8,
    #[bits(8..=11)]
    inner: Inner,
}

fn field<'a>(fields: &'a [FieldInfo], name: &str) -> &'a FieldInfo {
    fields
        .iter()
        .find(|f| f.name == name)
        .expect("field exists")
}

#[test]
fn bool_field() {
    let f = field(Reg::FIELDS, "enabled");
    assert_eq!(f.offset, 0);
    assert_eq!(f.width, 1);
    assert!(matches!(f.kind, FieldKind::Bool));
}

#[test]
fn uint_field() {
    let f = field(Reg::FIELDS, "count");
    assert_eq!(f.offset, 4);
    assert_eq!(f.width, 4);
    assert!(matches!(f.kind, FieldKind::Uint));
}

#[test]
fn enum_field_resolves_variants() {
    let f = field(Reg::FIELDS, "mode");
    assert_eq!(f.offset, 1);
    assert_eq!(f.width, 2);
    let info: &EnumInfo = match f.kind {
        FieldKind::Enum(info) => info,
        _ => panic!("expected enum kind"),
    };
    assert_eq!(info.name, "Mode");
    assert_eq!(
        info.variants,
        &[(0u128, "Off"), (1u128, "On"), (3u128, "Reserved")]
    );
}

#[test]
fn nested_struct_recurses() {
    let f = field(Reg::FIELDS, "inner");
    assert_eq!(f.offset, 8);
    assert_eq!(f.width, 4);
    let inner: &[FieldInfo] = match f.kind {
        FieldKind::Struct(fields) => fields,
        _ => panic!("expected struct kind"),
    };
    assert_eq!(inner.len(), 2);
    assert_eq!(field(inner, "lo").offset, 0);
    assert_eq!(field(inner, "hi").offset, 2);
}