This is a monorepo containing hierarchical state machine (HSM) implementations across multiple programming languages. Each language implementation is maintained as a separate Git submodule, allowing for independent development while maintaining a unified project structure.
This repository uses Git submodules to organize language-specific implementations:
✅ C++ (cpp/
)
- Status: Complete implementation
- Build System: CMake with comprehensive test suite
- Features: Full SCXML-compliant hierarchical state machines, event handling, timers, guards, and actions
- Repository: stateforward/hsm-cpp
✅ Go (go/
)
- Status: Complete implementation with OpenTelemetry observability
- Features: Hierarchical state machines with comprehensive event system, context propagation, and tracing
- Repository: stateforward/hsm-go
✅ JavaScript/TypeScript (javascript/
)
- Status: Complete implementation
- Package Manager: npm with comprehensive test suite
- Features: ES6+ implementation with async/await support, TypeScript definitions, and Node.js ecosystem integration
- Repository: stateforward/hsm-javascript
✅ Python (python/
)
- Status: Complete implementation
- Package Manager: uv with async support
- Features: asyncio-based implementation with comprehensive test coverage and modern Python practices
- Repository: stateforward/hsm-python
✅ Rust (rust/
)
- Status: Complete implementation
- Build System: Cargo with comprehensive benchmarks
- Features: Memory-safe, zero-cost abstractions with strong type safety and performance optimizations
- Repository: stateforward/hsm-rust
🚧 Zig (zig/
)
- Status: Work in Progress (WIP)
- Build System: Custom Zig build system
- Features: Planned low-level, high-performance implementation leveraging Zig's systems programming capabilities
- Repository: stateforward/hsm-zig
# Clone the main repository with all submodules
git clone --recursive https://github.com/stateforward/hsm.git
cd hsm
# If you already cloned without --recursive, initialize submodules
git submodule update --init --recursive
Each language implementation is self-contained and can be used independently:
# C++ implementation
cd cpp && mkdir build && cd build && cmake .. && make
# Go implementation
cd go && go build
# JavaScript implementation
cd javascript && npm install
# Python implementation
cd python && uv sync
# Rust implementation
cd rust && cargo build
# Zig implementation (WIP)
cd zig && zig build
All implementations follow the same core concepts:
- Hierarchical States: Support for nested state machines
- Events & Transitions: Event-driven state changes with guards and effects
- Entry/Exit Actions: Behaviors executed when entering/exiting states
- Timers: Time-based transitions and delayed events
- SCXML Compliance: Based on W3C SCXML specification where applicable
var Model = hsm.Define(
"TestHSM",
hsm.State("foo", hsm.Entry(noBehavior),
hsm.Exit(noBehavior)),
hsm.State("bar", hsm.Entry(noBehavior),
hsm.Exit(noBehavior)),
hsm.Transition(
hsm.On("foo"),
hsm.Source("foo"),
hsm.Target("bar"),
hsm.Effect(noBehavior),
),
hsm.Transition(
hsm.On("bar"),
hsm.Source("bar"),
hsm.Target("foo"),
hsm.Effect(noBehavior),
),
hsm.Initial(hsm.Target("foo"), hsm.Effect(noBehavior)),
)
const model = hsm.define(
"TestHSM",
hsm.state("foo",
hsm.entry(noBehavior),
hsm.exit(noBehavior)),
hsm.state("bar",
hsm.entry(noBehavior),
hsm.exit(noBehavior)),
hsm.transition(fooEvent,
hsm.source("foo"),
hsm.target("bar"),
hsm.effect(noBehavior)),
hsm.transition(barEvent,
hsm.source("bar"),
hsm.target("foo"),
hsm.effect(noBehavior)),
hsm.initial(
hsm.target("foo"),
hsm.effect(noBehavior)
))
model = hsm.define(
"TestHSM",
hsm.state("foo",
hsm.entry(noBehavior),
hsm.exit(noBehavior)
),
hsm.state("bar",
hsm.entry(noBehavior),
hsm.exit(noBehavior)
),
hsm.transition(
hsm.on(foo_event),
hsm.source("foo"),
hsm.target("bar"),
hsm.effect(noBehavior),
),
hsm.transition(
hsm.on(bar_event),
hsm.source("bar"),
hsm.target("foo"),
hsm.effect(noBehavior),
),
hsm.initial(hsm.target("foo"), hsm.effect(noBehavior)),
)
#include "cthsm.hpp"
// Define the model with compile-time HSM
auto model = cthsm::define(
"TestHSM",
cthsm::initial(cthsm::target("foo")),
cthsm::state(
"foo",
cthsm::transition(cthsm::on("bar"), cthsm::target("bar"))
),
cthsm::state(
"bar",
cthsm::transition(cthsm::on("foo"), cthsm::target("foo"))
)
);
// Compile and use it
cthsm::compile<decltype(model)> sm;
std::cout << "Initial state: " << sm.state() << "\n";
sm.dispatch("bar");
std::cout << "After bar event: " << sm.state() << "\n";
use rust_hsm::*;
let model = define(
"TestHSM",
vec![
state("foo",
vec![
entry(|ctx, instance| println!("Entering foo")),
exit(|ctx, instance| println!("Exiting foo")),
]
),
state("bar",
vec![
entry(|ctx, instance| println!("Entering bar")),
exit(|ctx, instance| println!("Exiting bar")),
]
),
transition(
vec![on("bar")],
source("foo"),
target("bar"),
vec![effect(|ctx, instance| println!("Transitioning foo -> bar"))],
),
transition(
vec![on("foo")],
source("bar"),
target("foo"),
vec![effect(|ctx, instance| println!("Transitioning bar -> foo"))],
),
initial(target("foo")),
]
);
const hsm = @import("hsm");
// Define the state machine model at compile time
const model = comptime hsm.define("TestHSM", .{
hsm.initial(hsm.target("foo")),
hsm.state("foo", .{
hsm.entry(fooEntry),
hsm.exit(fooExit),
hsm.transition(.{ hsm.on("bar"), hsm.target("bar"), hsm.effect(fooToBarEffect) })
}),
hsm.state("bar", .{
hsm.entry(barEntry),
hsm.exit(barExit),
hsm.transition(.{ hsm.on("foo"), hsm.target("foo"), hsm.effect(barToFooEffect) })
})
});
// Build and run the state machine
var built_model = try model.build(allocator);
defer built_model.deinit();
var context = hsm.Context.init(allocator);
var instance = hsm.Instance.init();
defer instance.deinit();
var sm = try hsm.start(&context, &instance, &built_model);
defer sm.deinit();
std.log.info("Initial state: {s}", .{sm.state()});
try sm.dispatch(&context, hsm.Event.init(allocator, "bar"));
std.log.info("After bar event: {s}", .{sm.state()});
Each language implementation has its own repository and contribution guidelines. Please refer to the individual README files in each submodule for language-specific contribution information.
This project is licensed under the MIT License - see the LICENSE file in each submodule for details.