#[bitflag]
Expand description
An attribute macro that transforms an C-like enum into a bitflag struct type implementing an API
similar to the bitflags
crate, and implementing many helpful traits (listed in more details
below).
The attribute requires that the Clone
and Copy
traits are derived for the type.
§Examples
Generate a flags type using u8
as the bits type:
#[bitflag(u8)]
#[derive(Clone, Copy)]
enum Flags {
A = 1,
B = 1 << 1,
C = 0b0000_0100,
}
Flags may refer to other flags using their names:
#[bitflag(u8)]
#[derive(Clone, Copy)]
enum Flags {
A = 1,
B = 1 << 1,
C = 0b0000_0100,
AB = A | B,
}
Flags may also refer to other flags using their bits
method value, like bitflags
crate:
#[bitflag(u8)]
#[derive(Clone, Copy)]
enum Flags {
A = 1,
B = 1 << 1,
C = 0b0000_0100,
AB = Flags::A.bits() | Flags::B.bits(),
}
It’s possible to use more derives and attributes by simply adding them
#[bitflag(u8)]
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, ExternalDerive)]
enum Flags {
A = 1,
B = 1 << 1,
C = 0b0000_0100,
AB = Flags::A.bits() | Flags::B.bits(),
}
§Known and unknown flags
The variant of the enum are flags. They will be expanded to type-associated constants. Every variant value is a known flag, while every not specified value is a unknown flag.
There are operation that will truncate out the unknown values. But tha can be configured if desired; more on that on Externally defined flags
§Externally defined flags
If you’re generating flags types for an external source, such as a C API, you can use the
non_exhaustive
attribute to communicate to the bitflags macro that there may be more valid
flags then the known flags.
Without extra configuration, it defaults to !0
(all bits set) as a mask of all bits the
external source may ever set, i.e. all bits are considered as possible values.
use bitflag_attr::bitflag;
#[bitflag(u32)]
#[non_exhaustive] // All bits are considered as possible values.
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub enum Flags {
/// The value `A`, at bit position `0`.
A = 0b00000001,
/// The value `B`, at bit position `1`.
B = 0b00000010,
/// The value `C`, at bit position `2`.
C = 0b00000100,
/// The combination of `A`, `B`, and `C`.
ABC = A | B | C,
}
But you can also configure it using the helper attribute extra_valid_bits
with the value of
valid bits that the external source may ever set.
use bitflag_attr::bitflag;
#[bitflag(u32)]
#[non_exhaustive] // Communicate there is more potential valid flags than the known flags
#[extra_valid_bits = 0b001001111] // Specify the extra bits to take into consideration.
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub enum Flags {
/// The value `A`, at bit position `0`.
A = 0b00000001,
/// The value `B`, at bit position `1`.
B = 0b00000010,
/// The value `C`, at bit position `2`.
C = 0b00000100,
/// The combination of `A`, `B`, and `C`.
ABC = A | B | C,
}
Why should you do this? Generated methods like all
and truncating operators like !
only
consider bits in defined flags. Adding an unnamed flag makes those methods consider additional
bits, without generating additional constants for them. It helps compatibility when the external
source may start setting additional bits at any time.
§Type representation
By default, the generated flag type will be #[repr(transparent)]
, but you can explicit it on
the definition as long is one of the supported ones (C
, Rust
and transparent
):
#[repr(C)]
#[bitflag(u8)]
#[derive(Clone, Copy)]
enum Flags {
A = 1,
B = 1 << 1,
C = 1 << 2,
}
§Generated trait implementations
This macro generates some trait implementations: ops:Not
, ops:BitAnd
,
ops:BitOr
, ops:BitXor
, ops:BitAndAssign
, ops:BitOrAssign
, ops:BitXorAssign
,
fmt::Binary
, fmt::LowerHex
, fmt::UpperHex
, fmt::Octal
, From
, Extend
,
FromIterator
, FromStr
and IntoIterator
.
The custom fmt::Debug
implementation will only be generated if it is included in the
#[derive(...)]
parameters.
The custom Default
implementation will only be generated if it is included in the
#[derive(...)]
parameters.
§Default derive
The bitflag
macro handles the Default
if specified in the derive list. Without specifying
a default variant, the default implementation is the same as a empty flag:
#[bitflag(u8)]
#[derive(Clone, Copy, Default)] // Default is the same as `Flags::empty()`
enum Flags {
A = 1,
B = 1 << 1,
C = 1 << 2,
}
But it can be specified like deriving Default
on enum, using the #[default]
helper attribute:
#[bitflag(u8)]
#[derive(Clone, Copy, Default)]
enum Flags {
A = 1,
B = 1 << 1,
#[default] // `Flags::C` are the default value returned by `Default::default()`
C = 1 << 2,
}
§Serde feature
If the crate is compiled with the serde
feature, this crate will generate implementations for
the serde::{Serialize, Deserialize}
traits if they are included in the #[derive(...)]
parameters, but it will not import/re-export these traits, your project must have serde
as
a direct dependency.
use bitflag_attr::bitflag;
use serde::{Serialize, Deserialize};
#[bitflag(u32)]
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub enum Flags {
/// The value `A`, at bit position `0`.
A = 0b00000001,
/// The value `B`, at bit position `1`.
B = 0b00000010,
/// The value `C`, at bit position `2`.
C = 0b00000100,
/// The combination of `A`, `B`, and `C`.
ABC = A | B | C,
}
§Arbitrary feature
If the crate is compiled with the arbitrary
feature, this crate will generate implementations for
the arbitrary::Arbitrary
traits if they are included in the #[derive(...)]
parameters, but it will not import/re-export these traits, your project must have arbitrary
as
a direct dependency.
use bitflag_attr::bitflag;
use arbitrary::Arbitrary;
#[bitflag(u32)]
#[derive(Clone, Copy, Arbitrary)]
enum Color {
RED = 0x1,
GREEN = 0x02,
BLUE = 0x4,
}
§Bytemuck feature
If the crate is compiled with the bytemuck
feature, this crate will generate implementations for
the bytemuck::{Pod, Zeroable}
traits if they are included in the #[derive(...)]
parameters, but it will not import/re-export these traits, your project must have bytemuck
as
a direct dependency.
use bitflag_attr::bitflag;
use bytemuck::{Pod, Zeroable};
#[bitflag(u32)]
#[derive(Debug, Clone, Copy, Pod, Zeroable)]
pub enum Flags {
/// The value `A`, at bit position `0`.
A = 0b00000001,
/// The value `B`, at bit position `1`.
B = 0b00000010,
/// The value `C`, at bit position `2`.
C = 0b00000100,
/// The combination of `A`, `B`, and `C`.
ABC = A | B | C,
}
§const-mut-ref
feature
If the crate is compiled with the const-mut-ref
feature, all type-associated API that takes
&mut self
will be generated as const-fn, meaning they can be used on const
context.
Note: &mut
on const function was stabilized on Rust 1.83.0, so using this feature flag on
Rust versions below that will cause compilation errors
§Custom types feature
If the crate is compiled with the custom-types
feature, it allows to use more than the types
defined in Rust core
(i8
,u8
,i16
,u16
,i32
,u32
,i64
,u64
,i128
,u128
,isize
,
usize
,c_char
,c_schar
,c_uchar
,c_short
,c_ushort
,c_int
,c_uint
,c_long
,c_ulong
,
c_longlong
,c_ulonglong
) as long as it is a type alias to one of those types.
The reason it is behind a feature flag is that to ensure the validity of such constrain, we have to pay the price of having much worse error messages. With this feature enabled, a invalid type will cause a massive wall of error message.
§More Examples
use bitflag_attr::bitflag;
#[bitflag(u32)]
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub enum Flags {
/// The value `A`, at bit position `0`.
A = 0b00000001,
/// The value `B`, at bit position `1`.
B = 0b00000010,
/// The value `C`, at bit position `2`.
C = 0b00000100,
/// The combination of `A`, `B`, and `C`.
ABC = A | B | C,
}
Without generating fmt::Debug
:
use bitflag_attr::bitflag;
#[bitflag(u32)]
#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub enum Flags {
/// The value `A`, at bit position `0`.
A = 0b00000001,
/// The value `B`, at bit position `1`.
B = 0b00000010,
/// The value `C`, at bit position `2`.
C = 0b00000100,
/// The combination of `A`, `B`, and `C`.
ABC = A | B | C,
}
§Syntax
#[bitflag($ty)]
$visibility enum $StructName {
FlagOne = flag1_value_expr,
FlagTwo = flag2_value_expr,
// ...
FlagN = flagn_value_expr,
}