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.
Unlike other crates, enumflags2
makes the type-level distinction between
a single flag (YourEnum
) and a set of flags (BitFlags<YourEnum>
).
This allows idiomatic handling of bitflags, such as with match
and iter
.
- 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.
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)));
serde
implementsSerialize
andDeserialize
forBitFlags<T>
.std
implementsstd::error::Error
forFromBitsError
.
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
.
Apart from functions whose name ends with _c
, the [make_bitflags!
] macro
is often useful for many const
and const fn
usecases.
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 — best accomplished by a simple macro.
Documentation considerations: The strategy described above is often used
by enumflags2
itself. To avoid clutter in the auto-generated documentation,
the implementations for widths other than u8
are marked with #[doc(hidden)]
.
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);