hsm

package module
v1.3.2 Latest Latest
Warning

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

Go to latest
Published: Jul 19, 2026 License: MIT Imports: 17 Imported by: 0

README

package hsm

import "github.com/stateforward/hsm.go"

Package hsm provides a powerful hierarchical state machine (HSM) implementation for Go.

Overview

It enables modeling complex state-driven systems with features like hierarchical states, entry/exit actions, guard conditions, and event-driven transitions. The implementation follows the Stateforward HSM DSL/runtime contract, ensuring consistency across platforms.

Features

  • Hierarchical States: Support for nested states and regions.
  • Event-Driven: Asynchronous event processing with context propagation.
  • Guards & Actions: Flexible functional definitions for transition guards and state actions.
  • Type Safe: Generics-based implementation for state context.

Usage

Define your state machine structure and behavior using the declarative builder pattern:

type MyHSM struct {
    hsm.HSM
    counter int
}

model := hsm.Define(
    "example",
    hsm.Initial(hsm.Target("foo")),
    hsm.State("foo"),
    hsm.State("bar"),
    hsm.Transition(
        hsm.On("moveToBar"),
        hsm.Source("foo"),
        hsm.Target("bar"),
    ),
)

// Start the state machine
sm := hsm.Started(context.Background(), &MyHSM{}, &model)
<-hsm.Dispatch(context.Background(), sm, hsm.Event{Name: "moveToBar"})

Synchronization

Wait on the Completion returned by Dispatch, Set, Restart, Stop, DispatchAll, or DispatchTo before asserting on post-transition state. The completion remains receive-compatible as <-chan struct{} and also supports Wait and Err for direct-call failures.

Direct dispatch to a nil, unstarted, or stopped instance returns a failed completion. Fan-out dispatch filters inactive recipients.

Use AfterProcess, AfterDispatch, AfterEntry, AfterExit, and AfterExecuted for tests and deterministic observation only.

  • Model construction: Define, Redefine, InlineModel, State, SubmachineState, Initial, Transition, TransitionType, Source, Target, Choice, EntryPoint, ExitPoint, ShallowHistory, DeepHistory, Final.
  • Behavior and triggers: Entry, Activity, Exit, Effect, Guard, On, OnSet, OnCall, After, At, Every, When, Defer, Attribute, Operation.
  • Model hooks: Validator, Finalizer, and Observe; custom hooks use ModelValidator, ModelValidatorFunc, DefaultModelValidator, ModelFinalizer, ModelFinalizerFunc, and DefaultModelFinalizer.
  • Runtime lifecycle: New, Started, Start, Stop, Restart, Dispatch, DispatchAll, DispatchTo, Set, Get, Call, TakeSnapshot, TakeSnapshots; TakeSnapshot(ctx, group) returns ordered []Snapshot.
  • Groups and identity: NewGroup, MakeGroup, Group.Instances, Group.States, Group.Snapshots, ID, QualifiedName, Name, FromContext, InstancesFromContext; group snapshots preserve flattened member order.
  • Deterministic test observation: AfterProcess, AfterDispatch, AfterEntry, AfterExit, and AfterExecuted.
  • Core types: Model, FinalizedModel, Config, Event, Completion, ObservationData, AttributeChange, CallData, Snapshot, TransitionSnapshot, EventSnapshot, Queue, Group, HSM, Instance, Element, RedefinableElement, OperationFunc, and ExpressionFunc.
  • Built-ins: InitialEvent, ErrorEvent, AnyEvent, FinalEvent, ObservationEvent, InfiniteDuration, Keys, Version, exported *Kind constants, and exported error sentinels including ErrMissingHSM, ErrInvalidState, ErrUnknownAttribute, and ErrInvalidAttributeType.

Documentation

Overview

Package hsm provides a powerful hierarchical state machine (HSM) implementation for Go.

Overview

It enables modeling complex state-driven systems with features like hierarchical states, entry/exit actions, guard conditions, and event-driven transitions. The implementation follows the Stateforward HSM DSL/runtime contract, ensuring consistency across platforms.

Features

  • **Hierarchical States**: Support for nested states and regions.
  • **Event-Driven**: Asynchronous event processing with context propagation.
  • **Guards & Actions**: Flexible functional definitions for transition guards and state actions.
  • **Type Safe**: Generics-based implementation for state context.

Usage

Define your state machine structure and behavior using the declarative builder pattern:

type MyHSM struct {
    hsm.HSM
    counter int
}

model := hsm.Define(
    "example",
    hsm.State("foo"),
    hsm.State("bar"),
    hsm.Transition(
        hsm.On("moveToBar"),
        hsm.Source("foo"),
        hsm.Target("bar"),
    ),
    hsm.Initial(hsm.Target("foo")),
)

// Start the state machine
sm := hsm.Started(context.Background(), &MyHSM{}, &model)
<-hsm.Dispatch(context.Background(), sm, hsm.Event{Name: "moveToBar"})

Index

Constants

View Source
const Version = "v1.3.2"

Version is the current semantic version of the hsm package.

Variables

View Source
var (
	// NullKind represents the absence of a kind or an uninitialized kind value.
	NullKind = kind.Make()
	// ElementKind is the base kind for all HSM elements. Every structural
	// component in the state machine hierarchy derives from ElementKind.
	ElementKind = kind.Make()
	// NamespaceKind represents elements that can contain named children,
	// enabling hierarchical name resolution for states and state machines.
	NamespaceKind = kind.Make(ElementKind)
	// VertexKind is the base kind for nodes in the state graph that can be
	// sources or targets of transitions, including states and pseudostates.
	VertexKind = kind.Make(ElementKind)
	// ConstraintKind represents guard conditions that control transition firing.
	ConstraintKind = kind.Make(ElementKind)
	// BehaviorKind represents executable behaviors such as entry, exit, and
	// transition effects that run during state machine execution.
	BehaviorKind = kind.Make(ElementKind)
	// ConcurrentKind represents behaviors that support concurrent execution
	// of multiple orthogonal regions.
	ConcurrentKind = kind.Make(BehaviorKind)
	// StateMachineKind represents the top-level state machine container that
	// owns regions, states, and transitions. Inherits from both ConcurrentKind
	// (for orthogonal regions) and NamespaceKind (for named child lookup).
	StateMachineKind = kind.Make(ConcurrentKind, NamespaceKind)
	// StateKind represents a state vertex that can contain nested regions,
	// entry/exit behaviors, and internal transitions. Inherits from VertexKind
	// (as a graph node) and NamespaceKind (as a container for child elements).
	StateKind = kind.Make(VertexKind, NamespaceKind)
	// SubmachineStateKind represents a state that composes a reusable child
	// machine under the containing state boundary.
	SubmachineStateKind = kind.Make(StateKind)
	// RegionKind represents an orthogonal region within a composite state or
	// state machine, containing vertices and transitions.
	RegionKind = kind.Make(ElementKind)
	// TransitionKind is the base kind for all transitions between vertices,
	// representing edges in the state graph.
	TransitionKind = kind.Make(ElementKind)
	// InternalKind represents internal transitions that execute without
	// exiting or re-entering the containing state.
	InternalKind = kind.Make(TransitionKind)
	// ExternalKind represents external transitions that exit the source state
	// and enter the target state, triggering exit and entry behaviors.
	ExternalKind = kind.Make(TransitionKind)
	// LocalKind represents local transitions that do not exit the containing
	// composite state when transitioning between its substates.
	LocalKind = kind.Make(TransitionKind)
	// SelfKind represents self-transitions where the source and target are
	// the same state, triggering exit and re-entry of that state.
	SelfKind = kind.Make(TransitionKind)
	// EventKind is the base kind for all events that can trigger transitions
	// in the state machine.
	EventKind = kind.Make(ElementKind)
	// TimeEventKind represents events triggered after a specified duration,
	// used for timeout-based transitions.
	TimeEventKind = kind.Make(EventKind)
	// CompletionEventKind represents events automatically generated when a
	// state completes all its internal activities or reaches a final state.
	CompletionEventKind = kind.Make(EventKind)
	// ChangeEventKind represents events triggered when a boolean condition
	// becomes true, enabling data-driven transitions.
	ChangeEventKind = kind.Make(EventKind)
	// CallEventKind represents events triggered by method calls on the state
	// machine, enabling synchronous event dispatch.
	CallEventKind = kind.Make(EventKind)
	// AttributeKind represents a model-level data slot.
	AttributeKind = kind.Make(ElementKind)
	// OperationKind represents a model-level callable operation.
	OperationKind = kind.Make(ElementKind)
	// ErrorEventKind represents events generated when an error occurs during
	// state machine execution. Inherits from CompletionEventKind as errors
	// typically complete the current processing.
	ErrorEventKind = kind.Make(CompletionEventKind)
	// PseudostateKind is the base kind for transient vertices that perform
	// control flow logic without representing stable states.
	PseudostateKind = kind.Make(VertexKind)
	// InitialKind represents the initial pseudostate that indicates the
	// default starting state when entering a region.
	InitialKind = kind.Make(PseudostateKind)
	// FinalStateKind represents a final state indicating that the enclosing
	// region has completed its execution.
	FinalStateKind = kind.Make(StateKind)
	// ChoiceKind represents a choice pseudostate that evaluates guards to
	// select among multiple outgoing transitions dynamically.
	ChoiceKind = kind.Make(PseudostateKind)
	// ObservationKind represents a model observation hook.
	ObservationKind = kind.Make(ElementKind)
	// EntryPointKind represents a connection point used to enter a submachine
	// through a named transient vertex.
	EntryPointKind = kind.Make(PseudostateKind)
	// ExitPointKind represents a connection point used to leave a submachine
	// through a named transient vertex.
	ExitPointKind = kind.Make(PseudostateKind)
	// ShallowHistoryKind represents a shallow history pseudostate that
	// remembers the most recently active direct substate of its region.
	ShallowHistoryKind = kind.Make(PseudostateKind)
	// DeepHistoryKind represents a deep history pseudostate that remembers
	// the full active state configuration within its region recursively.
	DeepHistoryKind = kind.Make(PseudostateKind)
	// CustomKind represents user-defined element types for extending the
	// HSM framework with application-specific constructs.
	CustomKind = kind.Make(ElementKind)
)

Kind constants define the HSM type hierarchy using bit-packed inheritance. Each Kind encodes its own ID and the IDs of its ancestor types, enabling efficient type checking via kind.Is(). The hierarchy follows UML state machine concepts where elements can inherit from multiple parent kinds.

View Source
var (
	// ErrNilHSM is returned when an operation is attempted on a nil state machine.
	ErrNilHSM = errors.New("hsm is nil")
	// ErrInvalidState is returned when attempting to access or transition to an invalid state.
	ErrInvalidState = errors.New("invalid state")
	// ErrMissingHSM is returned when the HSM instance cannot be found in the context.
	ErrMissingHSM = errors.New("missing hsm in context")
	// ErrMissingOperation is returned when an operation callback is required but not provided.
	ErrMissingOperation = errors.New("missing operation")
	// ErrInvalidOperation is returned when an operation callback has an unsupported function signature.
	ErrInvalidOperation = errors.New("invalid operation")
	// ErrAlreadyStarted is returned when a state machine has already been started.
	ErrAlreadyStarted = errors.New("hsm already started")
	// ErrUnknownAttribute is returned when a runtime attribute name is not defined.
	ErrUnknownAttribute = errors.New("unknown attribute")
	// ErrInvalidAttributeType is returned when a runtime attribute value has the wrong type.
	ErrInvalidAttributeType = errors.New("invalid attribute type")
)

Error variables for common HSM error conditions. These sentinel errors can be checked using errors.Is for specific error handling.

View Source
var (
	// InitialEvent is the completion event dispatched when a state machine starts.
	// It triggers the initial transition from the initial pseudostate to the first active state.
	InitialEvent = Event{
		Name: "hsm/initial",
		Kind: CompletionEventKind,
	}
	// ErrorEvent is dispatched when an error occurs during state machine execution,
	// such as panics in concurrent behaviors or timeout errors. Use On(ErrorEvent) to handle errors.
	ErrorEvent = Event{
		Name: "hsm/error",
		Kind: ErrorEventKind,
	}
	// AnyEvent is a wildcard event that matches any event not explicitly handled.
	// Transitions using On(AnyEvent) are only taken when no specific event transition matches.
	AnyEvent = Event{
		Name: "*",
		Kind: EventKind,
	}
	// FinalEvent is the completion event dispatched when a state reaches its final state.
	// It triggers exit behaviors and propagates completion to parent regions.
	FinalEvent = Event{
		Name: "hsm/final",
		Kind: CompletionEventKind,
	}
	// ObservationEvent is emitted to observation hooks for observed behaviors and transitions.
	ObservationEvent = Event{
		Name: "hsm/observation",
		Kind: EventKind,
	}
	// InfiniteDuration represents an unbounded duration for timeout operations.
	// Use this when a behavior should run indefinitely without timing out.
	InfiniteDuration = time.Duration(-1)
)

Built-in event types and special duration constants used by the HSM runtime.

View Source
var DefaultClock = Clock{
	After:    time.After,
	NewTimer: time.NewTimer,
}

DefaultClock is used when Config.Clock does not override timer behavior.

View Source
var Keys = struct {
	Instances key[*sync.Map]
	Owner     key[Instance]
	HSM       key[HSM]
}{
	Instances: key[*sync.Map]{},
	Owner:     key[Instance]{},
	HSM:       key[HSM]{},
}

Functions

func AfterDispatch

func AfterDispatch(ctx context.Context, hsm Instance, event Event) <-chan struct{}

AfterDispatch returns a channel that closes when the specified event is dispatched. Unlike AfterProcess, this signals when the event is added to the queue, not when processing completes. Use this helper for tests and deterministic observation only; it is not part of the supported production synchronization path.

func AfterEntry

func AfterEntry[T stringLike](ctx context.Context, hsm Instance, state T) <-chan struct{}

AfterEntry returns a channel that closes when the specified state is entered. The state parameter should be the fully qualified state path (e.g., "/parent/child"). Use this helper for tests and deterministic observation only; it is not part of the supported production synchronization path.

func AfterExecuted

func AfterExecuted[T stringLike](ctx context.Context, hsm Instance, state T) <-chan struct{}

AfterExecuted returns a channel that closes when the specified state's do-activity has completed execution. The state parameter should be the fully qualified state path. Use this helper for tests and deterministic observation only; it is not part of the supported production synchronization path.

func AfterExit

func AfterExit[T stringLike](ctx context.Context, hsm Instance, state T) <-chan struct{}

AfterExit returns a channel that closes when the specified state is exited. The state parameter should be the fully qualified state path (e.g., "/parent/child"). Use this helper for tests and deterministic observation only; it is not part of the supported production synchronization path.

func AfterProcess

func AfterProcess(ctx context.Context, hsm Instance, maybeEvent ...Event) <-chan struct{}

AfterProcess returns a channel that closes when event processing completes. If an event is provided, the channel closes after that specific event is processed. If no event is provided, the channel closes after the next processing cycle completes. Use this helper for tests and deterministic observation only; production callers should wait on the completion channel returned by Dispatch, Set, Restart, Stop, DispatchAll, or DispatchTo.

func AttributeType added in v1.3.1

func AttributeType[T any]() reflect.Type

AttributeType returns a reflect.Type token for explicit Attribute declarations.

func Call added in v1.0.3

func Call[T stringLike](ctx context.Context, hsm Instance, name T, args ...any) (any, error)

Call dispatches an OnCall event and invokes the named operation.

func Get added in v1.0.3

func Get[T stringLike](ctx context.Context, hsm Instance, name T) (any, bool)

Get reads an attribute value from the given state machine or from context.

func ID

func ID(hsm Instance) string

ID returns the unique identifier of a state machine instance. The ID is assigned when the state machine is created and remains constant throughout its lifecycle.

func IsAncestor

func IsAncestor(current, target string) bool

IsAncestor checks whether current is an ancestor of target in the state hierarchy. It returns true if current appears in the path from the root to target's parent. Returns false if current equals target, or if either path is "." (relative root). The root path "/" is considered an ancestor of all other paths.

func IsKind added in v1.3.0

func IsKind(k uint64, bases ...uint64) bool

IsKind reports whether k matches any of the provided base kinds.

func LCA

func LCA(a, b string) string

LCA finds the Lowest Common Ancestor between two qualified state names in a hierarchical state machine. It takes two qualified names 'a' and 'b' as strings and returns their closest common ancestor.

For example: - LCA("/s/s1", "/s/s2") returns "/s" - LCA("/s/s1", "/s/s1/s11") returns "/s/s1" - LCA("/s/s1", "/s/s1") returns "/s/s1"

func MakeKind added in v1.3.0

func MakeKind(bases ...uint64) uint64

MakeKind creates a new kind using the canonical HSM kind implementation.

func Match

func Match[V stringLike, P stringLike](value V, patterns ...P) bool

Match provides a simple interface, handling basic cases directly and delegating complex matching to the match function.

func Name

func Name(hsm Instance) string

Name returns the simple name of a state machine instance (without path prefix). This extracts the base name from the qualified name, e.g., "child" from "/parent/child".

func New

func New[T Instance](sm T, model *FinalizedModel, maybeConfig ...Config) T

func QualifiedName

func QualifiedName(hsm Instance) string

QualifiedName returns the fully qualified name of a state machine instance. For nested state machines, this includes the parent path (e.g., "/parent/child"). For top-level state machines, this is typically just the name with a leading slash.

func Start

func Start[T Instance](ctx context.Context, sm T, maybeData ...any) T

func Started

func Started[T Instance](ctx context.Context, sm T, model *FinalizedModel, maybeConfig ...Config) T

Started creates and starts a new state machine instance with the given model and configuration. The state machine will begin executing from its initial state.

Example:

model := hsm.Define(...)
sm := hsm.Started(context.Background(), &MyHSM{}, &model, hsm.Config{
    ID: "my-hsm-1",
    ActivityTimeout: 5 * time.Second,
})

func TakeSnapshot

func TakeSnapshot[S any, T snapshotTarget[S]](ctx context.Context, hsm T) S

TakeSnapshot captures the current state of a machine or group. For a state machine it returns Snapshot. For a Group it returns []Snapshot in group order.

Types

type AttributeChange added in v1.0.3

type AttributeChange struct {
	Name string
	Old  any
	New  any
}

AttributeChange is the payload for attribute change events.

type CallData added in v1.0.3

type CallData struct {
	Name string
	Args []any
}

CallData is the payload for call events.

type Clock added in v1.0.8

type Clock struct {
	After    func(time.Duration) <-chan time.Time
	NewTimer func(time.Duration) *time.Timer
}

Clock provides injectable timer functions used by the state machine runtime. Nil fields fall back to DefaultClock.

type Completion added in v1.3.1

type Completion <-chan struct{}

Completion is a receive-only completion channel. It remains compatible with `<-hsm.Dispatch(...)` while allowing callers to inspect runtime failures after the channel closes.

func Dispatch

func Dispatch[T context.Context](ctx T, hsm Instance, event Event) Completion

Dispatch sends an event to a specific state machine instance. It returns a completion channel that closes when the event has been fully processed. Waiting on that channel is the supported production synchronization path before asserting on post-transition state. Go's completion channel can be received directly; call Completion.Err after it closes to inspect direct runtime submission failures.

Example:

model := hsm.Define(...)
sm := hsm.Started(context.Background(), &MyHSM{}, &model)
done := hsm.Dispatch(context.Background(), sm, hsm.Event{Name: "start"})
<-done // Wait for event processing to complete

func DispatchAll

func DispatchAll(ctx context.Context, event Event) Completion

DispatchAll sends an event to all state machine instances in the current context. It returns a completion channel that closes when all selected instances have processed the event. Waiting on that channel is the supported production synchronization path before asserting on post-transition state.

Example:

sm1 := hsm.Started(context.Background(), &MyHSM{}, &model)
sm2 := hsm.Started(sm1.Context(), &MyHSM{}, &model)
done := hsm.DispatchAll(sm2.Context(), hsm.Event{Name: "globalEvent"})
<-done // Wait for all instances to process the event

func DispatchTo

func DispatchTo[T stringLike](ctx context.Context, event Event, maybeIds ...T) Completion

DispatchTo sends an event to the selected state machine instances in the current context. It returns a completion channel that closes when all matching instances have processed the event. Waiting on that channel is the supported production synchronization path before asserting on post-transition state.

func Restart

func Restart(ctx context.Context, hsm Instance, maybeData ...any) Completion

Restart stops a state machine and restarts it from the initial state. Optional data can be passed to reinitialize the state machine's data field. It returns a completion channel that closes when the restart completes. Waiting on that channel is the supported production synchronization path before asserting on post-transition state.

func Set added in v1.0.3

func Set[T stringLike](ctx context.Context, hsm Instance, name T, value any) Completion

Set updates an attribute value and emits an OnSet change event. It returns a completion channel that closes after the resulting processing completes. Waiting on that channel is the supported production synchronization path before asserting on post-transition state.

func Stop

func Stop(ctx context.Context, hsm Instance) Completion

Stop gracefully stops a state machine instance. It returns a completion channel that closes after shutdown processing finishes. Waiting on that channel is the supported production synchronization path before asserting on post-transition state. If no instance is available, Stop returns the shared closed completion channel.

Example:

sm := hsm.Started(context.Background(), &MyHSM{}, &model)
// ... use state machine ...
<-hsm.Stop(context.Background(), sm)

func (Completion) Err added in v1.3.1

func (completion Completion) Err() error

Err returns the runtime failure associated with this completion, if any.

func (Completion) Wait added in v1.3.1

func (completion Completion) Wait() error

Wait waits for completion and returns Err.

type ComposableModel added in v1.3.1

type ComposableModel interface {
	Model | *Model | FinalizedModel | *FinalizedModel
}

ComposableModel is a model value that can provide a submachine body.

type Config

type Config struct {
	// ID is a unique identifier for the state machine instance.
	ID string
	// ActivityTimeout is the timeout for the state activity to terminate.
	ActivityTimeout time.Duration
	// Clock overrides the timer functions used by the state machine runtime.
	Clock Clock
	// Queue overrides the event buffer used by the state machine runtime.
	Queue Queue
	// Name is the name of the state machine.
	Name string
	// Data to be passed during initialization
	Data any
}

Config provides configuration options for state machine initialization.

type DefaultModelFinalizer added in v1.3.1

type DefaultModelFinalizer struct{}

DefaultModelFinalizer builds the package's runtime dispatch indexes.

func (DefaultModelFinalizer) Finalize added in v1.3.1

func (DefaultModelFinalizer) Finalize(model *Model) *FinalizedModel

type DefaultModelValidator added in v1.3.1

type DefaultModelValidator struct{}

DefaultModelValidator runs the package's built-in model validation.

func (DefaultModelValidator) Validate added in v1.3.1

func (DefaultModelValidator) Validate(model *Model)

type Element

type Element interface {
	Id() string
	Kind() uint64
	Owner() string
	QualifiedName() string
	Name() string
}

type Event

type Event struct {
	Kind   uint64 `xml:"kind,attr" json:"kind"`
	Name   string `xml:"name,attr" json:"name"`
	ID     string `xml:"id,attr" json:"id"`
	Source string `xml:"source,attr,omitempty" json:"source,omitempty"`
	Target string `xml:"target,attr,omitempty" json:"target,omitempty"`
	Data   any    `xml:"data" json:"data"`
	Schema any    `xml:"schema" json:"schema"`
}

func (Event) WithData

func (e Event) WithData(data any) Event

func (Event) WithDataAndID

func (e Event) WithDataAndID(data any, id string) Event

type EventSnapshot added in v1.2.0

type EventSnapshot struct {
	Name   string
	Kind   uint64 `json:"-"`
	Target string
	Guard  bool
	// Schema is copied from model metadata when the snapshot is captured.
	// Mutable map, slice, array, pointer, interface, and exported struct fields
	// are recursively copied where Go reflection permits.
	Schema any
}

type ExpressionFunc added in v1.0.6

type ExpressionFunc[T Instance] func(ctx context.Context, hsm T, event Event) bool

ExpressionFunc is a function type that evaluates a condition on a state machine. Expressions are used for transition guards to determine whether a transition should be taken. They receive the current context, state machine instance, and the triggering event, returning true if the condition is satisfied.

type FinalizedModel added in v1.3.1

type FinalizedModel struct {
	*Model
	// contains filtered or unexported fields
}

FinalizedModel is the runtime-ready form of a declarative Model. It owns derived dispatch indexes used by runtime instances.

func Define

func Define[T stringLike](name T, redefinableElements ...RedefinableElement) FinalizedModel

Define creates a new state machine model with the given name and elements. The first argument can be either a string name or a RedefinableElement. Additional elements are added to the model in the order they are specified.

Example:

model := hsm.Define(
    "traffic_light",
    hsm.State("red"),
    hsm.State("yellow"),
    hsm.State("green"),
    hsm.Initial(hsm.Target("red")),
)

func Redefine added in v1.3.1

func Redefine(model FinalizedModel, args ...any) FinalizedModel

Redefine replays an existing model under the same root or under a new root name and applies replacement model elements.

func (FinalizedModel) Activities added in v1.3.1

func (state FinalizedModel) Activities() []string

func (FinalizedModel) Entry added in v1.3.1

func (state FinalizedModel) Entry() []string

func (FinalizedModel) Exit added in v1.3.1

func (state FinalizedModel) Exit() []string

type Group added in v1.0.6

type Group struct {
	// contains filtered or unexported fields
}

Group is a composite instance that forwards operations to multiple instances. It flattens nested groups and broadcasts events to all members.

func MakeGroup added in v1.3.0

func MakeGroup(values ...any) *Group

MakeGroup creates a new group from the provided instances. If the first argument is a string, it is used as the group ID.

func NewGroup added in v1.0.6

func NewGroup(instances ...Instance) *Group

NewGroup creates a new group from the provided instances. Nested groups are flattened.

func (*Group) Clock added in v1.0.8

func (group *Group) Clock() Clock

func (*Group) Context added in v1.0.6

func (group *Group) Context() context.Context

func (*Group) Instances added in v1.0.6

func (group *Group) Instances() []Instance

Instances returns a snapshot of the group's instances.

func (*Group) Snapshots added in v1.3.1

func (group *Group) Snapshots() []Snapshot

Snapshots captures one snapshot per grouped instance in group order.

func (*Group) State added in v1.0.6

func (group *Group) State() string

func (*Group) States added in v1.3.1

func (group *Group) States() []string

States returns the current state path for each grouped instance in group order.

type HSM

type HSM struct {
	// contains filtered or unexported fields
}

type Instance

type Instance interface {
	// State returns the current state's qualified name.
	State() string
	Context() context.Context

	Clock() Clock
	// contains filtered or unexported methods
}

Instance represents an active state machine instance that can process events and track state. It provides methods for event dispatch and state management.

func FromContext

func FromContext(ctx context.Context) (Instance, bool)

FromContext retrieves a state machine instance from a context. Returns the instance and a boolean indicating whether it was found.

Example:

if sm, ok := hsm.FromContext(ctx); ok {
    log.Printf("Current state: %s", sm.State())
}

func InstancesFromContext

func InstancesFromContext(ctx context.Context) ([]Instance, bool)

InstancesFromContext retrieves all state machine instances from a context. Returns a slice of instances and a boolean indicating whether any were found. This is useful when multiple state machines share a context and you need to access or iterate over all of them.

type Model

type Model struct {
	// contains filtered or unexported fields
}

Model represents the complete state machine model definition. It contains the root state and maintains a namespace of all elements.

func InlineModel added in v1.3.1

func InlineModel(redefinableElements ...RedefinableElement) Model

InlineModel creates an anonymous model body for generated submachine composition. Prefer Define for named reusable models.

func (*Model) Activities

func (state *Model) Activities() []string

func (*Model) Entry

func (state *Model) Entry() []string

func (*Model) Exit

func (state *Model) Exit() []string

func (*Model) Members

func (model *Model) Members() map[string]Element

func (*Model) TransitionSnapshots added in v1.3.1

func (model *Model) TransitionSnapshots() []TransitionSnapshot

TransitionSnapshots returns a stable snapshot of model transitions.

type ModelFinalizer added in v1.3.1

type ModelFinalizer interface {
	Finalize(model *Model) *FinalizedModel
}

ModelFinalizer prepares a validated model for runtime use.

type ModelFinalizerFunc added in v1.3.1

type ModelFinalizerFunc func(model *Model) *FinalizedModel

ModelFinalizerFunc adapts a function to ModelFinalizer.

func (ModelFinalizerFunc) Finalize added in v1.3.1

func (fn ModelFinalizerFunc) Finalize(model *Model) *FinalizedModel

type ModelValidator added in v1.3.1

type ModelValidator interface {
	Validate(model *Model)
}

ModelValidator validates a model after all elements have been applied.

type ModelValidatorFunc added in v1.3.1

type ModelValidatorFunc func(model *Model)

ModelValidatorFunc adapts a function to ModelValidator.

func (ModelValidatorFunc) Validate added in v1.3.1

func (fn ModelValidatorFunc) Validate(model *Model)

type ObservationData added in v1.3.1

type ObservationData struct {
	Event      Event
	Occurrence string
	Time       time.Time
}

ObservationData is the payload for hsm/observation events.

type OperationFunc added in v1.0.6

type OperationFunc[T Instance] func(ctx context.Context, hsm T, event Event)

OperationFunc is a function type that performs an action on a state machine. Operations are used for state entry/exit behaviors, transition effects, and activity functions. They receive the current context, state machine instance, and the triggering event.

type Queue added in v1.2.3

type Queue struct {
	Push func(ctx context.Context, event Event) error
	Pop  func(ctx context.Context) (Event, bool, error)
	Len  func(ctx context.Context) (int, error)
	// contains filtered or unexported fields
}

Queue provides injectable buffering for regular state machine events. Push, Pop, and Len are synchronous hooks: each operation must complete and return its event/availability/error directly to the runtime. Completion events are always stored in the runtime-owned LIFO side of Queue and are selected before the configurable regular-event queue.

type RedefinableElement

type RedefinableElement = func(model *Model, stack []Element) Element

RedefinableElement is a function type that modifies a Model by adding or updating elements. It's used to build the state machine structure in a declarative way.

func Activity

func Activity(operations ...any) RedefinableElement

Activity defines a long-running action that is executed while in a state. The activity is started after the entry action and stopped before the exit action.

Example:

hsm.Activity(func(ctx context.Context, hsm *MyHSM, event Event) {
    for {
        select {
        case <-ctx.Done():
            return
        case <-time.After(time.Second):
            log.Println("Activity tick")
        }
    }
})

func After

func After(expr any) RedefinableElement

After creates a time-based transition that occurs after a specified duration. The duration can be dynamically computed based on the state machine's context.

Example:

hsm.Transition(
    hsm.After(func(ctx context.Context, hsm *MyHSM, event Event) time.Duration {
        return time.Second * 30
    }),
    hsm.Source("active"),
    hsm.Target("timeout")
)

func At added in v1.1.0

func At(expr any) RedefinableElement

At creates a time-based transition that occurs at a specific timestamp. The timestamp can be dynamically computed based on the state machine's context.

Example:

hsm.Transition(
    hsm.At(func(ctx context.Context, hsm *MyHSM, event Event) time.Time {
        return time.Now().Add(time.Minute)
    }),
    hsm.Source("active"),
    hsm.Target("timeout")
)

func Attribute added in v1.0.3

func Attribute[T stringLike](name T, args ...any) RedefinableElement

Attribute declares a model-level attribute with an optional default value. Attributes can be observed via OnSet("name") transitions and updated at runtime via Set / Instance.Set.

func Choice

func Choice[T redefinableOrString](elementOrName T, partialElements ...RedefinableElement) RedefinableElement

Choice creates a pseudo-state that enables dynamic branching based on guard conditions. The first transition with a satisfied guard condition is taken.

Example:

hsm.Choice(
    hsm.Transition(
        hsm.Target("approved"),
        hsm.Guard(func(ctx context.Context, hsm *MyHSM, event Event) bool {
            return hsm.score > 700
        })
    ),
    hsm.Transition(
        hsm.Target("rejected")
    )
)

func DeepHistory added in v1.0.3

func DeepHistory[T redefinableOrString](elementOrName T, partialElements ...RedefinableElement) RedefinableElement

DeepHistory creates a deep history pseudostate within a composite state. If no history is available, any transitions defined on this pseudostate are used; otherwise the parent state's initial is used.

func Defer

func Defer[T interface {
	string | *Event | Event
}](events ...T) RedefinableElement

Defer schedules events to be processed after the current state is exited.

Example:

hsm.Defer(hsm.Event{Name: "event_name"})

func Effect

func Effect(operations ...any) RedefinableElement

Effect defines an action to be executed during a transition. The effect function is called after exiting the source state and before entering the target state.

Example:

hsm.Effect(func(ctx context.Context, hsm *MyHSM, event Event) {
    log.Printf("Transitioning with event: %s", event.Name)
})

func Entry

func Entry(operations ...any) RedefinableElement

Entry defines an action to be executed when entering a state. The entry action is executed before any internal activities are started.

Example:

hsm.Entry(func(ctx context.Context, hsm *MyHSM, event Event) {
    log.Printf("Entering state with event: %s", event.Name)
})

func EntryPoint added in v1.3.1

func EntryPoint[T stringLike](name T, partialElements ...RedefinableElement) RedefinableElement

EntryPoint creates or selects a named submachine entry point. Within a State, it creates a transient vertex with an optional outgoing transition. Within a Transition, it rewrites the transition target to the direct matching entry point on the transition target.

func Every

func Every(expr any) RedefinableElement

Every schedules events to be processed on an interval.

Example:

hsm.Every(func(ctx context.Context, hsm T, event Event) time.Duration {
    return time.Second * 30
})

func Exit

func Exit(operations ...any) RedefinableElement

Exit defines an action to be executed when exiting a state. The exit action is executed after any internal activities are stopped.

Example:

hsm.Exit(func(ctx context.Context, hsm *MyHSM, event Event) {
    log.Printf("Exiting state with event: %s", event.Name)
})

func ExitPoint added in v1.3.1

func ExitPoint[T stringLike](name T, partialElements ...RedefinableElement) RedefinableElement

ExitPoint creates a transient vertex used to route a submachine outcome to a handler transition on the owning state.

func Final

func Final[T stringLike](name T) RedefinableElement

Final creates a final state that represents the completion of a composite state or the entire state machine. When a final state is entered, a completion event is generated.

Example:

hsm.State("process",
    hsm.State("working"),
    hsm.Final("done"),
    hsm.Transition(
        hsm.Source("working"),
        hsm.Target("done")
    )
)

func Finalizer added in v1.3.1

func Finalizer(finalizer any) RedefinableElement

Finalizer overrides the model finalizer used while defining or redefining a model.

func Guard

func Guard(expression any) RedefinableElement

Guard defines a condition that must be true for a transition to be taken. If multiple transitions are possible, the first one with a satisfied guard is chosen.

Example:

hsm.Guard(func(ctx context.Context, hsm *MyHSM, event Event) bool {
    return hsm.counter > 10
})

func Initial

func Initial(partialElements ...RedefinableElement) RedefinableElement

Initial defines the initial state for a composite state or the entire state machine. When a composite state is entered, its initial state is automatically entered.

Example:

hsm.State("operational",
    hsm.State("idle"),
    hsm.State("running"),
    hsm.Initial(hsm.Target("idle")),
)

func Observe added in v1.3.1

func Observe[T Instance](observer func(context.Context, T, Event), targets ...any) RedefinableElement

Observe attaches an observer to behavior execution and selected transition events.

func On

func On[T interface{ *Event | Event | ~string }](events ...T) RedefinableElement

On defines the events that can cause a transition. Multiple events can be specified for a single transition.

Example:

hsm.Transition(
    hsm.On("start", "resume"),
    hsm.Source("idle"),
    hsm.Target("running")
)

func OnCall added in v1.0.3

func OnCall[T stringLike](name T) RedefinableElement

OnCall creates a trigger for Call() invocations of the named operation.

func OnSet added in v1.0.3

func OnSet[T stringLike](name T) RedefinableElement

OnSet creates an attribute-change trigger for the given attribute name. It is the attribute-based equivalent of On(...) and is driven by Set.

func Operation

func Operation[T stringLike](name T, maybeFn ...any) RedefinableElement

Operation declares a named callable for Call()/OnCall(). Supported callables include function values and method expressions.

func ShallowHistory added in v1.0.3

func ShallowHistory[T redefinableOrString](elementOrName T, partialElements ...RedefinableElement) RedefinableElement

ShallowHistory creates a shallow history pseudostate within a composite state. If no history is available, any transitions defined on this pseudostate are used; otherwise the parent state's initial is used.

func Source

func Source[T redefinableOrString](nameOrPartialElement T) RedefinableElement

Source specifies the source state of a transition. It can be used within a Transition definition.

Example:

hsm.Transition(
    hsm.Source("idle"),
    hsm.Target("running")
)

func State

func State[T stringLike](name T, partialElements ...RedefinableElement) RedefinableElement

State creates a new state element with the given name and optional child elements. States can have entry/exit actions, activities, and transitions.

Example:

hsm.State("active",
    hsm.Entry(func(ctx context.Context, hsm *MyHSM, event Event) {
        log.Println("Entering active state")
    }),
    hsm.Activity(func(ctx context.Context, hsm *MyHSM, event Event) {
        // Long-running activity
    }),
    hsm.Exit(func(ctx context.Context, hsm *MyHSM, event Event) {
        log.Println("Exiting active state")
    })
)

func SubmachineState added in v1.3.1

func SubmachineState[T stringLike, M ComposableModel](name T, machine M, partialElements ...RedefinableElement) RedefinableElement

SubmachineState composes a reusable child model under a state boundary.

func Target

func Target[T redefinableOrString](nameOrPartialElement T) RedefinableElement

Target specifies the target state of a transition. It can be used within a Transition definition.

Example:

hsm.Transition(
    hsm.Source("idle"),
    hsm.Target("running")
)

func Transition

func Transition[T redefinableOrString](nameOrPartialElement T, partialElements ...RedefinableElement) RedefinableElement

Transition creates a new transition between states. Transitions can have events, guards, and effects.

Example:

hsm.Transition(
    hsm.On("submit"),
    hsm.Source("draft"),
    hsm.Target("review"),
    hsm.Guard(func(ctx context.Context, hsm *MyHSM, event Event) bool {
        return hsm.IsValid()
    }),
    hsm.Effect(func(ctx context.Context, hsm *MyHSM, event Event) {
        log.Println("Transitioning from draft to review")
    })
)

func TransitionType added in v1.3.1

func TransitionType(kindValue uint64) RedefinableElement

TransitionType overrides the transition kind selected during model construction. kindValue must derive from TransitionKind.

func Validator added in v1.3.1

func Validator(validator any) RedefinableElement

Validator overrides the model validator used while defining or redefining a model.

func When

func When(expr any) RedefinableElement

type Snapshot

type Snapshot struct {
	ID            string
	QualifiedName string
	State         string
	// Attributes is a fresh map whose values are copied from runtime storage.
	// Mutating this map, or mutable values reachable only through it, does not
	// change the running instance.
	Attributes map[string]any
	QueueLen   int
	// Events is a fresh slice for this snapshot. Event schemas follow
	// EventSnapshot.Schema copy semantics.
	Events      []EventSnapshot
	Transitions []TransitionSnapshot
}

func TakeSnapshots added in v1.3.1

func TakeSnapshots(ctx context.Context, hsm Instance) []Snapshot

TakeSnapshots captures one snapshot per selected instance. For groups, snapshots preserve the group's flattened member order. For a single state machine instance, it returns a one-element slice.

type TransitionSnapshot added in v1.3.1

type TransitionSnapshot struct {
	Name   string
	Kind   uint64 `json:"-"`
	Source string
	Target string
	Events []string
	Guard  bool
}

Directories

Path Synopsis
cmd
conformance command
kind module
muid module

Jump to

Keyboard shortcuts

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