Skip to main content

Crate statum

Crate statum 

Source
Expand description

Compile-time verified typestate workflows for Rust.

Statum is for workflow and protocol models where representational correctness matters. It helps keep invalid, undesirable, or not-yet- validated states out of ordinary code. In the same spirit as Option and Result, it uses the type system to make absence, failure, and workflow legality explicit instead of leaving them in status fields and guard code. 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::SomeState::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.