#[derive(BitfieldEnum)]
{
    // Attributes available to this derive:
    #[bondrewd_enum]
}
Expand description

Generates an implementation of bondrewd::BitfieldEnum trait.

Important Note: u8 is the only primitive type i have tested. My newest code should be able to handle all primitive types but, to reiterate, i have NOT tested any primitive type other than u8.

Features

  • Generates code for the BitfieldEnum trait which allows an enum to be used by Bitfield structs.
  • Literal values. example
  • Automatic Value Assignment for non-literal variants. Variants are assigned values starting from 0 incrementing by 1 skipping values taken by literal definitions (That means you can mix and match inferred values a code defined literal values). example
  • Catch Variants
    • Catch All variant is used to insure that Results are not needed. Catch all will generate a _ => {..} match arm so that enums don’t need to have as many variants as there are values in the defined primitive. Catch all can be defined with a #[bondrewd_enum(invalid)] attribute or last variant will Automatically become a catch all if no Catch is defined. example
    • Catch Value is a variant that will store values that don’t match the reset of the variants. using a Catch Value is as simple as making a variant with a primitive value (if the bondrewd_enum attribute is present the primitive types must match). example

Other Features

  • Support for implementation of std::cmp::PartialEq for the given primitive (currently only u8)

Typical Example

Here i am letting the Derive do all of the work. The primitive type will be assumed to be u8 because there are less than 256 variants. Variants that do not define a value will be assigned a value starting with the lowest available value. Also due to the catch all system we can ignore the fact i have not covered all 255 values of a u8 because the last Variant, SimpleEnum::Three is this example, will be used a a default to insure not errors can occur.

use bondrewd::BitfieldEnum;
#[derive(BitfieldEnum, PartialEq, Debug)]
enum SimpleEnum {
    Zero, // assigned value 0
    One,  // assigned value 1
    Two,  // assigned value 2
    Three,// assigned value 3
}

assert_eq!(SimpleEnum::Zero.into_primitive(), 0);
assert_eq!(SimpleEnum::Zero, SimpleEnum::from_primitive(0));
assert_eq!(SimpleEnum::One.into_primitive(), 1);
assert_eq!(SimpleEnum::One, SimpleEnum::from_primitive(1));
assert_eq!(SimpleEnum::Two.into_primitive(), 2);
assert_eq!(SimpleEnum::Two, SimpleEnum::from_primitive(2));
assert_eq!(SimpleEnum::Three.into_primitive(), 3);
for i in 3..=u8::MAX {
    assert_eq!(SimpleEnum::Three, SimpleEnum::from_primitive(i));
}

If you do not want the last variant to be a catch all you must either:

  • Cover all possible values in the primitive type with a variant each.
  • Mark the variant you would like to be the catch all example.
  • Add a catch primitive variant example

Literal Example

use bondrewd::BitfieldEnum;
#[derive(BitfieldEnum, PartialEq, Debug)]
enum SimpleEnum {
    Life = 42,
    Min = 0,
    U8Max = 255,
    Unlucky = 13,
}

assert_eq!(SimpleEnum::Life.into_primitive(), 42);
assert_eq!(SimpleEnum::Life, SimpleEnum::from_primitive(42));
assert_eq!(SimpleEnum::Min.into_primitive(), 0);
assert_eq!(SimpleEnum::Min, SimpleEnum::from_primitive(0));
assert_eq!(SimpleEnum::U8Max.into_primitive(), 255);
assert_eq!(SimpleEnum::U8Max, SimpleEnum::from_primitive(255));
assert_eq!(SimpleEnum::Unlucky.into_primitive(), 13);
// check all values not defined and 13 get detected as Unlucky
for i in 1..42 {
    assert_eq!(SimpleEnum::Unlucky, SimpleEnum::from_primitive(i));
}
for i in 43..u8::MAX {
    assert_eq!(SimpleEnum::Unlucky, SimpleEnum::from_primitive(i));
}

Custom Catch All Example

If you don’t decorate the Enum at all the last variant will be assumed to be an Invalid variant. This means if the input value doesn’t match any defined value we can use the Invalid variant as a default.

use bondrewd::BitfieldEnum;
#[derive(BitfieldEnum, PartialEq, Debug)]
enum SimpleEnum {
    Zero, // assigned 0
    One, // assigned 1
    Two, // assigned 2
    Three, // assigned 3 and catches invalid values
}

assert_eq!(SimpleEnum::Zero.into_primitive(), 0);
assert_eq!(SimpleEnum::Zero, SimpleEnum::from_primitive(0));
assert_eq!(SimpleEnum::One.into_primitive(), 1);
assert_eq!(SimpleEnum::One, SimpleEnum::from_primitive(1));
assert_eq!(SimpleEnum::Two.into_primitive(), 2);
assert_eq!(SimpleEnum::Two, SimpleEnum::from_primitive(2));
assert_eq!(SimpleEnum::Three.into_primitive(), 3);
assert_eq!(SimpleEnum::Three, SimpleEnum::from_primitive(3));
// remaining possible values are caught as One.
for i in 4..=u8::MAX {
    assert_eq!(SimpleEnum::Three, SimpleEnum::from_primitive(i));
}

This example shows that we can mark any variant as the catch all variant. In this case Bondrewd will give SimpleEnum::One the value of 1 and make One catch all values not defined because of the invalid attribute.

use bondrewd::BitfieldEnum;
#[derive(BitfieldEnum, PartialEq, Debug)]
enum SimpleEnum {
    Zero, // assigned 0
    #[bondrewd_enum(invalid)]
    One, // assigned 1 and catches invalid values
    Two, // assigned 2
    Three, // assigned 3
}

assert_eq!(SimpleEnum::Zero.into_primitive(), 0);
assert_eq!(SimpleEnum::Zero, SimpleEnum::from_primitive(0));
assert_eq!(SimpleEnum::One.into_primitive(), 1);
assert_eq!(SimpleEnum::One, SimpleEnum::from_primitive(1));
assert_eq!(SimpleEnum::Two.into_primitive(), 2);
assert_eq!(SimpleEnum::Two, SimpleEnum::from_primitive(2));
assert_eq!(SimpleEnum::Three.into_primitive(), 3);
assert_eq!(SimpleEnum::Three, SimpleEnum::from_primitive(3));
// remaining possible values are caught as One.
for i in 4..=u8::MAX {
    assert_eq!(SimpleEnum::One, SimpleEnum::from_primitive(i));
}

Catch Value Example

In some cases we might need to know what the invalid value passed into from_primitive actually was. In my own code there is an enum field that gets encrypted and can become pretty much any value and cause panics in the library i used before writing Bondrewd. To fix this Bondrewd offers the ability to make 1 variant a tuple or struct variant with exactly one field which must be the primitive type the enum gets converted into/from, than the variant values not covered will be stored in the variants field.

use bondrewd::BitfieldEnum;
#[derive(BitfieldEnum, PartialEq, Debug)]
enum SimpleEnum {
    Zero,
    One,
    Two,
    Three(u8),
}

assert_eq!(SimpleEnum::Zero.into_primitive(), 0);
assert_eq!(SimpleEnum::Zero, SimpleEnum::from_primitive(0));
assert_eq!(SimpleEnum::One.into_primitive(), 1);
assert_eq!(SimpleEnum::One, SimpleEnum::from_primitive(1));
assert_eq!(SimpleEnum::Two.into_primitive(), 2);
assert_eq!(SimpleEnum::Two, SimpleEnum::from_primitive(2));
for i in 3..=u8::MAX {
    assert_eq!(SimpleEnum::Three(i), SimpleEnum::from_primitive(i));
}

Complex Example

Here i just want to show that Literals, Auto Value Assignment, and Invalid catch all can all be used together. As you might expect Catch Primitive can not have a Literal value because it stores a value. Here we expect:

  • SimpleEnum::Nine = 9,
  • SimpleEnum::One = 1,
  • SimpleEnum::Zero = 0 and accept 3, 4, 6, 7, 8, and 10..u8::MAX in from_primitive(),
  • SimpleEnum::Five = 5,
  • SimpleEnum::Two = 2,
use bondrewd::BitfieldEnum;
#[derive(BitfieldEnum, PartialEq, Debug)]
enum SimpleEnum {
    Nine = 9,
    // because variant `One` is the first non-literal variant it will be
    // given the first available value
    One,
    // Literals can still be a catch all.
    #[bondrewd_enum(invalid)]
    Zero = 0,
    Five = 5,
    // because variant `One` is the second non-literal variant it will be
    // given the second available value
    Two,
}

assert_eq!(SimpleEnum::Nine.into_primitive(), 9);
assert_eq!(SimpleEnum::Nine, SimpleEnum::from_primitive(9));
assert_eq!(SimpleEnum::One.into_primitive(), 1);
assert_eq!(SimpleEnum::One, SimpleEnum::from_primitive(1));
assert_eq!(SimpleEnum::Zero.into_primitive(), 0);
assert_eq!(SimpleEnum::Zero, SimpleEnum::from_primitive(0));
assert_eq!(SimpleEnum::Five.into_primitive(), 5);
assert_eq!(SimpleEnum::Five, SimpleEnum::from_primitive(5));
assert_eq!(SimpleEnum::Two.into_primitive(), 2);
assert_eq!(SimpleEnum::Two, SimpleEnum::from_primitive(2));
// Invalid tests
assert_eq!(SimpleEnum::Zero, SimpleEnum::from_primitive(3));
assert_eq!(SimpleEnum::Zero, SimpleEnum::from_primitive(4));
assert_eq!(SimpleEnum::Zero, SimpleEnum::from_primitive(6));
assert_eq!(SimpleEnum::Zero, SimpleEnum::from_primitive(7));
assert_eq!(SimpleEnum::Zero, SimpleEnum::from_primitive(8));
for i in 10..=u8::MAX {
    assert_eq!(SimpleEnum::Zero, SimpleEnum::from_primitive(i));
}