fsm

package
v0.6.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 1, 2026 License: MIT Imports: 5 Imported by: 0

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

View Source
var ErrIllegalTransition = errors.New("fsm: illegal transition")

ErrIllegalTransition is returned when no transition matches the current (state, event) pair (after guard evaluation).

View Source
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.

func (*Machine[S, E]) Send

func (m *Machine[S, E]) Send(ctx context.Context, ev E) error

Send delivers an event. Returns ErrIllegalTransition if no transition from the current state matches the event (or all matching guards fail).

func (*Machine[S, E]) State

func (m *Machine[S, E]) State() S

State returns the current state.

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL