statecraft-derive 0.1.0

Derive macros for the statecraft state machine library
Documentation
use proc_macro::TokenStream;
use quote::quote;
use syn::{DeriveInput, Meta, MetaList, parse_macro_input};

#[proc_macro_derive(State)]
pub fn state(input: TokenStream) -> TokenStream {
    let input = parse_macro_input!(input as DeriveInput);

    let name = input.ident;
    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();

    let expanded = quote! {
        impl #impl_generics State for #name #ty_generics #where_clause {}
    };

    TokenStream::from(expanded)
}

#[proc_macro_derive(Stateful, attributes(state))]
pub fn stateful(input: TokenStream) -> TokenStream {
    let input = parse_macro_input!(input as DeriveInput);
    let state_attrs: Vec<_> = input
        .attrs
        .iter()
        .filter(|attr| attr.style == syn::AttrStyle::Outer)
        .filter(|attr| attr.path().is_ident("state"))
        .collect();
    if state_attrs.len() != 1 {
        panic!("#[derive(Stateful)] requires specifying the state with #[state(<State>)] attribute")
    }

    let state_toks: Vec<_> = match state_attrs[0].meta.clone() {
        Meta::List(MetaList { tokens, .. }) => tokens.into_iter().collect(),
        _ => panic!("#[state(<State>)] is the proper way to describe the state"),
    };

    let state = if state_toks.len() != 1 {
        panic!("Only one state allowed in #[state(<State>)] attribute")
    } else {
        &state_toks[0]
    };

    let name = input.ident;
    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();

    let expanded = quote! {
        impl #impl_generics Stateful for #name #ty_generics #where_clause {
            type State = #state;
        }
    };

    TokenStream::from(expanded)
}

#[proc_macro_derive(SelfTransitionable)]
pub fn self_transitionable(input: TokenStream) -> TokenStream {
    let input = parse_macro_input!(input as DeriveInput);

    let name = input.ident;
    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();

    let expanded = quote! {
        impl #impl_generics SelfTransitionable for #name #ty_generics #where_clause {
        }
    };

    TokenStream::from(expanded)
}