Skip to content

Rust library for typesystem-assisted bitflags.

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT
Notifications You must be signed in to change notification settings

meithecatte/enumflags2

Repository files navigation

LICENSE LICENSE Documentation Crates.io Version

Enumflags

enumflags2 implements the classic bitflags datastructure. Annotate an enum with #[bitflags], and BitFlags<YourEnum> will be able to hold arbitrary combinations of your enum within the space of a single integer.

Features

  • Uses enums to represent individual flags—a set of flags is a separate type from a single flag.
  • Automatically chooses a free bit when you don't specify.
  • Detects incorrect BitFlags at compile time.
  • Has a similar API compared to the popular bitflags crate.
  • Does not expose the generated types explicity. The user interacts exclusively with struct BitFlags<Enum>;.
  • The debug formatter prints the binary flag value as well as the flag enums: BitFlags(0b1111, [A, B, C, D]).
  • Optional support for serialization with the serde feature flag.

Example

use enumflags2::{bitflags, make_bitflags, BitFlags};

#[bitflags]
#[repr(u8)]
#[derive(Copy, Clone, Debug, PartialEq)]
enum Test {
    A = 0b0001,
    B = 0b0010,
    C, // unspecified variants pick unused bits automatically
    D = 0b1000,
}

// Flags can be combined with |, this creates a BitFlags of your type:
let a_b: BitFlags<Test> = Test::A | Test::B;
let a_c = Test::A | Test::C;
let b_c_d = make_bitflags!(Test::{B | C | D});

// The debug output lets you inspect both the numeric value and
// the actual flags:
assert_eq!(format!("{:?}", a_b), "BitFlags<Test>(0b11, A | B)");

// But if you'd rather see only one of those, that's available too:
assert_eq!(format!("{}", a_b), "A | B");
assert_eq!(format!("{:04b}", a_b), "0011");

// Iterate over the flags like a normal set
assert_eq!(a_b.iter().collect::<Vec<_>>(), &[Test::A, Test::B]);

// Query the contents with contains and intersects
assert!(a_b.contains(Test::A));
assert!(b_c_d.contains(Test::B | Test::C));
assert!(!(b_c_d.contains(a_b)));

assert!(a_b.intersects(a_c));
assert!(!(a_b.intersects(Test::C | Test::D)));

Optional Feature Flags

  • serde implements Serialize and Deserialize for BitFlags<T>.
  • std implements std::error::Error for FromBitsError.

const fn-compatible APIs

Background: The subset of const fn features currently stabilized is pretty limited. Most notably, const traits are still at the RFC stage, which makes it impossible to use any overloaded operators in a const context.

Naming convention: If a separate, more limited function is provided for usage in a const fn, the name is suffixed with _c.

Blanket implementations: If you attempt to write a const fn ranging over T: BitFlag, you will be met with an error explaining that currently, the only allowed trait bound for a const fn is ?Sized. You will probably want to write a separate implementation for BitFlags<T, u8>, BitFlags<T, u16>, etc — probably generated by a macro. This strategy is often used by enumflags2 itself; to avoid clutter, only one of the copies is shown in the documentation.

Customizing Default

By default, creating an instance of BitFlags<T> with Default will result in an empty set. If that's undesirable, you may customize this:

#[bitflags(default = B | C)]
#[repr(u8)]
#[derive(Copy, Clone, Debug, PartialEq)]
enum Test {
    A = 0b0001,
    B = 0b0010,
    C = 0b0100,
    D = 0b1000,
}

assert_eq!(BitFlags::default(), Test::B | Test::C);