Module language::machines

State machines

A machine declares a closed set of events, states, and transition rules. step mutates a machine value, and state_name returns its current state. Every state/event cell must be covered. default { state } is the explicit no-op stay rule for all cells not otherwise listed.

machine Counter {
    events { Inc; Reset; }
    state Zero;
    state NonZero { value: i64; }
    on Inc: Zero => NonZero { value: 1 }
    on Inc: NonZero => NonZero reenter { value: state.value + 1 }
    on Reset: NonZero => Zero;
    default { state }
}

fn main() {
    var counter: Counter = .Zero;
    let _ = counter.step(.Inc);
    let _ = counter.step(.Inc);
    println(counter.state_name());
}

A rule head names the state the transition produces, so the body carries only what the head cannot: nothing for a unit target, the field list for a fielded one, and an expression when the value is computed. state.field reads the source state and event.field reads the event payload; self is an actor or method receiver and is not bound here.

reenter marks a self-state transition that re-enters the state's lifecycle rather than being treated as an ordinary stay. It is useful when a self-transition must rebuild state or trigger state-entry behaviour.

Wildcards are asymmetric: _ is allowed for a state pattern, but events must be named explicitly. For example, on Kill: _ => Dead, covers Kill from every state, but there is no wildcard-event spelling. Explicit cells win over wildcard-state rules. Omitting a cell without a matching default is a compile error, so state and event exhaustiveness is enforced rather than inferred at runtime.