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