fsm

package module
v1.0.0 Latest Latest
Warning

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

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

README

go-fsm

A minimal, generic Finite State Machine for Go.

Philosophy

Most FSM libraries come with events, sources, destinations, callbacks, and background contexts.

This one doesn't.

A finite state machine only needs states - each state has a single transition function that returns the next state name.

That's it.

Installation

go get codeberg.org/datek/fsm

Usage

Define your shared data type, create states with transition functions, and run the machine. The first state in the slice is the initial state. The machine stops when a transition returns StateFinal.

package main

import (
	"fmt"

	"codeberg.org/datek/fsm"
)

type Data struct {
	count int
}

func main() {
	increment := &fsm.State[Data]{
		Name: "increment",
		Transit: func(d *Data) fsm.StateName {
			d.count++
			if d.count >= 3 {
				return fsm.StateFinal
			}
			return "increment"
		},
	}

	data := &Data{}
	machine := fsm.NewFSM([]*fsm.State[Data]{increment}, data)
	machine.Run()

	fmt.Printf("machine.CurrentStateName(): %v\n", machine.CurrentStateName())
	fmt.Printf("data.count: %v\n", data.count)
}

// machine.CurrentStateName(): STATE_FINAL
// data.count: 3

API

NewFSM(states []*State[T], data *T) FSM

Creates a new FSM. The first element of states is the initial state. data is a pointer to shared context passed into every transition.

FSM.Run()

Runs the machine until a transition returns StateFinal. If a transition returns a state name that was not registered, the call will panic.

FSM.CurrentStateName() StateName

Returns the name of the current state.

StateFinal

The sentinel value "STATE_FINAL" — returning it from a transition stops the machine.

Error handling

Transit does not return an error. All error handling is the caller's responsibility inside the transition function. The recommended pattern is to store errors in the shared data and check them in subsequent states:

type Data struct {
    result string
    err    error
}

fetch := &fsm.State[Data]{
    Name: "fetch",
    Transit: func(d *Data) fsm.StateName {
        d.result, d.err = doSomething()
        if d.err != nil {
            return fsm.StateFinal
        }
        return "process"
    },
}

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrInvalidState = errors.New("invalid state")

Functions

This section is empty.

Types

type FSM

type FSM interface {
	Run()
	CurrentStateName() StateName
}

func NewFSM

func NewFSM[T any](states []*State[T], data *T) FSM

type State

type State[T any] struct {
	Name    StateName
	Transit func(data *T) StateName
}

type StateName

type StateName string
const StateFinal StateName = "STATE_FINAL"

Jump to

Keyboard shortcuts

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