builders 0.5.0

Rust macros for building structs
Documentation
use quote::quote;
use syn::{parse_macro_input, Attribute, DeriveInput, Expr, ExprLit, Field, Lit, LitBool, Meta, MetaNameValue};

use crate::util::{self, get_stripped_generics};

fn must_generate(f: &Field) -> bool {
    let attr = util::get_field_attr(&f.attrs, "constructor");
    if let Some(Attribute{ meta: Meta::NameValue(MetaNameValue{ ref value, .. }), .. }) = attr.last() {
        if let Expr::Lit(ExprLit{lit: Lit::Bool(LitBool{value, ..}), ..}) = value {
            return *value;
        }
    }
    true
}

pub (crate) fn constructor_derive_impl(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let ast = parse_macro_input!(input as DeriveInput);
    let vis = &ast.vis;
    let name = &ast.ident;

    let fields = match util::get_named_struct(&ast) {
        Ok(fields) => fields,
        Err(err) => return err.into_compile_error().into(),
    };

    let args = fields.iter().filter_map(|f| {
        if !must_generate(&f) { return None; }
        let ident = util::get_field_ident(f);
        let ty = &f.ty;
        Some(
        quote! {
            #ident : impl std::convert::Into<#ty>
        })
    });
    let names = fields.iter().map(|f| {
        let ident = util::get_field_ident(f);
        if must_generate(&f) {
            quote!( #ident : #ident.into() )
        } else {
            quote!( #ident : std::default::Default::default() )
        }
    });

    let generics = &ast.generics;
    let wher = &generics.where_clause;
    let stripped_generics = get_stripped_generics(generics, false);

    quote! {
        impl #generics #name #stripped_generics #wher {
            #vis fn new(
                #( #args ,)*
            ) -> #name #stripped_generics {
                Self {
                    #( #names ,)*
                }
            }
        }

    }.into()
}