A proc-macro crate for Rust that allows creating bit flags enums.
How to use:
- First you need to this crate to your cargo.tomlfile:
[dependencies]
EnumBitFlags = "1.0.8"- Then, you can use it in your Rust project like this:
#[EnumBitFlags]
enum MyFlags {
  Flag_1 = 0x0001,
  Flag_2 = 0x0002,
  Flag_3 = 0x0004
}
fn main() {
  let flags = MyFlags::Flag_1 | MyFlags::Flag_2;
  
  // check if a flag is set (via .contains(...) method)
  if flags.contains(MyFlags::Flag_1) {
    println!("Flag_1 is present");
  }
  
  // check if a flag is set (via AND operation)
  if (flags & MyFlags::Flag_2) == MyFlags::Flag_2 {
    println!("Flag_2 is present");
  }
}Moreover, the following function allows you to create an object from a numeric value:
fn from_value(value: T) -> Option<Self> where T is an unsigned numeric type (u8, u16, u32, u64).
#[EnumBitFlags]
enum MyFlags {
  Flag_1 = 0x0001,
  Flag_2 = 0x0002,
  Flag_3 = 0x0004
}
fn main() {
  if let Some(y) = MyFlags::from_value(5) {
        println!("{y}");
    }
    else {
        eprintln!("Could not create value!");
    }
}EnumBitFlags supports various arguments that provide additional information on how to build the enum. Arguments are specified in the EnumBitFlags arguments with the following format: key=value,key=value,.... Alternativelly, you can use : instead of = (key:value, key:value....)
- 
bitsIn-memory representation of the bitfield. It could be one of the following:8,16,32,64or128. If not specified the default value is32. Example#[EnumBitFlags(bits=8)] enum MyFlags { Flag_1 = 0x01, Flag_2 = 0x02, Flag_3 = 0x04 } 
- 
emptyThe name of the empty variant. An empty variant is the case where not bits are being set up. If not specified,Nonewill be generated. The name of the empty variant must NOT be present in the enum variants and must start with a letter or underline character and can contain letters, numbers and the underline character. Example#[EnumBitFlags(empty=Nothing)] enum MyFlags { Flag_1 = 1, Flag_2 = 2, Flag_3 = 4 } fn main() { let f = MyFlags::Nothing; } 
- 
disable_empty_generationDisables the generation of an empty (value 0) variant. By default this isNonebut the name can be changed by using theemptyattribute. This attribute will also disable any manual variant with value 0 (e.g.No_flag = 0) Example#[EnumBitFlags(disable_empty_generation=true)] enum MyFlags { Flag_1 = 1, Flag_2 = 2, Flag_3 = 4 } fn main() { let f = MyFlags::None; // this code will produce an error as variant None will not be generated } - debugWill print the resulted structure after parsing. Example
 #[EnumBitFlags(debug=true)] enum MyFlags { Flag_1 = 1, Flag_2 = 2, Flag_3 = 4 } 
Every EnumBitFlags has several methods that can be used to easily manipulate and chek bits status:
| Method | Description | 
|---|---|
| obj.contains(mask) | Returns trueif all set bits from the mask are present in the object, orfalseotherwise | 
| obj.contains_one(mask) | Returns trueif at least one bit from the mask is present in the object, orfalseotherwise | 
| obj.clear() | Clears all bits from the current object | 
| obj.is_empty() | Returns trueif not bits are set,falseotherwise | 
| obj.remove(mask) | Removes all set flags from the mask | 
| obj.set(mask) | Set all bits from the mask | 
| obj.get_value() | Returns the numerical value associated to the bit mask flags | 
- 
containsChecks if an exact bitflag mask is presentfn contains(&self, obj: <EnumName>) -> bool The obj must not be empty (at least one bit has to be set) and all bits from the object must be present. Example: #[EnumBitFlags] enum MyFlags { A = 1, B = 2, C = 4 } fn main() { let t = MyFlags::A | MyFlags::B; if t.contains(MyFlags::A) { /* this code will be executed */ } if t.contains(MyFlags::A | MyFlags::B) { /* this code will be executed */ } if t.contains(MyFlags::A | MyFlags::C) { /* this code WILL NOT BE REACHED as flags C is not set in variable t */ } } 
- 
contains_oneChecks if at least one bit from the mask is present in the objectfn contains_one(&self, mask: <EnumName>) -> bool The obj must not be empty (at least one bit has to be set) . Example: #[EnumBitFlags] enum MyFlags { A = 1, B = 2, C = 4 } fn main() { let t = MyFlags::A | MyFlags::B; if t.contains_one(MyFlags::A) { /* this code will be executed */ } if t.contains_one(MyFlags::A | MyFlags::B) { /* this code will be executed */ } if t.contains_one(MyFlags::A | MyFlags::C) { /* this code will be executed */ } } 
- 
clearClears all bits from the enumfn clear(&mut self) Example: #[EnumBitFlags] enum MyFlags { A = 1, B = 2, C = 4 } fn main() { let mut t = MyFlags::A | MyFlags::B; if t.contains_one(MyFlags::A) { /* this code will be executed */ } t.clear(); if t.contains(MyFlags::A) { /* this code will NOT BE REACHED as t was cleared */ } }