Documentation
¶
Overview ¶
Package fsm provides a generic finite state machine over typed State and Event values. Declarative configuration (Spec) over a fluent builder — config is a value, easier to introspect, validate, and test.
Concurrency-safe by default via a single internal mutex; consumers needing lock-free single-writer semantics (tick loops) can drive the machine from a single goroutine and treat it as plain state.
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ErrIllegalTransition = errors.New("fsm: illegal transition")
ErrIllegalTransition is returned when no transition matches the current (state, event) pair (after guard evaluation).
var ErrInvalidSpec = errors.New("fsm: invalid spec")
ErrInvalidSpec is returned when a Spec fails construction-time validation.
Functions ¶
func Validate ¶
func Validate[S, E comparable](spec Spec[S, E]) error
Validate checks a Spec for common errors: unreachable states, transitions targeting states never entered, and duplicate (From, Event) pairs without guards (which would make selection non-deterministic).
Types ¶
type AtomicEvent ¶
type AtomicEvent uint32
AtomicEvent is the event type used by an AtomicMachine. Same uint32 backing for the same reason.
type AtomicMachine ¶
type AtomicMachine struct {
// contains filtered or unexported fields
}
AtomicMachine is a lock-free single-writer-friendly FSM. State is held in an atomic.Uint32; State() and IsState() are concurrent-safe lookups. Send must be called from a single goroutine — concurrent Send may lose transitions under a CAS race.
Use this when the consumer is an actor (one goroutine owns the machine) and many readers need to query state without contention. For general-purpose use prefer Machine[S, E].
func NewAtomic ¶
func NewAtomic(spec AtomicSpec) *AtomicMachine
NewAtomic constructs an AtomicMachine.
func (*AtomicMachine) IsState ¶
func (m *AtomicMachine) IsState(s AtomicState) bool
IsState reports whether the machine is in s. Cheaper than comparing State() when you only need a boolean.
func (*AtomicMachine) Send ¶
func (m *AtomicMachine) Send(ctx context.Context, ev AtomicEvent) error
Send delivers an event. Caller-side single-writer: concurrent Send from multiple goroutines is not safe.
func (*AtomicMachine) State ¶
func (m *AtomicMachine) State() AtomicState
State returns the current state. Safe to call from any goroutine.
type AtomicSpec ¶
type AtomicSpec struct {
Initial AtomicState
Transitions []AtomicTransition
}
AtomicSpec describes an AtomicMachine. Validation is the caller's responsibility — this type is for the hot path, where Machine[S,E]'s safety checks would impose unnecessary cost.
type AtomicState ¶
type AtomicState uint32
AtomicState is the state type used by an AtomicMachine. Backed by a uint32 so it fits atomic.Uint32; consumers cast their own state enums.
type AtomicTransition ¶
type AtomicTransition struct {
From AtomicState
Event AtomicEvent
To AtomicState
Guard func(ctx context.Context) bool
}
AtomicTransition is a transition declared by index rather than by generic comparable; the trade-off vs Machine[S,E] is no compile-time type safety on the state/event symbols, traded for zero-allocation atomic-only transitions.
type Machine ¶
type Machine[S, E comparable] struct { // contains filtered or unexported fields }
Machine is the live FSM. Safe for concurrent use.
func New ¶
func New[S, E comparable](spec Spec[S, E]) *Machine[S, E]
New constructs a Machine from a Spec. Validates the spec; nil is never returned (panics on invalid spec).
func (*Machine[S, E]) History ¶
func (m *Machine[S, E]) History() []S
History returns a copy of the recorded state history (oldest first). Empty unless Spec.HistorySize > 0.
type Spec ¶
type Spec[S, E comparable] struct { Initial S Transitions []Transition[S, E] OnEnter map[S]func(ctx context.Context) OnExit map[S]func(ctx context.Context) // HistorySize bounds the recorded state history (0 = disabled). HistorySize int }
Spec is the declarative definition of a machine. Pass by value to New.
type Transition ¶
type Transition[S, E comparable] struct { From S Event E To S Guard func(ctx context.Context) bool }
Transition declares a movement from From → To when Event arrives. Guard, if non-nil, must return true for the transition to fire.