statement 0.1.0

An event-driven state machine library for Rust
Documentation

This library provides an Event-Driven State Machine implementation for Rust

A State Machine describes a struct that maintains a State variable in a predictable way, using a set of Transitions to describe how the state may change. Transitions are triggered by Events, which are generated by the environment, and may in turn cause Effects to execute, which can influence the environment. State Machines may also carry arbitrary Data, which can be mutated by Effects.

In this State Machine implementation, the State Machine is operated by providing it with Events through the [StateMachine::handle_event] method. Events can be anything, but it is common to represent them with an Enum.

States themselves are very restricted to allow for Any / AllOf matching, and typically should also be implemented with an enum that derives Copy, Clone, Eq, PartialEq, and Debug.

Defining Transitions

State Machines in statement are simply a thin wrapper over a state object and a list of transitions. To define a state machine, you need to:

  1. Create a [StateMachineFactory] using [StateMachineFactory::new]
  2. Add transitions using one or more of:
  • [StateMachineFactory::with_predicated_transition]
  • [StateMachineFactory::with_predicated_transition_effect]
  • [StateMachineFactory::with_event_transition]
  • [StateMachineFactory::with_event_transition_effect]
  • [StateMachineFactory::with_auto_transition]
  • [StateMachineFactory::with_custom_transition]
  1. Lock your factory into a [LockedStateMachineFactory] by calling [StateMachineFactory::lock]
  2. Create a state machine by calling [LockedStateMachineFactory::build]

Transitions

Transitions (represented by the [StateMachineTransition] struct) must specify the State or set of initial states (as a [FromState]) that may trigger them, and may also optionally provide a predicate to apply custom logic to decide whether the Transition is applied. Transitions may also be triggered from any ([FromState::Any]) state, meaning that they are considered for any Event.

Transitions must also describe the state that they transition the State Machine into. The to_state of a transition can be represented as one of the following:

  • [To]: A specific, pre-defined state
  • [Same]: Whatever state the transition started from; this makes the transition a no-op for the state machine, but side effects may still be executed. This is useful in some cases, such as in transition loggers.
  • [Calc]: Allows for dynamic target state calculation, when a given transition may result in more than one target states. This is something of an anti-pattern; these should preferentially be represented as multiple transitions with different predicates.

Event Lifecycle

  1. Handle event called.
  2. For each defined transition:

2a. Determine if the from_state of the transition matches the current state. If false, break and move on to the next transition.

2b. Determine the to_state of the transition.

2c. Run the transition's predicate, if any. If false (or no predicate), break and move on to the next transition.

2d. Run the transition's effect, if any.

2e. Transition the state machine to the to_state determined in 2b above.

  1. If the State Machine has cycle set to true, return to 2.