Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Bitfield

Define and operate on a type represented as a bitfield

bitflags no_std

Creates a type safe bitfield type MyFlags with the bitflags! macro. The macro generates the bitwise operators (|, &, - and !) along with methods such as contains, bits and from_bits_truncate. clear comes from the Flags trait, which must be in scope. Deriving Debug prints the names of the set flags.

use bitflags::{Flags, bitflags};

bitflags! {
    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
    struct MyFlags: u32 {
        const FLAG_A = 0b00000001;
        const FLAG_B = 0b00000010;
        const FLAG_C = 0b00000100;
        const FLAG_ABC = Self::FLAG_A.bits() | Self::FLAG_B.bits() | Self::FLAG_C.bits();
    }
}

fn main() {
    let e1 = MyFlags::FLAG_A | MyFlags::FLAG_C;
    let e2 = MyFlags::FLAG_B | MyFlags::FLAG_C;
    assert_eq!((e1 | e2), MyFlags::FLAG_ABC);
    assert_eq!((e1 & e2), MyFlags::FLAG_C);
    assert_eq!((e1 - e2), MyFlags::FLAG_A);
    assert_eq!(!e2, MyFlags::FLAG_A);

    assert!(e1.contains(MyFlags::FLAG_A));
    assert!(!e1.contains(MyFlags::FLAG_B));

    let mut flags = MyFlags::FLAG_ABC;
    assert_eq!(
        format!("{:032b}", flags.bits()),
        "00000000000000000000000000000111"
    );
    flags.clear();
    assert_eq!(
        format!("{:032b}", flags.bits()),
        "00000000000000000000000000000000"
    );

    assert_eq!(
        format!("{:?}", MyFlags::FLAG_A | MyFlags::FLAG_B),
        "MyFlags(FLAG_A | FLAG_B)"
    );

    // Bits that do not match a defined flag are dropped by `from_bits_truncate`.
    assert_eq!(
        MyFlags::from_bits_truncate(0b1000_0011),
        MyFlags::FLAG_A | MyFlags::FLAG_B
    );
    assert_eq!(MyFlags::from_bits(0b1000_0011), None);
}

How it works

The same type can be written by hand with only the standard library. MyFlags wraps a u32, each flag is a constant with a single bit set, and the bitwise operators are implemented with the matching std::ops traits. This version also implements Display to print the bits in binary.

use std::fmt;

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
struct MyFlags(u32);

impl MyFlags {
    const FLAG_A: MyFlags = MyFlags(0b00000001);
    const FLAG_B: MyFlags = MyFlags(0b00000010);
    const FLAG_C: MyFlags = MyFlags(0b00000100);
    const FLAG_ABC: MyFlags = MyFlags(Self::FLAG_A.0 | Self::FLAG_B.0 | Self::FLAG_C.0);

    fn empty() -> Self {
        MyFlags(0)
    }

    fn bits(&self) -> u32 {
        self.0
    }

    pub fn clear(&mut self) -> &mut MyFlags {
        *self = MyFlags::empty();
        self
    }
}

impl std::ops::BitOr for MyFlags {
    type Output = Self;
    fn bitor(self, rhs: Self) -> Self {
        MyFlags(self.0 | rhs.0)
    }
}

impl std::ops::BitAnd for MyFlags {
    type Output = Self;
    fn bitand(self, rhs: Self) -> Self {
        MyFlags(self.0 & rhs.0)
    }
}

impl std::ops::Sub for MyFlags {
    type Output = Self;
    fn sub(self, rhs: Self) -> Self {
        MyFlags(self.0 & !rhs.0)
    }
}

impl std::ops::Not for MyFlags {
    type Output = Self;
    fn not(self) -> Self {
        MyFlags(!self.0 & 0b00000111) // Only consider defined flags
    }
}

impl fmt::Display for MyFlags {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:032b}", self.bits())
    }
}

fn main() {
    let e1 = MyFlags::FLAG_A | MyFlags::FLAG_C;
    let e2 = MyFlags::FLAG_B | MyFlags::FLAG_C;
    assert_eq!((e1 | e2), MyFlags::FLAG_ABC);
    assert_eq!((e1 & e2), MyFlags::FLAG_C);
    assert_eq!((e1 - e2), MyFlags::FLAG_A);
    assert_eq!(!e2, MyFlags::FLAG_A);

    let mut flags = MyFlags::FLAG_ABC;
    assert_eq!(format!("{}", flags), "00000000000000000000000000000111");
    assert_eq!(
        format!("{}", flags.clear()),
        "00000000000000000000000000000000"
    );
    assert_eq!(format!("{:?}", MyFlags::FLAG_B), "MyFlags(2)");
    assert_eq!(
        format!("{:?}", MyFlags::FLAG_A | MyFlags::FLAG_B),
        "MyFlags(3)"
    );
}