use crate::utils::{ add_where_clauses_for_new_ident, AttrParams, MultiFieldData, State, }; use proc_macro2::{Span, TokenStream}; use quote::quote; use syn::{parse::Result, DeriveInput, Ident}; pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result { let as_ref_type = &Ident::new("__AsRefT", Span::call_site()); let state = State::with_type_bound( input, trait_name, quote!(::core::convert), String::from("as_ref"), AttrParams::ignore_and_forward(), false, )?; let MultiFieldData { fields, input_type, members, infos, trait_path, impl_generics, ty_generics, where_clause, .. } = state.enabled_fields_data(); let sub_items: Vec<_> = infos .iter() .zip(members.iter()) .zip(fields) .map(|((info, member), field)| { let field_type = &field.ty; if info.forward { let trait_path = quote!(#trait_path<#as_ref_type>); let type_where_clauses = quote! { where #field_type: #trait_path }; let new_generics = add_where_clauses_for_new_ident( &input.generics, &[field], as_ref_type, type_where_clauses, false, ); let (impl_generics, _, where_clause) = new_generics.split_for_impl(); let casted_trait = quote!(<#field_type as #trait_path>); ( quote!(#casted_trait::as_ref(&#member)), quote!(#impl_generics), quote!(#where_clause), quote!(#trait_path), quote!(#as_ref_type), ) } else { ( quote!(&#member), quote!(#impl_generics), quote!(#where_clause), quote!(#trait_path<#field_type>), quote!(#field_type), ) } }) .collect(); let bodies = sub_items.iter().map(|i| &i.0); let impl_generics = sub_items.iter().map(|i| &i.1); let where_clauses = sub_items.iter().map(|i| &i.2); let trait_paths = sub_items.iter().map(|i| &i.3); let return_types = sub_items.iter().map(|i| &i.4); Ok(quote! {#( impl#impl_generics #trait_paths for #input_type#ty_generics #where_clauses { #[inline] fn as_ref(&self) -> &#return_types { #bodies } } )*}) }