state_machines_macro/lib.rs
1//! Procedural macros for the state machines crate.
2//!
3//! This crate provides the `state_machine!` macro for defining
4//! type-safe state machines with transitions, guards, and callbacks.
5//!
6//! # Architecture
7//!
8//! The macro implementation is split into several modules:
9//!
10//! - **types**: Data structures representing state machines
11//! - **parser**: Parsing macro input into our data structures
12//! - **codegen**: Generating Rust code from the parsed structures
13//! - **validation**: Validating state machine definitions
14//!
15//! # Example
16//!
17//! ```ignore
18//! use state_machines::state_machine;
19//!
20//! state_machine! {
21//! name: Door,
22//! state: DoorState,
23//! initial: Closed,
24//! states: [Open, Closed],
25//! events: {
26//! open {
27//! transition: { from: Closed, to: Open }
28//! }
29//! close {
30//! transition: { from: Open, to: Closed }
31//! }
32//! }
33//! }
34//! ```
35
36use proc_macro::TokenStream;
37
38// Module declarations
39mod codegen;
40mod parser;
41mod types;
42mod validation;
43
44/// Define a state machine with compile-time guarantees.
45///
46/// This macro generates:
47/// - A state enum with all defined states
48/// - A state machine struct with transition methods
49/// - Event methods for triggering transitions (e.g., `open()`)
50/// - Can methods for checking if transitions are allowed (e.g., `can_open()`)
51/// - Default implementations
52/// - Machine trait implementation for introspection
53///
54/// # Syntax
55///
56/// ```ignore
57/// state_machine! {
58/// name: MachineName, // Required: name of the generated struct
59/// state: StateName, // Required: name of the state enum
60/// initial: InitialState, // Required: initial state
61/// async: true, // Optional: enable async support
62/// action: action_method, // Optional: method called on every transition
63///
64/// states: [ // Required: list of states
65/// StateA,
66/// StateB(DataType), // States can have associated data
67/// superstate Parent { // Superstates for hierarchical machines
68/// state Child1,
69/// state Child2,
70/// initial: Child1, // Superstate's initial child
71/// }
72/// ],
73///
74/// events: { // Optional: event definitions
75/// event_name {
76/// payload: PayloadType, // Optional: event payload type
77/// guards: [guard1], // Optional: event-level guards
78/// unless: [guard2], // Optional: inverted guards
79/// before: [callback1], // Optional: before callbacks
80/// after: [callback2], // Optional: after callbacks
81///
82/// transition: {
83/// from: SourceState,
84/// to: TargetState,
85/// guards: [guard3], // Optional: transition-level guards
86/// unless: [guard4], // Optional: transition-level unless
87/// before: [cb3], // Optional: transition-level before
88/// after: [cb4], // Optional: transition-level after
89/// }
90/// }
91/// },
92///
93/// callbacks: { // Optional: global callbacks
94/// before_transition [
95/// { name: log_transition, from: [StateA], to: [StateB], on: [event] }
96/// ],
97/// after_transition [
98/// { name: after_cb }
99/// ],
100/// around_transition [
101/// { name: wrap_cb }
102/// ]
103/// }
104/// }
105/// ```
106///
107/// # Generated Code
108///
109/// The macro generates:
110///
111/// 1. A state enum with all variants
112/// 2. A machine struct with:
113/// - `new()` constructor
114/// - `state()` accessor
115/// - Event methods (e.g., `activate()`)
116/// - Can methods (e.g., `can_activate()`)
117/// - Storage accessors for state-associated data
118/// 3. A `DEFINITION` constant for runtime introspection
119/// 4. Trait implementations (Machine, Default, Debug)
120///
121/// # Features
122///
123/// - **Type-safe transitions**: Invalid transitions are compile errors
124/// - **Guards**: Conditional transitions with guard methods
125/// - **Callbacks**: Execute code before/after/around transitions
126/// - **State data**: Associate data with specific states
127/// - **Hierarchical states**: Superstates containing child states
128/// - **Async support**: Async guards, callbacks, and transitions
129/// - **Introspection**: Runtime metadata about the machine structure
130///
131/// # Learning Resource
132///
133/// This codebase is intentionally over-commented to serve as a learning
134/// resource for procedural macro development. Each module contains
135/// extensive documentation explaining the what, why, and how.
136#[proc_macro]
137pub fn state_machine(input: TokenStream) -> TokenStream {
138 // Parse the macro input into our StateMachine structure
139 // The Parse trait implementation is in parser.rs
140 let machine = syn::parse_macro_input!(input as types::StateMachine);
141
142 // Expand the machine into generated code
143 // This validates the definition and generates all the code
144 // The expand() method is in codegen.rs
145 match machine.expand() {
146 Ok(tokens) => tokens.into(),
147 Err(err) => err.to_compile_error().into(),
148 }
149}