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}