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_by_name, ensure_state_enum_loaded,
14};
15use macro_registry::callsite::current_module_path;
16use proc_macro::TokenStream;
17use syn::{Item, ItemImpl, parse_macro_input};
18
19#[proc_macro_attribute]
20pub fn state(_attr: TokenStream, item: TokenStream) -> TokenStream {
21    let input = parse_macro_input!(item as Item);
22    let input = match input {
23        Item::Enum(item_enum) => item_enum,
24        other => return invalid_state_target_error(&other).into(),
25    };
26
27    // Validate the enum before proceeding
28    if let Some(error) = validate_state_enum(&input) {
29        return error.into();
30    }
31
32    let enum_info = match EnumInfo::from_item_enum(&input) {
33        Ok(info) => info,
34        Err(err) => return err.to_compile_error().into(),
35    };
36
37    // Store metadata in `state_enum_map`
38    store_state_enum(&enum_info);
39
40    // Generate structs and implementations dynamically
41    let expanded = generate_state_impls(&enum_info.module_path);
42
43    TokenStream::from(expanded)
44}
45
46#[proc_macro_attribute]
47pub fn machine(_attr: TokenStream, item: TokenStream) -> TokenStream {
48    let input = parse_macro_input!(item as Item);
49    let input = match input {
50        Item::Struct(item_struct) => item_struct,
51        other => return invalid_machine_target_error(&other).into(),
52    };
53
54    let machine_info = MachineInfo::from_item_struct(&input);
55
56    // Validate the struct before proceeding
57    if let Some(error) = validate_machine_struct(&input, &machine_info) {
58        return error.into();
59    }
60
61    // Store metadata in `machine_map`
62    store_machine_struct(&machine_info);
63
64    // Generate any required structs or implementations dynamically
65    let expanded = generate_machine_impls(&machine_info);
66
67    TokenStream::from(expanded)
68}
69
70#[proc_macro_attribute]
71pub fn transition(
72    _attr: proc_macro::TokenStream,
73    item: proc_macro::TokenStream,
74) -> proc_macro::TokenStream {
75    let input = parse_macro_input!(item as ItemImpl);
76
77    // -- Step 1: Parse
78    let tr_impl = match parse_transition_impl(&input) {
79        Ok(parsed) => parsed,
80        Err(err) => return err.into(),
81    };
82
83    let module_path = current_module_path();
84
85    let state_path: StateModulePath = module_path.clone().into();
86    let machine_path: MachinePath = module_path.clone().into();
87    let _ = ensure_state_enum_loaded(&state_path);
88    let machine_info_owned = ensure_machine_loaded_by_name(&machine_path, &tr_impl.machine_name);
89    let machine_info = match machine_info_owned.as_ref() {
90        Some(info) => info,
91        None => {
92            return missing_transition_machine_error(
93                &tr_impl.machine_name,
94                &module_path,
95                tr_impl.machine_span,
96            )
97            .into();
98        }
99    };
100
101    if let Some(err) = validate_transition_functions(&tr_impl, machine_info) {
102        return err.into();
103    }
104
105    // -- Step 3: Generate new code
106    let expanded = generate_transition_impl(&input, &tr_impl, machine_info, &module_path);
107
108    // Combine expanded code with the original `impl` if needed
109    // or simply return the expanded code
110    expanded.into()
111}
112
113#[proc_macro_attribute]
114pub fn validators(attr: TokenStream, item: TokenStream) -> TokenStream {
115    let module_path = current_module_path();
116    parse_validators(attr, item, &module_path)
117}