Skip to main content

statecraft_derive/
lib.rs

1use proc_macro::TokenStream;
2use quote::quote;
3use syn::{DeriveInput, Meta, MetaList, parse_macro_input};
4
5#[proc_macro_derive(State)]
6pub fn state(input: TokenStream) -> TokenStream {
7    let input = parse_macro_input!(input as DeriveInput);
8
9    let name = input.ident;
10    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
11
12    let expanded = quote! {
13        impl #impl_generics State for #name #ty_generics #where_clause {}
14    };
15
16    TokenStream::from(expanded)
17}
18
19#[proc_macro_derive(Stateful, attributes(state))]
20pub fn stateful(input: TokenStream) -> TokenStream {
21    let input = parse_macro_input!(input as DeriveInput);
22    let state_attrs: Vec<_> = input
23        .attrs
24        .iter()
25        .filter(|attr| attr.style == syn::AttrStyle::Outer)
26        .filter(|attr| attr.path().is_ident("state"))
27        .collect();
28    if state_attrs.len() != 1 {
29        panic!("#[derive(Stateful)] requires specifying the state with #[state(<State>)] attribute")
30    }
31
32    let state_toks: Vec<_> = match state_attrs[0].meta.clone() {
33        Meta::List(MetaList { tokens, .. }) => tokens.into_iter().collect(),
34        _ => panic!("#[state(<State>)] is the proper way to describe the state"),
35    };
36
37    let state = if state_toks.len() != 1 {
38        panic!("Only one state allowed in #[state(<State>)] attribute")
39    } else {
40        &state_toks[0]
41    };
42
43    let name = input.ident;
44    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
45
46    let expanded = quote! {
47        impl #impl_generics Stateful for #name #ty_generics #where_clause {
48            type State = #state;
49        }
50    };
51
52    TokenStream::from(expanded)
53}
54
55#[proc_macro_derive(SelfTransitionable)]
56pub fn self_transitionable(input: TokenStream) -> TokenStream {
57    let input = parse_macro_input!(input as DeriveInput);
58
59    let name = input.ident;
60    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
61
62    let expanded = quote! {
63        impl #impl_generics SelfTransitionable for #name #ty_generics #where_clause {
64        }
65    };
66
67    TokenStream::from(expanded)
68}