Macro bit_struct

Source
macro_rules! bit_struct {
    (
        $(
        $(#[$meta:meta])*
        $struct_vis: vis struct $name: ident ($kind: ty) {
        $(
            $(#[$field_meta:meta])*
            $field: ident: $actual: ty
        ),* $(,)?
        }
        )*
    ) => { ... };
}
Expand description

Create a bit struct.

This macro can only be used once for each module. This is because the macro creates sub-module to limit access to certain unsafe access. In the macro, bit-structs can be defined just like a struct outside of the the macro. The catch is a base type must be specified. Valid base types are u{8,16,32,64,128}. The elements stored in the struct are statically guaranteed to not exceed the number of bits in the base type. This means we cannot store a u16 in a u8, but it also means we cannot store 9 u1s in a u8.

Elements start at the top of the number (for a u16 this would be the 15th bit) and progress down.

ยงExample

bit_struct::enums! {
    /// The default value for each enum is always the first
    pub ThreeVariants { Zero, One, Two }

    /// This is syntax to set the default value to Cat
    pub Animal(Cat) { Cow, Bird, Cat, Dog }

    pub Color { Orange, Red, Blue, Yellow, Green }
}

bit_struct::bit_struct! {
    /// We can write documentation for the struct here.
    struct BitStruct1 (u16){
        /// a 1 bit element. This is stored in u16[15]
        a: bit_struct::u1,

        /// This is calculated to take up 2 bits. This is stored in u16[13..=14]
        variant: ThreeVariants,

        /// This also takes 2 bits. This is stored in u16[11..=12]
        animal: Animal,

        /// This takes up 3 bits. This is stored u16[8..=10]
        color: Color,
    }

    struct BitStruct2(u32) {
        /// We could implement for this too. Note, this does not have a default
        a_color: Color,
        b: bit_struct::u3,
    }
}

fn main() {
    use std::convert::TryFrom;
    let mut bit_struct: BitStruct1 = BitStruct1::of_defaults();

    assert_eq!(bit_struct.a().start(), 15);
    assert_eq!(bit_struct.a().stop(), 15);

    assert_eq!(bit_struct.color().start(), 8);
    assert_eq!(bit_struct.color().stop(), 10);

    assert_eq!(
        format!("{:?}", bit_struct),
        "BitStruct1 { a: 0, variant: Zero, animal: Cat, color: Orange }"
    );
    assert_eq!(bit_struct.raw(), 4096);

    let reverse_bit_struct = BitStruct1::try_from(4096);
    assert_eq!(
        format!("{:?}", reverse_bit_struct),
        "Ok(BitStruct1 { a: 0, variant: Zero, animal: Cat, color: Orange })"
    );

    // u3! macro provides a static assert that the number is not too large
    let mut other_struct = BitStruct2::new(Color::Green, bit_struct::u3!(0b101));
    assert_eq!(
        format!("{:?}", other_struct),
        "BitStruct2 { a_color: Green, b: 5 }"
    );

    assert_eq!(other_struct.a_color().get(), Color::Green);

    other_struct.a_color().set(Color::Red);

    assert_eq!(other_struct.a_color().get(), Color::Red);
}