Skip to content

A simple statechart implementation that includes a runtime.

License

comalice/statechart

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 

Repository files navigation

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.

About

A simple statechart implementation that includes a runtime.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages