Skip to main content

Crate unit_enum

Crate unit_enum 

Source
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 variant
  • ordinal(): Get the zero-based position of a variant
  • from_ordinal(): Convert an ordinal to a variant
  • discriminant(): Get the variant’s discriminant value
  • from_discriminant(): Convert a discriminant to a variant
  • len(): Get the total number of unit variants
  • values(): Get an iterator over all unit variants
  • VALUES: 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, isize
  • u8, 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 to i32

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§

UnitEnum
Derives the UnitEnum trait for an enum.