1 use crate::default_methods;
2 use crate::parse::TraitImpl;
3 use crate::visibility::Visibility;
4 use proc_macro2::{Span, TokenStream};
5 use quote::quote;
6 use syn::{Attribute, FnArg, Ident, ImplItem, Signature};
7 
inherent(vis: Visibility, mut input: TraitImpl) -> TokenStream8 pub fn inherent(vis: Visibility, mut input: TraitImpl) -> TokenStream {
9     let generics = &input.generics;
10     let where_clause = &input.generics.where_clause;
11     let trait_ = &input.trait_;
12     let ty = &input.self_ty;
13 
14     let fwd_method = |attrs: &[Attribute], sig: &Signature| {
15         let constness = &sig.constness;
16         let asyncness = &sig.asyncness;
17         let unsafety = &sig.unsafety;
18         let abi = &sig.abi;
19         let ident = &sig.ident;
20         let generics = &sig.generics;
21         let output = &sig.output;
22         let where_clause = &sig.generics.where_clause;
23 
24         let (arg_pat, arg_val): (Vec<_>, Vec<_>) = sig
25             .inputs
26             .iter()
27             .enumerate()
28             .map(|(i, input)| match input {
29                 FnArg::Receiver(receiver) => {
30                     if receiver.reference.is_some() {
31                         (quote!(#receiver), quote!(self))
32                     } else {
33                         (quote!(self), quote!(self))
34                     }
35                 }
36                 FnArg::Typed(arg) => {
37                     let var = Ident::new(&format!("__arg{}", i), Span::call_site());
38                     let ty = &arg.ty;
39                     (quote!(#var: #ty), quote!(#var))
40                 }
41             })
42             .unzip();
43 
44         let types = generics.type_params().map(|param| &param.ident);
45 
46         let has_doc = attrs.iter().any(|attr| attr.path.is_ident("doc"));
47         let default_doc = if has_doc {
48             None
49         } else {
50             let mut link = String::new();
51             for segment in &trait_.segments {
52                 link += &segment.ident.to_string();
53                 link += "::";
54             }
55             let msg = format!("See [`{}{}`]", link, ident);
56             Some(quote!(#[doc = #msg]))
57         };
58 
59         quote! {
60             #(#attrs)*
61             #default_doc
62             #vis #constness #asyncness #unsafety #abi fn #ident #generics (
63                 #(#arg_pat,)*
64             ) #output #where_clause {
65                 <Self as #trait_>::#ident::<#(#types,)*>(#(#arg_val,)*)
66             }
67         }
68     };
69 
70     let mut errors = Vec::new();
71     let fwd_methods: Vec<_> = input
72         .items
73         .iter()
74         .flat_map(|item| match item {
75             ImplItem::Method(method) => vec![fwd_method(&method.attrs, &method.sig)],
76             ImplItem::Macro(item) if item.mac.path.is_ident("default") => {
77                 match item.mac.parse_body_with(default_methods::parse) {
78                     Ok(body) => body
79                         .into_iter()
80                         .map(|item| fwd_method(&item.attrs, &item.sig))
81                         .collect(),
82                     Err(e) => {
83                         errors.push(e.to_compile_error());
84                         Vec::new()
85                     }
86                 }
87             }
88             _ => Vec::new(),
89         })
90         .collect();
91 
92     input.items.retain(|item| match item {
93         ImplItem::Macro(item) if item.mac.path.is_ident("default") => false,
94         _ => true,
95     });
96 
97     quote! {
98         #(#errors)*
99 
100         impl #generics #ty #where_clause {
101             #(#fwd_methods)*
102         }
103 
104         #input
105     }
106 }
107