xstate-macros
Procedural macros for xstate-core:
#[derive(TypedEvent)]: an enum as the typed event vocabulary of a machine (rename rules, payload mapping,From/TryFrom<Event>,declared_events(),checkagainst aMachine);#[derive(TypedState)]: an enum naming a machine’s leaf states (is_active,check);statechart!: a Rust-literal chart DSL covering every XState construct, validated at compile time (duplicates, initial children, target resolution, tree shape) and building aMachine.
Status: 0.1.0, with trybuild UI tests for the diagnostics. The xstate-statemachine facade
(feature macros) is enough: the generated code resolves xstate_core and serde_json through
it, and a CI job checks a crate that depends on the facade alone
(tests/facade-only/). Using xstate-macros directly still needs xstate-core (and serde for
payload types) in the calling crate, and statechart! additionally needs serde_json.
#![allow(unused)]
fn main() {
use xstate_core::{MachineLogic, SyncInterpreter};
use xstate_macros::{TypedEvent, TypedState, statechart};
#[derive(TypedEvent)]
#[event(rename_all = "SCREAMING_SNAKE_CASE")]
enum DoorEvent { Open, Close }
#[derive(Debug, Clone, Copy, PartialEq, TypedState)]
#[state(machine = "door")]
enum Door { Closed, Opened }
let machine = statechart! {
id: "door",
initial: closed,
states: {
closed { on { OPEN => opened } }
opened { on { CLOSE => closed } }
}
}?;
let mut door = SyncInterpreter::new(machine, MachineLogic::dynamic());
door.start()?;
door.send(DoorEvent::Open)?;
assert!(Door::Opened.is_active(&door));
Ok::<(), xstate_core::Error>(())
}
Features
None (a proc-macro crate).
Python counterpart
The Pythonic DSL (xstate_statemachine.pythonic):
class-based StateMachine / State, the builder and the functional form. Rust gets typed enums
and a compile-time-checked macro instead of metaclass scanning.