Skip to main content

statum_macros/
lib.rs

1moddef::moddef!(
2    flat (pub) mod {
3    },
4    flat (pub(crate)) mod {
5        state,
6        machine,
7        transition,
8        validators
9    }
10);
11
12use crate::{
13    MachinePath, StateModulePath, ensure_machine_loaded, ensure_state_enum_loaded, get_machine,
14};
15use macro_registry::callsite::current_module_path;
16use proc_macro::TokenStream;
17use syn::{ItemEnum, ItemImpl, ItemStruct, parse_macro_input};
18
19#[proc_macro_attribute]
20pub fn state(_attr: TokenStream, item: TokenStream) -> TokenStream {
21    let input = parse_macro_input!(item as ItemEnum);
22
23    // Validate the enum before proceeding
24    if let Some(error) = validate_state_enum(&input) {
25        return error.into();
26    }
27
28    let enum_info = match EnumInfo::from_item_enum(&input) {
29        Ok(info) => info,
30        Err(err) => return err.to_compile_error().into(),
31    };
32
33    // Store metadata in `state_enum_map`
34    store_state_enum(&enum_info);
35
36    // Generate structs and implementations dynamically
37    let expanded = generate_state_impls(&enum_info.module_path);
38
39    TokenStream::from(expanded)
40}
41
42#[proc_macro_attribute]
43pub fn machine(_attr: TokenStream, item: TokenStream) -> TokenStream {
44    let input = parse_macro_input!(item as ItemStruct);
45
46    let machine_info = MachineInfo::from_item_struct(&input);
47
48    // Validate the struct before proceeding
49    if let Some(error) = validate_machine_struct(&input, &machine_info) {
50        return error.into();
51    }
52
53    // Store metadata in `machine_map`
54    store_machine_struct(&machine_info);
55
56    // Generate any required structs or implementations dynamically
57    let expanded = generate_machine_impls(&machine_info);
58
59    TokenStream::from(expanded)
60}
61
62#[proc_macro_attribute]
63pub fn transition(
64    _attr: proc_macro::TokenStream,
65    item: proc_macro::TokenStream,
66) -> proc_macro::TokenStream {
67    let input = parse_macro_input!(item as ItemImpl);
68
69    // -- Step 1: Parse
70    let tr_impl = parse_transition_impl(&input);
71
72    let module_path = current_module_path();
73
74    let state_path: StateModulePath = module_path.clone().into();
75    let machine_path: MachinePath = module_path.clone().into();
76    let _ = ensure_state_enum_loaded(&state_path);
77    let _ = ensure_machine_loaded(&machine_path);
78
79    let machine_info_owned = get_machine(&machine_path);
80    let machine_info = machine_info_owned
81        .as_ref()
82        .expect("Machine not found, even though we validated above");
83
84    if let Some(err) = validate_transition_functions(&tr_impl.functions, machine_info) {
85        return err.into();
86    }
87
88    // -- Step 3: Generate new code
89    let expanded = generate_transition_impl(&input, &tr_impl, machine_info, &module_path);
90
91    // Combine expanded code with the original `impl` if needed
92    // or simply return the expanded code
93    expanded.into()
94}
95
96#[proc_macro_attribute]
97pub fn validators(attr: TokenStream, item: TokenStream) -> TokenStream {
98    let module_path = current_module_path();
99    parse_validators(attr, item, &module_path)
100}