Source code

Revision control

Copy as Markdown

Other Tools

use crate::utils::{
add_where_clauses_for_new_ident, AttrParams, MultiFieldData, State,
};
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use syn::{parse::Result, DeriveInput};
pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result<TokenStream> {
let as_ref_type = format_ident!("__AsRefT");
let state = State::with_type_bound(
input,
trait_name,
"as_ref".into(),
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! {#(
#[automatically_derived]
impl #impl_generics #trait_paths for #input_type #ty_generics #where_clauses {
#[inline]
fn as_ref(&self) -> &#return_types {
#bodies
}
}
)*})
}