auto-delegate-impl 0.1.2

Auto delegate allows you that automatic impl of traits and delegate their handling to child members.
Documentation
use proc_macro2::Ident;
use syn::{Attribute, Fields, Generics, ItemStruct, Type};
use syn::__private::TokenStream2;
use syn::Fields::Unnamed;

use crate::attribute::{find_to_attribute, syn_error_not_found_fields, syn_error_not_found_trait_names, trait_names};
use crate::delegatable::delegatable_ident_with_generics;
use crate::derive::by_fields::{ByField, ByFields};

pub fn try_expand_derive_delegate_struct(item_struct: ItemStruct) -> syn::Result<proc_macro2::TokenStream> {
    let to_attr = find_to_attribute(&item_struct.attrs);

    if let Some(to_attr) = to_attr {
        impl_macro_markers_with_new_type(&item_struct, &to_attr)
    } else {
        impl_macro_markers_with_named_fields(item_struct)
    }
}


fn impl_macro_markers_with_new_type(
    item: &ItemStruct,
    to_attr: &Attribute,
) -> syn::Result<TokenStream2> {
    let trait_names = trait_names(to_attr)
        .ok_or(syn_error_not_found_trait_names())?;

    let delegate_field_name = quote::quote!(0);
    let delegate_field_ty = parse_new_type_ty(item.fields.clone())
        .ok_or(syn_error_not_found_fields())?;

    Ok(
        impl_delegatable(
            &item.ident,
            &delegate_field_name,
            &delegate_field_ty,
            &trait_names,
            &item.generics,
        )
    )
}


fn parse_new_type_ty(
    fields: Fields
) -> Option<Type> {
    if let Unnamed(un_named) = fields {
        Some(un_named
            .unnamed
            .first()?
            .ty
            .clone()
        )
    } else {
        None
    }
}


fn impl_macro_markers_with_named_fields(item_struct: ItemStruct) -> syn::Result<TokenStream2> {
    let struct_name = &item_struct.ident;

    let expand_impl_methods = ByFields::new(item_struct.fields)
        .map(|by_field| impl_delegatable_with_fields(struct_name, by_field, &item_struct.generics));

    Ok(quote::quote! {
        #(#expand_impl_methods)*
    })
}


fn impl_delegatable_with_fields(
    struct_name: &Ident,
    by_field: ByField,
    generics: &Generics,
) -> proc_macro2::TokenStream {
    impl_delegatable(
        struct_name,
        by_field.field_name_ref(),
        by_field.field_ty_ref(),
        by_field.trait_names_ref(),
        generics,
    )
}


fn impl_delegatable(
    struct_name: &Ident,
    delegate_field_name: &TokenStream2,
    delegate_filed_ty: &Type,
    trait_names: &[Ident],
    generics: &Generics,
)
    -> TokenStream2 {
    let (_, type_params, _) = &generics.split_for_impl();
    let where_bound = generics.where_clause.as_ref();

    let expand = trait_names
        .iter()
        .map(|trait_name| {
            let delegatable_ident = delegatable_ident_with_generics(trait_name.clone());

            quote::quote! {
                impl #generics #delegatable_ident for #struct_name #type_params #where_bound{
                    type A = #delegate_filed_ty;
                    type B = #delegate_filed_ty;
                    type C = #delegate_filed_ty;
                    type D = #delegate_filed_ty;
                    type E = #delegate_filed_ty;
                    type F = #delegate_filed_ty;
                    type G = #delegate_filed_ty;
                    type H = #delegate_filed_ty;
                    type I = #delegate_filed_ty;
                    type J = #delegate_filed_ty;
                    type K = #delegate_filed_ty;
                    type L = #delegate_filed_ty;

                    #[inline(always)]
                    fn delegate_by_owned(self) -> auto_delegate::Delegates<Self::A, Self::B, Self::C, Self::D, Self::E, Self::F, Self::G, Self::H, Self::I, Self::J, Self::K, Self::L>{
                        auto_delegate::Delegates(Some(self.#delegate_field_name), None, None, None, None, None, None, None, None, None, None, None)
                    }

                    #[inline(always)]
                    fn delegate_by_ref(&self) -> auto_delegate::Delegates<&Self::A, &Self::B, &Self::C, &Self::D, &Self::E, &Self::F, &Self::G, &Self::H, &Self::I, &Self::J, &Self::K, &Self::L>{
                        auto_delegate::Delegates(Some(&self.#delegate_field_name), None, None, None, None, None, None, None, None, None, None, None)
                    }

                    #[inline(always)]
                    fn delegate_by_mut(&mut self) -> auto_delegate::Delegates<&mut Self::A, &mut Self::B, &mut Self::C, &mut Self::D, &mut Self::E, &mut Self::F, &mut Self::G, &mut Self::H, &mut Self::I, &mut Self::J, &mut Self::K, &mut Self::L>{
                        auto_delegate::Delegates(Some(&mut self.#delegate_field_name), None, None, None, None, None, None, None, None, None, None, None)
                    }
                }
            }
        });

    quote::quote!(#(#expand)*)
}