Expand description
A typesafe bitmask flag generator useful for sets of C-style flags. It can be used for creating ergonomic wrappers around C APIs.
The bitflags!
macro generates struct
s that manage a set of flags. The
type of those flags must be some primitive integer.
Examples
use bitflags::bitflags;
bitflags! {
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
struct Flags: u32 {
const A = 0b00000001;
const B = 0b00000010;
const C = 0b00000100;
const ABC = Self::A.bits() | Self::B.bits() | Self::C.bits();
}
}
fn main() {
let e1 = Flags::A | Flags::C;
let e2 = Flags::B | Flags::C;
assert_eq!((e1 | e2), Flags::ABC); // union
assert_eq!((e1 & e2), Flags::C); // intersection
assert_eq!((e1 - e2), Flags::A); // set difference
assert_eq!(!e2, Flags::A); // set complement
}
See example_generated::Flags
for documentation of code
generated by the above bitflags!
expansion.
Visibility
The bitflags!
macro supports visibility, just like you’d expect when writing a normal
Rust struct
:
mod example {
use bitflags::bitflags;
bitflags! {
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Flags1: u32 {
const A = 0b00000001;
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
struct Flags2: u32 {
const B = 0b00000010;
}
}
}
fn main() {
let flag1 = example::Flags1::A;
let flag2 = example::Flags2::B; // error: const `B` is private
}
Attributes
Attributes can be attached to the generated flags types and their constants as normal.
Representation
It’s valid to add a #[repr(C)]
or #[repr(transparent)]
attribute to a generated flags type.
The generated flags type is always guaranteed to be a newtype where its only field has the same
ABI as the underlying integer type.
In this example, Flags
has the same ABI as u32
:
use bitflags::bitflags;
bitflags! {
#[repr(transparent)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
struct Flags: u32 {
const A = 0b00000001;
const B = 0b00000010;
const C = 0b00000100;
}
}
Extending
Generated flags types belong to you, so you can add trait implementations to them outside
of what the bitflags!
macro gives:
use std::fmt;
use bitflags::bitflags;
bitflags! {
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
struct Flags: u32 {
const A = 0b00000001;
const B = 0b00000010;
}
}
impl Flags {
pub fn clear(&mut self) {
*self.0.bits_mut() = 0;
}
}
fn main() {
let mut flags = Flags::A | Flags::B;
flags.clear();
assert!(flags.is_empty());
assert_eq!(format!("{:?}", Flags::A | Flags::B), "Flags(A | B)");
assert_eq!(format!("{:?}", Flags::B), "Flags(B)");
}
What’s implemented by bitflags!
The bitflags!
macro adds some trait implementations and inherent methods
to generated flags types, but leaves room for you to choose the semantics
of others.
Iterators
The following iterator traits are implemented for generated flags types:
Extend
: adds the union of the instances iterated over.FromIterator
: calculates the union.IntoIterator
: iterates over set flag values.
Formatting
The following formatting traits are implemented for generated flags types:
Binary
.LowerHex
andUpperHex
.Octal
.
Also see the Debug and Display section for details about standard text representations for flags types.
Operators
The following operator traits are implemented for the generated struct
s:
BitOr
andBitOrAssign
: unionBitAnd
andBitAndAssign
: intersectionBitXor
andBitXorAssign
: toggleSub
andSubAssign
: set differenceNot
: set complement
Methods
The following methods are defined for the generated struct
s:
empty
: an empty set of flagsall
: the set of all defined flagsbits
: the raw value of the flags currently storedfrom_bits
: convert from underlying bit representation, unless that representation contains bits that do not correspond to a defined flagfrom_bits_truncate
: convert from underlying bit representation, dropping any bits that do not correspond to defined flagsfrom_bits_retain
: convert from underlying bit representation, keeping all bits (even those not corresponding to defined flags)is_empty
:true
if no flags are currently storedis_all
:true
if currently set flags exactly equal all defined flagsintersects
:true
if there are flags common to bothself
andother
contains
:true
if all of the flags inother
are contained withinself
insert
: inserts the specified flags in-placeremove
: removes the specified flags in-placetoggle
: the specified flags will be inserted if not present, and removed if they are.set
: inserts or removes the specified flags depending on the passed valueintersection
: returns a new set of flags, containing only the flags present in bothself
andother
(the argument to the function).union
: returns a new set of flags, containing any flags present in eitherself
orother
(the argument to the function).difference
: returns a new set of flags, containing all flags present inself
without any of the flags present inother
(the argument to the function).symmetric_difference
: returns a new set of flags, containing all flags present in eitherself
orother
(the argument to the function), but not both.complement
: returns a new set of flags, containing all flags which are not set inself
, but which are allowed for this type.
What’s not implemented by bitflags!
Some functionality is not automatically implemented for generated flags types
by the bitflags!
macro, even when it reasonably could be. This is so callers
have more freedom to decide on the semantics of their flags types.
Clone
and Copy
Generated flags types are not automatically copyable, even though they can always
derive both Clone
and Copy
.
Default
The Default
trait is not automatically implemented for the generated structs.
If your default value is equal to 0
(which is the same value as calling empty()
on the generated struct), you can simply derive Default
:
use bitflags::bitflags;
bitflags! {
// Results in default value with bits: 0
#[derive(Default, Clone, Copy, Debug, PartialEq, Eq, Hash)]
struct Flags: u32 {
const A = 0b00000001;
const B = 0b00000010;
const C = 0b00000100;
}
}
fn main() {
let derived_default: Flags = Default::default();
assert_eq!(derived_default.bits(), 0);
}
If your default value is not equal to 0
you need to implement Default
yourself:
use bitflags::bitflags;
bitflags! {
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
struct Flags: u32 {
const A = 0b00000001;
const B = 0b00000010;
const C = 0b00000100;
}
}
// explicit `Default` implementation
impl Default for Flags {
fn default() -> Flags {
Flags::A | Flags::C
}
}
fn main() {
let implemented_default: Flags = Default::default();
assert_eq!(implemented_default, (Flags::A | Flags::C));
}
Debug
and Display
The Debug
trait can be derived for a reasonable implementation. This library defines a standard
text-based representation for flags that generated flags types can use. For details on the exact
grammar, see the parser
module.
To support formatting and parsing your generated flags types using that representation, you can implement
the standard Display
and FromStr
traits in this fashion:
use bitflags::bitflags;
use std::{fmt, str};
bitflags! {
pub struct Flags: u32 {
const A = 1;
const B = 2;
const C = 4;
const D = 8;
}
}
impl fmt::Debug for Flags {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&self.0, f)
}
}
impl fmt::Display for Flags {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&self.0, f)
}
}
impl str::FromStr for Flags {
type Err = bitflags::parser::ParseError;
fn from_str(flags: &str) -> Result<Self, Self::Err> {
Ok(Self(flags.parse()?))
}
}
PartialEq
and PartialOrd
Equality and ordering can be derived for a reasonable implementation, or implemented manually for different semantics.
Edge cases
Zero Flags
Flags with a value equal to zero will have some strange behavior that one should be aware of.
use bitflags::bitflags;
bitflags! {
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
struct Flags: u32 {
const NONE = 0b00000000;
const SOME = 0b00000001;
}
}
fn main() {
let empty = Flags::empty();
let none = Flags::NONE;
let some = Flags::SOME;
// Zero flags are treated as always present
assert!(empty.contains(Flags::NONE));
assert!(none.contains(Flags::NONE));
assert!(some.contains(Flags::NONE));
// Zero flags will be ignored when testing for emptiness
assert!(none.is_empty());
}
Users should generally avoid defining a flag with a value of zero.
Multi-bit Flags
It is allowed to define a flag with multiple bits set, however such
flags are not treated as a set where any of those bits is a valid
flag. Instead, each flag is treated as a unit when converting from
bits with from_bits
or from_bits_truncate
.
use bitflags::bitflags;
bitflags! {
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
struct Flags: u8 {
const F3 = 0b00000011;
}
}
fn main() {
// This bit pattern does not set all the bits in `F3`, so it is rejected.
assert!(Flags::from_bits(0b00000001).is_none());
assert!(Flags::from_bits_truncate(0b00000001).is_empty());
}
The Flags
trait
This library defines a Flags
trait that’s implemented by all generated flags types.
The trait makes it possible to work with flags types generically:
fn count_unset_flags<F: bitflags::Flags>(flags: &F) -> usize {
// Find out how many flags there are in total
let total = F::all().iter().count();
// Find out how many flags are set
let set = flags.iter().count();
total - set
}
use bitflags::bitflags;
bitflags! {
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
struct Flags: u32 {
const A = 0b00000001;
const B = 0b00000010;
const C = 0b00000100;
}
}
assert_eq!(2, count_unset_flags(&Flags::B));
The internal field
This library generates newtypes like:
pub struct Flags(Field0);
You can freely use methods and trait implementations on this internal field as .0
.
For details on exactly what’s generated for it, see the Field0
example docs.