statechart

package module
v0.0.0-...-9f0dfa8 Latest Latest
Warning

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

Go to latest
Published: Aug 26, 2025 License: MIT Imports: 3 Imported by: 0

README

Statechart - Minimal Generic Statechart Library for Go

A lightweight, type-safe statechart implementation in Go using generics. Supports hierarchical states, parallel states, history states, guards, and actions in 272 lines of code.

Features

  • Generic Type Safety: Use any comparable type for states and events, any type for context
  • Hierarchical States: Nested states with behavioral inheritance
  • Parallel States: Multiple concurrent state regions
  • History States: Remember last active child state
  • Guards and Actions: Conditional transitions with side effects
  • Thread Safe: Concurrent access protection with RWMutex
  • Compile-time Definitions: Define state structure at compile time
  • Runtime Flexibility: Dynamic event processing and state transitions

Generic Design Approach

What's Generic?
  1. State IDs (S comparable): Any comparable type (string, int, custom types)
  2. Event Types (E comparable): Any comparable type for events
  3. Context Data (C any): Any type for user-defined context/extended state
Benefits
  • Type Safety: Compile-time checking prevents invalid state/event combinations
  • Performance: No reflection or type assertions needed
  • Reusability: Same library works with different type combinations
  • Zero Allocation: Struct-based generics avoid interface boxing

Statechart Runtime Concept

The statechart runtime is the execution engine that orchestrates state machine behavior:

Core Responsibilities
  1. State Management: Tracks current active state and maintains hierarchical relationships
  2. Event Processing: Receives events and finds applicable transitions based on current state
  3. Transition Execution: Coordinates exit actions, transition actions, and entry actions
  4. Context Preservation: Maintains user-defined state data across transitions
  5. Hierarchy Navigation: Supports behavioral inheritance where child states inherit parent transitions
  6. Concurrency Control: Thread-safe operations for multi-goroutine environments
Runtime Architecture

The runtime fits in ~270 LOC by focusing on essential statechart semantics:

  • Compile-time Structure: States and transitions defined at compile time
  • Runtime Execution: Dynamic event processing and state changes
  • Memory Efficient: Direct struct allocation, no object pools needed for this size
  • Type Safe: Generics eliminate runtime type checking

Usage

package main

import (
    "context"
    "github.com/user/statechart"
)

// Define your types
type MyState string
type MyEvent string
type MyContext struct {
    Counter int
}

func main() {
    // Create runtime with initial context
    ctx := statechart.Context[MyContext](MyContext{Counter: 0})
    runtime := statechart.NewRuntime[MyState, MyEvent, MyContext](ctx)
    
    // Add states
    runtime.AddState(
        statechart.StateID[MyState]("idle"), 
        statechart.SimpleState, 
        statechart.StateID[MyState](""),
    )
    
    // Add transitions with guards and actions
    runtime.AddTransition(
        statechart.StateID[MyState]("idle"),
        statechart.StateID[MyState]("active"),
        statechart.EventType[MyEvent]("start"),
        func(ctx context.Context, from statechart.StateID[MyState], event statechart.EventType[MyEvent], context *statechart.Context[MyContext]) bool {
            return (*context).Counter < 10 // Guard condition
        },
        func(ctx context.Context, from, to statechart.StateID[MyState], event statechart.EventType[MyEvent], context *statechart.Context[MyContext]) error {
            (*context).Counter++
            return nil
        },
    )
    
    // Start and use
    runtime.SetInitialState(statechart.StateID[MyState]("idle"))
    runtime.Start(context.Background())
    runtime.SendEvent(context.Background(), statechart.EventType[MyEvent]("start"))
}

API Overview

Core Types
  • Runtime[S, E, C]: Main statechart runtime engine
  • State[S, E, C]: Individual state with hierarchy and actions
  • Transition[S, E, C]: State transition with guard and action
  • Guard[S, E, C]: Function type for transition conditions
  • Action[S, E, C]: Function type for side effects
State Types
  • SimpleState: Basic state with no children
  • CompositeState: Hierarchical state with child states
  • ParallelState: Concurrent state regions
  • HistoryState: Remembers last active child state
Key Methods
  • AddState(): Define states with hierarchy
  • AddTransition(): Define transitions with guards/actions
  • SendEvent(): Process events
  • IsInState(): Check current state (including ancestors)
  • GetContext(): Access user context data

Example: Door Controller

See example/main.go for a complete door controller example demonstrating:

  • Hierarchical states (Closed -> Locked/Unlocked)
  • Guards (can't open when locked)
  • Actions (logging, context updates)
  • State introspection
  • Context management

Installation

go get github.com/user/statechart

License

MIT License - see LICENSE file for details.

Documentation

Overview

Package statechart provides a minimal, generic statechart implementation (~200 LOC) supporting hierarchical states, parallel states, history states, guards, and actions.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Action

type Action[S comparable, E comparable, C any] func(ctx context.Context, from, to StateID[S], event EventType[E], context *Context[C]) error

type Context

type Context[C any] struct{ Value C }

type EventType

type EventType[E comparable] struct{ Value E }

type Guard

type Guard[S comparable, E comparable, C any] func(ctx context.Context, from StateID[S], event EventType[E], context *Context[C]) bool

Function types for guards and actions

type Runtime

type Runtime[S comparable, E comparable, C any] struct {
	// contains filtered or unexported fields
}

Runtime represents the statechart runtime engine

func NewRuntime

func NewRuntime[S comparable, E comparable, C any](initialContext Context[C]) *Runtime[S, E, C]

NewRuntime creates a new statechart runtime

func (*Runtime[S, E, C]) AddState

func (r *Runtime[S, E, C]) AddState(id StateID[S], stateType StateType, parent StateID[S]) *State[S, E, C]

AddState adds a state to the statechart

func (*Runtime[S, E, C]) AddTransition

func (r *Runtime[S, E, C]) AddTransition(from, to StateID[S], event EventType[E], guard Guard[S, E, C], action Action[S, E, C])

AddTransition adds a transition between states

func (*Runtime[S, E, C]) GetContext

func (r *Runtime[S, E, C]) GetContext() *Context[C]

GetContext returns the current context

func (*Runtime[S, E, C]) GetCurrentState

func (r *Runtime[S, E, C]) GetCurrentState() StateID[S]

GetCurrentState returns the current state ID

func (*Runtime[S, E, C]) IsInState

func (r *Runtime[S, E, C]) IsInState(id StateID[S]) bool

IsInState checks if the statechart is currently in the specified state (including ancestors)

func (*Runtime[S, E, C]) SendEvent

func (r *Runtime[S, E, C]) SendEvent(ctx context.Context, event EventType[E]) error

SendEvent sends an event to the statechart

func (*Runtime[S, E, C]) SetInitialState

func (r *Runtime[S, E, C]) SetInitialState(id StateID[S]) error

SetInitialState sets the initial state

func (*Runtime[S, E, C]) Start

func (r *Runtime[S, E, C]) Start(ctx context.Context) error

Start starts the statechart runtime

func (*Runtime[S, E, C]) Stop

func (r *Runtime[S, E, C]) Stop(ctx context.Context) error

Stop stops the statechart runtime

type State

type State[S comparable, E comparable, C any] struct {
	ID        StateID[S]
	Type      StateType
	Parent    *State[S, E, C]
	Children  []*State[S, E, C]
	OnEntry   Action[S, E, C]
	OnExit    Action[S, E, C]
	LastChild *State[S, E, C] // For history states
}

State represents a state in the statechart

type StateID

type StateID[S comparable] struct{ Value S }

Generic wrapper types for type safety

type StateType

type StateType int

StateType defines the type of state

const (
	SimpleState StateType = iota
	CompositeState
	ParallelState
	HistoryState
)

type Transition

type Transition[S comparable, E comparable, C any] struct {
	From   StateID[S]
	To     StateID[S]
	Event  EventType[E]
	Guard  Guard[S, E, C]
	Action Action[S, E, C]
}

Transition represents a state transition

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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