This crates provides a procedural macro to let enums not only get its variants' ordinal but also be constructed from an ordinal.
Use #[derive(Ordinalize)]
to make an enum (which must only has unit variants) have from_ordinal_unsafe
, from_ordinal
, variants
, and variant_count
associated functions and a ordinal
method.
```rust
enum MyEnum { Zero, One, Two, }
asserteq!(0i8, MyEnum::Zero.ordinal()); asserteq!(1i8, MyEnum::One.ordinal()); assert_eq!(2i8, MyEnum::Two.ordinal());
asserteq!(Some(MyEnum::Zero), MyEnum::fromordinal(0i8)); asserteq!(Some(MyEnum::One), MyEnum::fromordinal(1i8)); asserteq!(Some(MyEnum::Two), MyEnum::fromordinal(2i8));
asserteq!(MyEnum::Zero, unsafe { MyEnum::fromordinalunsafe(0i8) }); asserteq!(MyEnum::One, unsafe { MyEnum::fromordinalunsafe(1i8) }); asserteq!(MyEnum::Two, unsafe { MyEnum::fromordinal_unsafe(2i8) }); ```
```rust
enum MyEnum { Zero, One, Two, }
asserteq!([MyEnum::Zero, MyEnum::One, MyEnum::Two], MyEnum::variants()); asserteq!(3, MyEnum::variant_count()); ```
variants
and variant_count
are constant functions.
The ordinal value is an integer whose size is determined by the enum itself. The larger (or the smaller if it's negative) the variants' values are, the bigger the enum size is.
For example,
```rust
enum MyEnum { Zero, One, Two, Thousand = 1000, }
asserteq!(0i16, MyEnum::Zero.ordinal()); asserteq!(1i16, MyEnum::One.ordinal()); assert_eq!(2i16, MyEnum::Two.ordinal());
asserteq!(Some(MyEnum::Zero), MyEnum::fromordinal(0i16)); asserteq!(Some(MyEnum::One), MyEnum::fromordinal(1i16)); asserteq!(Some(MyEnum::Two), MyEnum::fromordinal(2i16));
asserteq!(MyEnum::Zero, unsafe { MyEnum::fromordinalunsafe(0i16) }); asserteq!(MyEnum::One, unsafe { MyEnum::fromordinalunsafe(1i16) }); asserteq!(MyEnum::Two, unsafe { MyEnum::fromordinal_unsafe(2i16) }); ```
In order to store 1000
, the size of MyEnum
grows. Thus, the ordinal is in i16
instead of i8
.
You can use the #[repr(type)]
attribute to control the size explicitly. For instance,
```rust
enum MyEnum { Zero, One, Two, Thousand = 1000, }
asserteq!(0usize, MyEnum::Zero.ordinal()); asserteq!(1usize, MyEnum::One.ordinal()); assert_eq!(2usize, MyEnum::Two.ordinal());
asserteq!(Some(MyEnum::Zero), MyEnum::fromordinal(0usize)); asserteq!(Some(MyEnum::One), MyEnum::fromordinal(1usize)); asserteq!(Some(MyEnum::Two), MyEnum::fromordinal(2usize));
asserteq!(MyEnum::Zero, unsafe { MyEnum::fromordinalunsafe(0usize) }); asserteq!(MyEnum::One, unsafe { MyEnum::fromordinalunsafe(1usize) }); asserteq!(MyEnum::Two, unsafe { MyEnum::fromordinal_unsafe(2usize) }); ```
The integers represented by variants are extended in successive increments and can be set explicitly from anywhere.
```rust
enum MyEnum { Two = 2, Three, Four, Eight = 8, Nine, NegativeTen = -10, NegativeNine, }
asserteq!(4i8, MyEnum::Four.ordinal()); asserteq!(9i8, MyEnum::Nine.ordinal()); assert_eq!(-9i8, MyEnum::NegativeNine.ordinal());
asserteq!(Some(MyEnum::Four), MyEnum::fromordinal(4i8)); asserteq!(Some(MyEnum::Nine), MyEnum::fromordinal(9i8)); asserteq!(Some(MyEnum::NegativeNine), MyEnum::fromordinal(-9i8));
asserteq!(MyEnum::Four, unsafe { MyEnum::fromordinalunsafe(4i8) }); asserteq!(MyEnum::Nine, unsafe { MyEnum::fromordinalunsafe(9i8) }); asserteq!(MyEnum::NegativeNine, unsafe { MyEnum::fromordinal_unsafe(-9i8) }); ```
https://crates.io/crates/enum-ordinalize
https://docs.rs/enum-ordinalize