An immutable state transition validator for applications that model workflow as data.
Many applications model workflows such as order processing, ticketing, or document approval.
When those workflows are configuration-driven or stored as data rather than hard-coded enums and match statements, validating legal transitions becomes repetitive.
Statekit provides an immutable state-machine definition that validates whether a transition is permitted.
Statekit is intended for applications where states are not known at compile time.
Examples include:
- workflows loaded from configuration
- user-defined business processes
- state machines stored in a database
- plugins that define additional states
Statekit is under active development.
Current release: v0.3.0.
Statekit follows semantic versioning. As a pre-1.0 crate, its public API may evolve between minor releases.
[dependencies]
statekit = "0.3"use statekit::{Machine, StateError};
fn main() -> Result<(), StateError> {
let machine = Machine::builder()
.try_allow("queued", "running")?
.try_allow("running", "completed")?
.try_allow("running", "failed")?
.build()?;
let result = machine.validate_transition("queued", "running")?;
assert!(machine.can_transition("queued", "running"));
assert!(!machine.can_transition("queued", "completed"));
Ok(())
}Machines can be inspected without exposing their internal storage.
for source in machine.sources() {
println!("{source}");
for target in machine.targets_from(source) {
println!(" -> {target}");
}
}targets_from() returns an empty iterator when a state has no outgoing transitions, including unknown states and states that appear only as transition targets.
for state in machine.states() {
println!("{state}");
}Machine::transitions() exposes immutable Transition values with source and target state names.
for transition in machine.transitions() {
println!(
"{} -> {}",
transition.source(),
transition.target()
);
}Iteration order is unspecified.
- State names must not be empty or consist entirely of whitespace.
- State names must not begin or end with Unicode whitespace.
- State names are case-sensitive.
- Self-transitions are rejected.
- Cycles between distinct states are permitted.
- A machine must contain at least one transition.
- Duplicate transitions between the same source and target are stored as a single logical transition.
try_allow() validates state names and transition relationships when they are added.
build() validates machine-level requirements, including that at least one transition exists.
All public Statekit errors implement std::error::Error.
Once constructed, a machine cannot be modified.
This allows a machine definition to be reused safely without callers mutating its transition structure.
Statekit is not:
- a process engine
- a policy engine
- a pathfinding library
- a workflow engine
Statekit can be used as a building block for these kinds of systems, but intentionally does not implement them.
- Statekit Specification — domain definitions and invariants
- Migration Guide — guidance for upgrading between releases
- Changelog — notable changes by release
MIT
