macro-input-macros 0.3.1

the macro part of macro-input
Documentation
use crate::{field_name, mod_name};
use macro_compose::{Collector, Expand};
use syn::{parse_quote, Data, DeriveInput, Expr, FieldValue, Fields, ItemImpl};

pub struct TryFromAttributes;

impl Expand<DeriveInput> for TryFromAttributes {
    type Output = ItemImpl;

    fn expand(&self, input: &DeriveInput, _: &mut Collector) -> Option<Self::Output> {
        let ident = &input.ident;

        let fields = match &input.data {
            Data::Struct(s) => &s.fields,
            _ => unreachable!(),
        };

        let mod_name = mod_name(input);
        let values = fields.iter().map(|f| -> Expr {
            let (_, ident) = field_name(f);
            parse_quote!(#mod_name::#ident.get_value::<>(attrs)?)
        });

        let block: Expr = match fields {
            Fields::Named(named) => {
                let values = values
                    .zip(
                        named
                            .named
                            .iter()
                            .map(|f| f.ident.as_ref().cloned().unwrap()),
                    )
                    .map(|(value, ident)| -> FieldValue { parse_quote!(#ident: #value) });

                parse_quote!(
                    Self {
                        #(#values),*
                    }
                )
            }
            Fields::Unnamed(_) => parse_quote!(Self (#(#values),*)),
            Fields::Unit => parse_quote!(Self),
        };

        Some(parse_quote!(
            impl ::core::convert::TryFrom<&[::syn::Attribute]> for #ident {
                type Error = ::syn::Error;

                fn try_from(attrs: &[::syn::Attribute]) -> ::syn::Result<Self> {
                    ::std::result::Result::Ok(#block)
                }
            }
        ))
    }
}