A Rust procedural macro that expands an enum with a special #[other]
variant containing a u8
field into a full unit
enum with separate variants for all possible u8
values.
When working with binary protocols or file formats that use byte values as tags, you often need to handle both known values and potentially unknown values. This macro lets you define the known values as normal enum variants while automatically generating variants for all other possible values.
use expand_enum::expand_enum;
expand_enum! {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
enum Direction {
North = 1,
East = 2,
South = 3,
West = 4,
#[other]
Other(u8),
}
}
The macro will expand this into a unit enum with:
- Your explicitly defined variants (
North
,East
,South
,West
) - Additional variants like
Other0
,Other5
,Other6
, ... for all other possibleu8
values
The macro also generates helper methods:
is_other(&self) -> bool
- Returns true if the variant is one of the automatically generated "other" variantsas_other_value(&self) -> Option<u8>
- Returns the underlying value if this is an "other" variantfrom_u8(value: u8) -> Self
- Creates an enum variant from a rawu8
value
Plus implementations of From<u8>
and From<YourEnum> for u8
.
The enum must:
- Be marked with
#[repr(u8)]
- Derive both
Clone
andCopy
- Have exactly one variant marked with
#[other]
that contains a singleu8
field - Specify explicit discriminants for all unit variants
let d = Direction::from_u8(5); // This becomes Direction::Other5
assert!(d.is_other());
assert_eq!(d.as_other_value(), Some(5));
let north = Direction::North;
assert!(!north.is_other());
assert_eq!(north.as_other_value(), None);
// Converts to u8 when needed
let value: u8 = Direction::East.into();
assert_eq!(value, 2);
This macro is particularly useful for protocols or formats where you need to handle a predefined set of known values while preserving the ability to round-trip any arbitrary value.