microrm-macros 0.6.3

Procedural macro implementations for the microrm crate.
Documentation
use quote::quote;

pub fn derive(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let input: syn::DeriveInput = syn::parse_macro_input!(tokens);

    let items = if let syn::Data::Struct(syn::DataStruct {
        struct_token: _,
        fields: syn::Fields::Named(fields),
        semi_token: _,
    }) = input.data
    {
        fields
            .named
            .into_iter()
            .map(|f| (f.ident.unwrap(), f.ty))
            .collect::<Vec<_>>()
    } else {
        panic!("Can only derive Schema on data structs with named fields!");
    };

    let db_ident = input.ident;

    let item_names = items
        .iter()
        .map(|field| field.0.clone())
        .collect::<Vec<_>>();
    let item_types = items
        .iter()
        .map(|field| field.1.clone())
        .collect::<Vec<_>>();
    let visit_items = items.iter().map(|field| {
        let item_type = &field.1;

        quote! {
            <#item_type as ::microrm::schema::DatabaseItem>::accept_item_visitor(v);
        }
    });

    let name_field = match input
        .attrs
        .iter()
        .filter(|v| v.path.is_ident("name"))
        .map(|v| v.parse_meta())
        .next()
    {
        Some(Ok(syn::Meta::NameValue(nv))) => {
            let literal = nv.lit;
            quote! { const NAME: Option<&'static str> = Some(#literal); }
        },
        Some(_) => {
            panic!("expected name format is name = \"...\"")
        },
        None => quote! {},
    };

    quote! {
        impl ::microrm::schema::DatabaseItem for #db_ident {
            fn accept_item_visitor(v: &mut impl ::microrm::schema::DatabaseItemVisitor) {
                use ::microrm::schema::DatabaseItem;
                #(#visit_items)*
            }

            fn build(seal: ::microrm::schema::BuildSeal) -> Self where Self: Sized {
                Self {
                    #( #item_names: < #item_types as ::microrm::schema::DatabaseItem>::build(seal) ),*
                }
            }

            type Subitems = ( #(#item_types),* , );
        }
        impl ::microrm::schema::Schema for #db_ident { #name_field }
    }
    .into()
}