Expand description
§UnitEnum
A procedural macro for enhancing enums that consist primarily of unit variants.
This crate provides the UnitEnum derive macro which automatically implements
various utility methods for working with enums. It respects the
enum’s #[repr] attribute for discriminant types and provides methods for
accessing variant names, ordinals, and discriminants.
§Basic Usage
use unit_enum::UnitEnum;
#[derive(Debug, Clone, Copy, PartialEq, UnitEnum)]
enum Status {
Active = 1,
Pending, // 2
Inactive = 5
}
// Access variant name
assert_eq!(Status::Active.name(), "Active");
// Get zero-based ordinal
assert_eq!(Status::Pending.ordinal(), 1);
// Convert from ordinal
assert_eq!(Status::from_ordinal(2), Some(Status::Inactive));
// Access discriminant value
assert_eq!(Status::Inactive.discriminant(), 5);
// Convert from discriminant
assert_eq!(Status::from_discriminant(1), Some(Status::Active));
// Get number of variants
assert_eq!(Status::len(), 3);
// Iterate over all variants
assert_eq!(
Status::values().collect::<Vec<_>>(),
vec![Status::Active, Status::Pending, Status::Inactive]
);§Const-friendly methods
Because all enum information is known at compile time, most of the generated
methods are available as const fn and can be used in constant contexts, along
with the VALUES array of all unit variants.
use unit_enum::UnitEnum;
#[derive(Debug, Clone, Copy, PartialEq, UnitEnum)]
enum Status {
Active = 1,
Pending, // 2
Inactive = 5,
}
const STATUS_COUNT: usize = Status::len();
const FIRST_NAME: &str = Status::Active.name();
const FROM_ORDINAL: Option<Status> = Status::from_ordinal(1);
const FROM_DISCRIMINANT: Option<Status> = Status::from_discriminant(1);
const ALL: [Status; Status::len()] = Status::VALUES;
fn main() {
assert_eq!(STATUS_COUNT, 3);
assert_eq!(FIRST_NAME, "Active");
assert_eq!(FROM_ORDINAL, Some(Status::Pending));
assert_eq!(FROM_DISCRIMINANT, Some(Status::Active));
assert_eq!(ALL, [Status::Active, Status::Pending, Status::Inactive]);
}§Usage with “Other” Variant
The macro also supports enums with an additional “other” variant for handling undefined discriminant values:
use unit_enum::UnitEnum;
#[derive(Debug, Clone, Copy, PartialEq, UnitEnum)]
#[repr(u16)] // required when using other variant
enum Status {
Active = 1,
Inactive = 2,
#[unit_enum(other)]
Unknown(u16) // type must match repr
}
// from_discriminant always returns a value
assert_eq!(Status::from_discriminant(1), Status::Active);
assert_eq!(Status::from_discriminant(42), Status::Unknown(42));
// values only includes unit variants
assert_eq!(
Status::values().collect::<Vec<_>>(),
vec![Status::Active, Status::Inactive]
);§Features
The UnitEnum derive macro provides the following methods:
name(): Get the string name of a variantordinal(): Get the zero-based position of a variantfrom_ordinal(): Convert an ordinal to a variantdiscriminant(): Get the variant’s discriminant valuefrom_discriminant(): Convert a discriminant to a variantlen(): Get the total number of unit variantsvalues(): Get an iterator over all unit variantsVALUES: A constant array of all unit variants
§Discriminant Types
The macro respects the enum’s #[repr] attribute to determine discriminant types:
#[derive(UnitEnum)]
#[repr(u8)]
enum Small {
A, // 0u8
B, // 1u8
}
#[derive(UnitEnum)]
#[repr(i64)]
enum Large {
X = -1_000_000,
Y = 1_000_000,
#[unit_enum(other)]
Other(i64)
}Supported types include:
i8,i16,i32,i64,i128,isizeu8,u16,u32,u64,u128,usize
If no integer #[repr] is specified, i32 is used by default. Other hints are ignored for this purpose:
#[repr(C)] uses i32, and #[repr(C, u8)] uses u8. Note that when using an “other” variant,
the #[repr] attribute is required and must match the type of the “other” variant’s field.
§Minimum Supported Rust Version (MSRV)
This crate supports Rust 1.71+. All const-friendly methods described above are available on this MSRV.
§no_std Support
The generated code only depends on core, so UnitEnum can be derived in #![no_std] crates.
§Requirements
For basic unit-only enums:
- All variants must be unit variants (no fields)
#[repr]attribute is optional, defaults toi32
For enums with an “other” variant:
- Must have a
#[repr]attribute - Only one variant can be marked with
#[unit_enum(other)] - The “other” variant must have exactly one unnamed field matching the repr type
- All other variants must be unit variants
§Generated Methods
The following methods are generated for any enum that derives UnitEnum:
impl EnumName {
/// All unit variants in declaration order (excluding the "other" variant).
pub const VALUES: [Self; N] = [ ... ];
/// Returns the string name of the variant.
pub const fn name(&self) -> &'static str { ... }
/// Returns the zero-based ordinal (position) of the variant.
/// For enums with an "other" variant, it returns the last ordinal.
pub const fn ordinal(&self) -> usize { ... }
/// Converts an ordinal to its corresponding variant, if valid.
/// Returns None for invalid ordinals or the "other" variant.
pub const fn from_ordinal(ord: usize) -> Option<Self> { ... }
/// Returns the discriminant value of the variant.
/// For "other" variants, returns the contained value.
pub const fn discriminant(&self) -> ReprType { ... }
/// Converts a discriminant value to its corresponding variant.
/// For enums with an "other" variant, always returns a value.
/// For regular enums, returns None for undefined discriminants.
pub const fn from_discriminant(discr: ReprType) -> Self { ... } // or -> Option<Self>
/// Returns the total number of unit variants (excluding "other" variant).
pub const fn len() -> usize { ... }
/// Returns an iterator over all unit variants of the enum.
/// The "other" variant is not included in the iteration.
pub fn values() -> impl Iterator<Item = Self> { ... }
}Derive Macros§
- Unit
Enum - Derives the
UnitEnumtrait for an enum.