nestum
nestum lets nested enums read like nested paths in Rust.
Construct:
Created
instead of:
Document
and match the same way with nested!.
use ;
let inner: Enum = Created;
let event: Enum = Created;
nested!
let _ = inner;
Mental Model
#[nestum]on an enum turns the enum name into a namespace for nested-path constructors.nested! { ... }rewrites nested constructors and nested patterns where Rust syntax needs help.- If you need the concrete enum type itself, use
Outer::Enum<T>.
That namespace tradeoff is what makes Event::Document::Created possible in ordinary Rust syntax.
What This Path Means
DocumentEvent::Createdconstructs aDocumentEvent::Enum.Event::Document::Createdconstructs anEvent::Enum.Event::Documentis a namespace branch, not a completedEventvalue.
Good fits for nestum look like:
Event::Document::CreatedCommand::User::CreateMessage::Billing::Paid
Avoid shapes like Document::Event::Created as the main mental model. They read like inner type namespaces, but nestum is strongest when the outer enum is an envelope over event, command, or message families.
Quick Start
- Add
#[nestum]to each enum in the hierarchy. - Construct wrapped values with nested paths like
Event::Document::Created. - Wrap
match,if let,while let,let-else,matches!, and named-field nested construction innested! { ... }.
Real-World Showcases
The nestum-examples workspace crate shows the macro against real libraries instead of toy enums.
todo_api: Axum + in-memory SQLite + broadcast events. This proves nested command trees, nested domain errors, and nested events can survive a normal web stack.ops_cli: Clap subcommands with nested dispatch. This proves nestum can sit on top of derive-heavy command surfaces without turning the type tree into boilerplate.
Run them with:
Coding Agents
If you use coding agents, see docs/agents/. It includes copyable instruction templates, an opportunity-signals guide, an audit playbook, and prompts for audits, greenfield design, review, and targeted refactors.
Examples
Basic Nesting
let _ = Created;
let _ = Archived;
Named-Field Constructors
Use nested! when the nested leaf is a named-field variant:
use ;
let value: Enum = nested! ;
Cross-Module Nesting
Use #[nestum(external = "...")] when the inner enum lives in another module file:
let _ = A;
Core Rules
- Only enums are supported.
- Both the outer enum and the nested inner enum need
#[nestum]. - Use
nested!for pattern-bearing forms and named-field nested constructors.
Advanced Notes
- In type positions, use
Outer::Enum<T>for the enum type itself. - Put
#[nestum]before#[derive(...)]so derive macros see the rewritten enum shape. - Generic outer enums use functions for nested unit constructors, so
Outer::Wrap::Ready()may be a function call instead of a constant. - Plain or qualified local inner enum paths are supported, including generic arguments.
- Cross-module nesting is explicit with
#[nestum(external = "crate::path::Enum")]. - For nested variants, the raw root constructor path like
Outer::Wrap(inner)is no longer part of the public surface; useOuter::Enum::Wrap(inner)if you need the explicit underlying constructor.
Limitations
self::...,super::..., and qself or associated paths are rejected for nested field detection.#[path = "..."],include!(), and complexcfgmodule layouts may not resolve.- External crates are not supported because proc macros cannot reliably inspect dependency sources.
API
#[nestum]
Marks an enum so nested enum-wrapping variants can be constructed through path-shaped syntax.
use nestum;
let _ = A;
nested! { ... }
Rewrites nested constructors and nested patterns into ordinary Rust enum syntax.
Use it for match, if let, while let, let-else, matches!, and named-field nested construction.
use ;
let value = B;
let ok = nested! ;
#[nestum(external = "path::to::Enum")]
Marks a variant as wrapping a nested enum defined in another module file.
use nestum;
nestum_match! { match value { ... } }
Match-only compatibility macro. Prefer nested! unless you specifically want a match-only entry point.
License
MIT