7 releases (4 breaking)

0.5.1 Feb 19, 2020
0.5.0 Feb 19, 2020
0.4.0 Feb 16, 2020
0.3.0 Feb 11, 2020
0.1.1 Feb 10, 2020

#1289 in Development tools

MIT/Apache

17KB
272 lines

Macros for working with bitfields.

This crate contains the bitfield! macro and BitEnum derive.

bitfield! is used to generate (const fn) getter and setter methods on bitfields. BitEnum allows an enum to be used as a field value.

Example

use bitbash::{bitfield, BitEnum};

bitfield! {
    #[derive(Copy, Clone, PartialEq, Eq)]
    pub struct Foo(u16);

    pub new(bar);
    derive_debug;

    pub field bar: Bar = [0..3];
    pub field baz: usize = [3..7] ~ [8..12];
    pub field quux: bool = [7];
}

#[derive(BitEnum, Copy, Clone, PartialEq, Eq, Debug)]
pub enum Bar {
    A = 0b101,
    B = 0b010,
}

fn main() {
    let mut foo = Foo::new(Bar::A).with_baz(0xcd);
    foo.set_quux(true);
    assert_eq!(foo.bar(), Bar::A);
    assert_eq!(foo.baz(), 0xcd);
    assert!(foo.quux());
    assert_eq!(foo.0, ((Bar::A as u16) << 0) | (0xd << 3) | (0xc << 8) | (1 << 7));
}

bitfield! macro

Supported structs

The bitfield! macro supports three kinds of structs: a tuple struct of an unsigned integer, a tuple struct of an array of unsigned integers, and a regular struct.

bitfield! {
    struct Foo(u8);

    field a: bool = [7];
}

bitfield! {
    struct Bar([u32; 2]);

    field a: bool = 0[7];
    field b: bool = 1[7];
}

bitfield! {
    struct Baz {
        _padding: [u32; 1],
        apple: u32,
        banana: u32,
    }

    field a: bool = apple[7];
}

Regular structs may contain types that are not unsigned integers, however they cannot be referred to by fields.

(pub) field

A field statement defines in which bits a value is stored. Fields can refer to a single bit, a range of bits, a concatenation of bits, or a mapping of bits in the value to bits in the bitfield:

bitfield! {
    struct Foo([u32; 2]);

    field single: bool = 0[0];
    field range: u8 = 0[0..8];
    field concatenation: u16 = 0[0..8] ~ 1[8..16];
    field mapping: u32 {
        [8..16] => 1[8..16],
        [31] => 0[31],
    }
}

By default, three methods are generated for each field: a getter, a setter, and a builder:

fn field_name(&self) -> Value;
fn set_field_name(&mut self, value: Value);
fn with_field_name(self, value: Value) -> Self;

To only generate the getter, use the #[ro] attribute. To make the setter and builder of a pub field private, use the #[private_write] attribute.

When a field is read, its bits must be a valid representation of the value. When a field is written, only the bits in the value that are referred to by the field may be set. If these requirements are not met a panic occurs.

Referring to bits that do not exist causes either a compile-time error or a runtime error, depending on whether const fn code was generated.

Construction of values is done entirely in safe code. Moreover, no unsafe code is generated by the macros in this crate.

(pub) new()

When the new() statement is specified, an fn new() method that zero-initializes the bitfield is generated. Fields for which zero is not a valid representation can be passed as parameters to the new() statement to generate a method which takes their initial values as parameters:

bitfield! {
    struct Foo(u32);

    new(a);

    field a: Bar = [0..3];
}

#[derive(BitEnum)]
enum Bar {
    A = 0b101,
    B = 0b010,
}

fn main() {
    let _ = Foo::new(Bar::A);
}

When the bitfield has been constructed, the new method reads all fields to ensure that no invalid representations exist in the bitfield. This behaviour can be disabled by using the #[disable_check] attribute.

new() does not support structs that contain types that are not (arrays of) unsigned integers.

derive_debug

The derive_debug statement implements core::fmt::Debug for the bitfield. The underlying representation is not printed.

const fn

To generate const fn methods, build the bitbash crate with the "const" feature. Alternatively, use the bitflags_const! macro.

A nightly compiler is required and the #![feature(const_fn, const_panic, const_if_match, const_mut_refs)] features must be enabled.

ConvertRepr trait

Bitfield values must implement the ConvertRepr trait. It is implemented for all unsigned integer types and types that derive BitEnum.

The try_from_repr and into_repr methods are used in non-const fn bitfields. Implement const_try_from_repr and const_into_repr on your types to also use them in const fn bitfields.

BitEnum derive

The BitEnum derive implements ConvertRepr for C-style enums.

Enums that derive BitEnum can be used in both const fn and non-const fn bitfields.

Dependencies

~1.5MB
~37K SLoC