fsm

package module
v0.1.2 Latest Latest
Warning

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

Go to latest
Published: May 20, 2026 License: MIT Imports: 6 Imported by: 0

README

Build Status

finite state machine for Go

This is package implements finite state machine

Basic Example

package main

import (
	"fmt"
	"reflect"

	"github.com/ssych/fsm"
)

type Person struct {
	Сash  int
	State fsm.State
}

func isRich(e *fsm.Event) (bool, error) {
	person := e.Source.(*Person)
	if person.Сash > 1000000 {
		return true, nil
	}
	return false, nil
}

func after(e *fsm.Event) error {
	person := e.Source.(*Person)
	fmt.Println(person.State)
	return nil
}

func before(e *fsm.Event) error {
	person := e.Source.(*Person)
	fmt.Println(person.State)
	return nil
}

func main() {

	person := &Person{
		Сash:  1000001,
		State: fsm.State("poor"),
	}

	f := fsm.NewFSM()

	f.Register(reflect.TypeOf((*Person)(nil)), "State", fsm.Events{{
		Name:   "grow_rich",
		From:   []fsm.State{"poor"},
		To:     fsm.State("rich"),
		Guards: []fsm.Guard{isRich},
		After:  after,
		Before: before,
	}})

	f.Fire(person, "grow_rich")
}

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Chain

type Chain struct {
	Guards []IGuard
}

Chain is a composite IGuard that runs a sequence of guards in order. It implements IGuard itself, so it can be nested or used wherever IGuard is accepted. The first guard to return a non-nil error stops execution and returns that error.

func (*Chain) Guard

func (c *Chain) Guard(ctx context.Context, obj any) error

Guard implements IGuard. It iterates over all guards in order, returning the first non-nil error encountered, or nil if all guards pass.

Parameters:

  • ctx: context passed to each guard.
  • obj: the domain object undergoing the state transition.

Returns:

  • error: the first validation error from any guard, or nil if all pass.

type Event

type Event struct {
	// Event is the name of the event being fired.
	Event string
	// Source holds the domain object undergoing the transition.
	Source any
	// Destination is the target state the object will transition to.
	Destination State
}

Event represents a state machine event being processed during a transition.

type EventTransition

type EventTransition struct {
	// Name is the identifier of the event that triggers this transition.
	Name string
	// From lists the source states from which this transition is valid.
	From []State
	// To is the destination state reached after a successful transition.
	To State
	// Guards holds legacy guard functions evaluated before the transition.
	Guards []Guard
	// GuardInstances holds IGuard implementations evaluated before the transition.
	GuardInstances []IGuard
	// After is an optional callback invoked after the state has been updated.
	After func(context.Context, *Event) error
	// Before is an optional callback invoked before the state is updated.
	Before func(context.Context, *Event) error
}

EventTransition defines a single transition rule in the FSM, specifying the source states, target state, guards, and lifecycle callbacks.

type Events

type Events []EventTransition

Events is a slice of EventTransition definitions used to configure an FSM.

type FSM

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

FSM is the top-level finite state machine registry that manages per-type state machine configurations and dispatches transitions.

func NewFSM

func NewFSM() *FSM

NewFSM creates and returns an empty FSM instance ready for machine registration.

Returns:

  • *FSM: a new FSM with an initialized machine registry

func (*FSM) Fire

func (f *FSM) Fire(ctx context.Context, s interface{}, event string) error

Fire executes a named state transition on the given object.

Parameters:

  • ctx: context for cancellation and deadline propagation
  • s: pointer to the domain object to transition
  • event: the name of the event to fire

Returns:

  • error: if the transition fails

Errors:

  • InternalError if no machine is registered for the object's type
  • UnknownEventError if the event does not exist for the current state
  • InvalidTransitionError if a guard prevents the transition
  • ctx.Err() if the context is canceled or expired

func (*FSM) GetPermittedEvents

func (f *FSM) GetPermittedEvents(ctx context.Context, s interface{}, options ...Option) ([]string, error)

GetPermittedEvents returns the names of all events that can currently be fired for the given object based on its state and active guards.

Parameters:

  • ctx: context for cancellation and deadline propagation
  • s: pointer to the domain object to inspect
  • options: optional modifiers, e.g. SkipGuard to bypass guard evaluation

Returns:

  • []string: names of all currently permitted events
  • error: if the evaluation fails

Errors:

  • InternalError if no machine is registered for the object's type

func (*FSM) GetPermittedStates

func (f *FSM) GetPermittedStates(ctx context.Context, s interface{}, options ...Option) ([]State, error)

GetPermittedStates returns all destination states reachable from the object's current state. Unlike GetPermittedEvents, guards are never evaluated; all structurally valid transitions are returned regardless of guard conditions. The options parameter is accepted for API consistency but has no effect here.

Parameters:

  • ctx: context for cancellation and deadline propagation
  • s: pointer to the domain object to inspect
  • options: accepted for API consistency; guards are not evaluated and SkipGuard has no effect

Returns:

  • []State: all states reachable via valid transitions from the current state
  • error: if the evaluation fails

Errors:

  • InternalError if no machine is registered for the object's type
  • UnknownEventError if an internal transition key is inconsistent

func (*FSM) MayFire

func (f *FSM) MayFire(ctx context.Context, s interface{}, event string, options ...Option) (bool, error)

MayFire reports whether a named event can be fired for the given object without executing the transition.

Parameters:

  • ctx: context for cancellation and deadline propagation
  • s: pointer to the domain object to check
  • event: the name of the event to check
  • options: optional modifiers, e.g. SkipGuard to bypass guard evaluation

Returns:

  • bool: true if the transition is permitted
  • error: if the check itself fails

Errors:

  • InternalError if no machine is registered for the object's type

func (*FSM) Register

func (f *FSM) Register(tag reflect.Type, column string, events []EventTransition) error

Register associates a state machine configuration with a specific Go type.

Parameters:

  • tag: the reflect.Type of the domain object to register
  • column: the struct field name that holds the state value
  • events: the list of transition definitions for this machine

Returns:

  • error: always nil; reserved for future validation

func (*FSM) Release

func (f *FSM) Release(s interface{})

Release removes the instance lock for the given object from memory. This is optional and should be called when an instance is no longer needed to prevent memory accumulation in long-running applications.

type Guard

type Guard func(context.Context, *Event) (bool, error)

Guard is the legacy guard function type. It returns a boolean indicating whether the transition is permitted, and an optional error for infrastructure failures (e.g. database errors). Use IGuard for new guards that need to return user-facing validation errors.

type IGuard

type IGuard interface {
	// Guard evaluates whether a state transition is permitted for the given object.
	//
	// Parameters:
	//   - ctx: context for cancellation and deadline propagation
	//   - obj: the domain object undergoing the transition
	//
	// Returns:
	//   - error: non-nil if the transition should be canceled
	Guard(ctx context.Context, obj any) error
}

IGuard is the plugin interface for guard logic. Implement this interface in domain packages and register instances via EventTransition.GuardInstances. The FSM calls Guard for each registered instance before executing a transition; a non-nil error cancels the transition and propagates directly to the caller.

Methods:

  • Guard: evaluates whether a state transition is permitted for the given object

type InternalError

type InternalError struct{}

InternalError is returned when the FSM encounters an unexpected internal condition, such as an unregistered type or invalid reflection state.

func (InternalError) Error

func (InternalError) Error() string

type InvalidTransitionError

type InvalidTransitionError struct {
	// Event is the name of the event that was attempted.
	Event string
	// State is the current state from which the transition was blocked.
	State string
}

InvalidTransitionError is returned when a guard prevents a state transition from occurring for the specified event.

func (InvalidTransitionError) Error

func (e InvalidTransitionError) Error() string

type Option

type Option func(*Options)

Option is a functional option for configuring FSM query behavior.

func SkipGuard

func SkipGuard(value bool) Option

SkipGuard returns an Option that controls whether guards are skipped during MayFire and permission checks.

Parameters:

  • value: true to skip guard evaluation, false to enforce it

Returns:

  • Option: a functional option that sets the SkipGuards flag

type Options

type Options struct {
	// SkipGuards disables guard evaluation during MayFire, GetPermittedEvents, and GetPermittedStates checks.
	SkipGuards bool
}

Options holds configuration flags that modify FSM query behavior.

type State

type State string

State represents a named FSM state as a string value, compatible with database scanning and driver interfaces.

func (*State) Scan

func (s *State) Scan(value interface{}) error

Scan implements the sql.Scanner interface to read a state value from a database column.

Parameters:

  • value: the raw database value, expected to be []uint8 or string

Returns:

  • error: always nil; panics via log.Fatalf on unexpected types

func (*State) Value

func (s *State) Value() (driver.Value, error)

Value implements the driver.Valuer interface for database serialization.

Returns:

  • driver.Value: the state as a string, or nil if the receiver is nil
  • error: always nil

type UnknownEventError

type UnknownEventError struct {
	// Event is the name of the unrecognized event.
	Event string
}

UnknownEventError is returned when an event is fired that has no registered transition for the object's current state.

func (UnknownEventError) Error

func (e UnknownEventError) Error() string

Jump to

Keyboard shortcuts

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