1 | use crate::utils::{ |
2 | add_where_clauses_for_new_ident, AttrParams, MultiFieldData, State, |
3 | }; |
4 | use proc_macro2::{Span, TokenStream}; |
5 | use quote::quote; |
6 | use syn::{parse::Result, DeriveInput, Ident}; |
7 | |
8 | pub fn expand(input: &DeriveInput, trait_name: &'static str) -> Result<TokenStream> { |
9 | let as_ref_type = &Ident::new("__AsRefT" , Span::call_site()); |
10 | let state = State::with_type_bound( |
11 | input, |
12 | trait_name, |
13 | quote!(::core::convert), |
14 | String::from("as_ref" ), |
15 | AttrParams::ignore_and_forward(), |
16 | false, |
17 | )?; |
18 | let MultiFieldData { |
19 | fields, |
20 | input_type, |
21 | members, |
22 | infos, |
23 | trait_path, |
24 | impl_generics, |
25 | ty_generics, |
26 | where_clause, |
27 | .. |
28 | } = state.enabled_fields_data(); |
29 | let sub_items: Vec<_> = infos |
30 | .iter() |
31 | .zip(members.iter()) |
32 | .zip(fields) |
33 | .map(|((info, member), field)| { |
34 | let field_type = &field.ty; |
35 | if info.forward { |
36 | let trait_path = quote!(#trait_path<#as_ref_type>); |
37 | let type_where_clauses = quote! { |
38 | where #field_type: #trait_path |
39 | }; |
40 | let new_generics = add_where_clauses_for_new_ident( |
41 | &input.generics, |
42 | &[field], |
43 | as_ref_type, |
44 | type_where_clauses, |
45 | false, |
46 | ); |
47 | let (impl_generics, _, where_clause) = new_generics.split_for_impl(); |
48 | let casted_trait = quote!(<#field_type as #trait_path>); |
49 | ( |
50 | quote!(#casted_trait::as_ref(&#member)), |
51 | quote!(#impl_generics), |
52 | quote!(#where_clause), |
53 | quote!(#trait_path), |
54 | quote!(#as_ref_type), |
55 | ) |
56 | } else { |
57 | ( |
58 | quote!(&#member), |
59 | quote!(#impl_generics), |
60 | quote!(#where_clause), |
61 | quote!(#trait_path<#field_type>), |
62 | quote!(#field_type), |
63 | ) |
64 | } |
65 | }) |
66 | .collect(); |
67 | let bodies = sub_items.iter().map(|i| &i.0); |
68 | let impl_generics = sub_items.iter().map(|i| &i.1); |
69 | let where_clauses = sub_items.iter().map(|i| &i.2); |
70 | let trait_paths = sub_items.iter().map(|i| &i.3); |
71 | let return_types = sub_items.iter().map(|i| &i.4); |
72 | |
73 | Ok(quote! {#( |
74 | impl#impl_generics #trait_paths for #input_type#ty_generics |
75 | #where_clauses |
76 | { |
77 | #[inline] |
78 | fn as_ref(&self) -> &#return_types { |
79 | #bodies |
80 | } |
81 | } |
82 | )*}) |
83 | } |
84 | |