Skip to main content

Crate statum

Crate statum 

Source
Expand description

Compile-time verified typestate workflows for Rust.

Statum is for workflows where phase order matters and invalid transitions are expensive. It generates typed state markers, typed machines, transition helpers, and typed rehydration from stored data.

§Mental Model

  • state defines the legal phases.
  • machine defines the durable context carried across phases.
  • transition defines the legal edges between phases.
  • validators rebuilds typed machines from persisted data.

§Quick Start

use statum::{machine, state, transition};

#[state]
enum CheckoutState {
    EmptyCart,
    ReadyToPay(OrderDraft),
    Paid,
}

#[derive(Clone)]
struct OrderDraft {
    total_cents: u64,
}

#[machine]
struct Checkout<CheckoutState> {
    id: String,
}

#[transition]
impl Checkout<EmptyCart> {
    fn review(self, total_cents: u64) -> Checkout<ReadyToPay> {
        self.transition_with(OrderDraft { total_cents })
    }
}

#[transition]
impl Checkout<ReadyToPay> {
    fn pay(self) -> Checkout<Paid> {
        self.transition()
    }
}

fn main() {
    let cart = Checkout::<EmptyCart>::builder()
        .id("order-1".to_owned())
        .build();

    let ready = cart.review(4200);
    assert_eq!(ready.state_data.total_cents, 4200);

    let _paid = ready.pay();
}

§Typed Rehydration

#[validators] lets you rebuild persisted rows back into typed machine states:

use statum::{machine, state, validators, Error};

#[state]
enum TaskState {
    Draft,
    InReview(String),
    Published,
}

#[machine]
struct Task<TaskState> {
    id: u64,
}

struct TaskRow {
    id: u64,
    status: &'static str,
    reviewer: Option<String>,
}

#[validators(Task)]
impl TaskRow {
    fn is_draft(&self) -> statum::Result<()> {
        if self.status == "draft" {
            Ok(())
        } else {
            Err(Error::InvalidState)
        }
    }

    fn is_in_review(&self) -> statum::Result<String> {
        if self.status == "in_review" {
            self.reviewer.clone().ok_or(Error::InvalidState)
        } else {
            Err(Error::InvalidState)
        }
    }

    fn is_published(&self) -> statum::Result<()> {
        if self.status == "published" {
            Ok(())
        } else {
            Err(Error::InvalidState)
        }
    }
}

fn main() -> statum::Result<()> {
    let row = TaskRow {
        id: 7,
        status: "in_review",
        reviewer: Some("alice".to_owned()),
    };

    let row_id = row.id;
    let machine = row.into_machine().id(row_id).build()?;
    match machine {
        task::State::InReview(task) => assert_eq!(task.state_data, "alice"),
        _ => panic!("expected in-review task"),
    }
    Ok(())
}

§Compile-Time Gating

Methods only exist on states where you define them.

use statum::{machine, state};

#[state]
enum LightState {
    Off,
    On,
}

#[machine]
struct Light<LightState> {}

let light = Light::<Off>::builder().build();
let _ = light.switch_off(); // no such method on Light<Off>

§Where To Look Next

  • Start with state, machine, and transition.
  • For stored rows and database rebuilds, read validators.
  • For append-only event logs, use projection before validator rebuilds.
  • The repository README and docs/ directory contain longer guides and showcase applications.

Modules§

projection
Event-stream projection helpers for Statum rebuild flows.

Enums§

Error
Errors returned by Statum runtime helpers.

Traits§

CanTransitionMap
A machine that can transition by mapping its current state data into Next.
CanTransitionTo
A machine that can transition directly to Next.
CanTransitionWith
A machine that can transition using Data.
DataState
A generated state marker that carries payload data.
StateMarker
A generated state marker type.
UnitState
A generated state marker with no payload.

Type Aliases§

Result
Convenience result alias used by Statum APIs.

Attribute Macros§

machine
Define a typed machine that carries durable context across states.
state
Define the legal lifecycle phases for a machine.
transition
Validate and generate legal transitions for one source state.
validators
Rebuild typed machines from persisted data.