confgr_derive 0.2.1

Procedural derive macro implementation for the confgr crate
Documentation
use crate::{get_ident_from_type, ConfigAttributes, SUFFIX};
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use syn::{Ident, Type};

pub fn generate_layer(
    name: &Ident,
    attributes: &ConfigAttributes,
    field_data: &[(&Ident, &Type, ConfigAttributes)],
) -> TokenStream {
    let layer_name = format_ident!("{}{}", name, SUFFIX);

    let struct_rename = if let Some(attr_name) = &attributes.name {
        quote! { #[serde(rename = #attr_name)] }
    } else {
        quote! {}
    };

    let (field_defs, empty_defs, merges) = field_data.iter().fold(
        (vec![], vec![], vec![]),
        |(mut defs, mut empty, mut merges), (field_name, ty, attr)| {
            let field_rename = if let Some(rename) = &attr.name {
                quote! { #[serde(rename = #rename)] }
            } else {
                quote! {}
            };

            if attr.nest {
                let ty_ident = get_ident_from_type(ty);
                let nested_builder = format_ident!("{}{}", ty_ident, SUFFIX);
                defs.push(quote! {
                    #field_rename
                    #[serde(default)]
                    pub #field_name: #nested_builder
                });
                empty.push(quote! {
                    #field_name: #nested_builder::empty()
                });
                merges.push(quote! {
                    #field_name: self.#field_name.merge(other.#field_name)
                });
            } else {
                defs.push(quote! {
                    #field_rename
                    pub #field_name: Option<#ty>
                });
                empty.push(quote! {
                    #field_name: None
                });
                merges.push(quote! {
                    #field_name: self.#field_name.or(other.#field_name)
                });
            }
            (defs, empty, merges)
        },
    );

    quote! {
        #[automatically_derived]
        #[derive(::serde::Deserialize, Debug, Clone)]
        #[doc(hidden)]
        #struct_rename
        pub struct #layer_name {
            #( #field_defs ),*
        }

        #[automatically_derived]
        impl Default for #layer_name {
           fn default() -> Self {
                #name::default().into()
            }
        }

        #[automatically_derived]
        impl ::confgr::core::Merge for #layer_name {
            fn merge(self, other: Self) -> Self {
                Self {
                    #( #merges ),*
                }
            }
        }

        #[automatically_derived]
        impl ::confgr::core::Empty for #layer_name {
            fn empty() -> Self {
               Self {
                #( #empty_defs ),*
               }
            }
        }
    }
}