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| ¶m.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