architect-derive 0.4.0

Architect.xyz Trading Platform API, proc-macros
Documentation
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, Data, DeriveInput, Fields, Ident, Variant};

pub fn enum_factory(args: TokenStream, input: TokenStream) -> TokenStream {
    // Parse the builder name from the attribute arguments
    let builder: Ident =
        syn::parse(args).expect("expceted a builder, e.g. #[enum_factory(Builder)]");
    let derive_input: DeriveInput = parse_macro_input!(input);
    let derive_input_copied = derive_input.clone();
    let ident = derive_input.ident;
    let data_enum = match derive_input.data {
        Data::Enum(data_enum) => data_enum,
        _ => panic!("enum_factory can only be derived for enums"),
    };
    let match_arms: Vec<_> = data_enum
        .variants
        .iter()
        .map(|v| {
            let Variant { ident: variant_name, fields, attrs, .. } = v;
            match fields {
                Fields::Unnamed(fields_unnamed) if fields_unnamed.unnamed.len() == 1 => {
                    let variant_s = variant_name.to_string();
                    quote! {
                        #(#attrs)*
                        #variant_s => {
                            builder.build(|inner| Ok(Self::#variant_name(inner)))
                        }
                    }
                }
                _ => panic!("variant `{}` is not a single tuple variant", variant_name),
            }
        })
        .collect();
    TokenStream::from(quote! {
        #derive_input_copied

        impl #ident {
            pub fn new(kind: &str, builder: #builder) -> anyhow::Result<Self> {
                match kind {
                    #(#match_arms)*
                    other => anyhow::bail!("unknown enum variant: {}", other),
                }
            }
        }
    })
}