Open Source
Public Rust libraries that show how I model APIs and invariants.
Typestate, enum ergonomics, and workspace rules turned into concrete tools.
statum
Typestate transitions and rehydration for persisted Rust workflows.
Rust
State machine
#[state]
enum ReviewState { Draft, Published }
#[machine]
struct Post<ReviewState> {
title: String,
}Rust
Transition
#[transition]
impl Post<Draft> {
fn publish(self) -> Post<Published> {
self.transition()
}
}Transitions stay in the type system
- Transition methods state both the starting and ending machine types.
- The resulting API reads like workflow code instead of enum plumbing.
Rust
Data-bearing state
#[state]
enum ReviewState {
Draft,
InReview(ReviewData),
Published,
}
struct ReviewData {
reviewer: String,
notes: Vec<String>,
}Rust
Transition with data
#[transition]
impl Post<Draft> {
fn submit_for_review(self, reviewer: String) -> Post<InReview> {
self.transition_with(ReviewData {
reviewer,
notes: vec![],
})
}
}State-specific data stays attached to state-specific behavior
- Review-only data appears only when the machine is actually in review.
- The transition API makes data handoff explicit instead of leaking optional fields everywhere.
Rust
Validator shape
#[validators(TaskMachine)]
impl DbRow {
fn is_draft(&self) -> statum::Result<()> {
match self.state {
Status::Draft => Ok(()),
_ => Err(statum::Error::InvalidState),
}
}
}Rust
Rehydration call
fn rebuild_task(row: &DbRow) -> statum::Result<task_machine::State> {
row.into_machine()
}Rehydration is part of the design, not an afterthought
- Persistent rows validate into concrete machine states instead of generic runtime blobs.
- Storage integration stays close to the workflow model instead of branching into a second untyped path.
nestum
Nested enum construction and matching that preserves domain hierarchy.
Rust
Definitions
#[nestum]
enum DocumentsEvent {
Update(Document),
Delete(String),
}
#[nestum]
enum Event {
Documents(DocumentsEvent),
}Rust
Construction
let event = Event::Documents::Update(doc);Nested enum paths stay readable
- The API keeps the conceptual tree visible at the call site.
- Deeply modeled event trees stay readable without collapsing into flatter APIs.
Rust
Match syntax
nested! {
match event {
Event::Documents::Update(doc) => {
let _ = doc.id;
}
Event::Documents::Delete(id) => {
let _ = id;
}
}
}Matching keeps the same mental model as construction
- The same nested path style works in both expression and pattern positions.
- Intent survives in the noisiest parts of routing code.
Rust
External nesting
#[nestum]
enum Outer {
#[nestum(external = "crate::inner::Inner")]
Wrap(Inner),
}
let value = Outer::Wrap::A;The hierarchy does not have to collapse at file boundaries
- Cross-module nesting is opt-in and explicit.
- The public path still reads as one coherent domain tree.
modum
Workspace linting for namespace shape, naming, and API-surface rules.
Rust
Desired public shape
pub mod user {
pub use repository::UserRepository as Repository;
pub use error::UserError as Error;
}Rust
Call site
fn load(repo: &user::Repository) -> Result<(), user::Error> {
Ok(())
}API shape is treated like a design constraint
- The tool targets naming and namespace drift before it spreads across a workspace.
- Code review can focus on behavior instead of recurring naming cleanup.
Rust
Marker
// ci: descriptive-module-import crate::views::partials::components::tab_setRust
Qualified usage
use crate::views::partials::components::tab_set;
let component = tab_set::Component::from_content(props);Imports can preserve the module vocabulary
- Modules stay visible when they add context instead of just noise.
- That makes call sites easier to scan in larger codebases.
Rust
CLI
cargo run -p modum -- check --root /path/to/workspaceRust
CI-style flow
cargo run -p modum -- check --root /home/eran/code/eran_codes \
> modum-lint-report.txt 2>&1Style standards become part of the delivery loop
- Policy can run across a whole workspace instead of being enforced ad hoc.
- It turns naming standards into infrastructure rather than tribal knowledge.