1use quote::quote_spanned;
2use syn::{parse_quote, punctuated::Punctuated, spanned::Spanned, GenericParam, Token};
3
4pub fn signature_to_function_call(sig: &syn::Signature) -> syn::Result<syn::ExprCall> {
6 let funcexpr = syn::ExprPath {
8 attrs: Vec::new(),
9 qself: None,
10 path: sig.ident.clone().into(),
11 };
12
13 let mut funcargs = Punctuated::new();
15 for item in &sig.inputs {
16 match item {
17 syn::FnArg::Receiver(recv) => {
18 let span = recv.self_token.span;
19 funcargs.push(syn::parse2(quote_spanned!(span=> self))?);
20 }
21 syn::FnArg::Typed(argty) => {
22 if let syn::Pat::Ident(ref id) = *argty.pat {
23 let argpath = syn::ExprPath {
24 attrs: Vec::new(),
25 qself: None,
26 path: id.ident.clone().into(),
27 };
28 funcargs.push(syn::Expr::Path(argpath));
29 } else {
30 return Err(syn::Error::new(argty.span(), "expected identifier"));
31 }
32 }
33 }
34 }
35
36 Ok(syn::ExprCall {
38 attrs: Vec::new(),
39 paren_token: syn::token::Paren::default(),
40 func: Box::new(funcexpr.into()),
41 args: funcargs,
42 })
43}
44
45pub fn signature_to_method_call(sig: &syn::Signature) -> syn::Result<syn::ExprMethodCall> {
47 let receiver = sig.receiver().unwrap();
49 let span = receiver.span();
50
51 let mut funcargs = Punctuated::new();
53 for item in &sig.inputs {
54 match item {
55 syn::FnArg::Receiver(_) => {}
56 syn::FnArg::Typed(argty) => {
57 if let syn::Pat::Ident(ref id) = *argty.pat {
58 let argpath = syn::ExprPath {
59 attrs: Vec::new(),
60 qself: None,
61 path: id.ident.clone().into(),
62 };
63 funcargs.push(syn::Expr::Path(argpath));
64 } else {
65 return Err(syn::Error::new(argty.span(), "expected identifier"));
66 }
67 }
68 }
69 }
70
71 Ok(syn::ExprMethodCall {
73 attrs: Vec::new(),
74 receiver: Box::new(syn::parse2(quote_spanned!(span=> self))?),
75 dot_token: syn::token::Dot {
76 spans: [sig.span()],
77 },
78 method: sig.ident.clone(),
79 turbofish: None,
80 paren_token: syn::token::Paren::default(),
81 args: funcargs,
82 })
83}
84
85pub fn prepend_function_path(call: &mut syn::ExprCall, module: syn::Path) -> syn::Result<()> {
87 if let syn::Expr::Path(ref mut path) = *call.func {
88 for (i, segment) in module.segments.into_iter().enumerate() {
89 path.path.segments.insert(i, segment);
90 }
91 Ok(())
92 } else {
93 Err(syn::Error::new(call.func.span(), "expected path"))
94 }
95}
96
97pub fn deref_expr(expr: syn::Expr) -> syn::Expr {
99 syn::Expr::Paren(syn::ExprParen {
100 attrs: Vec::new(),
101 paren_token: syn::token::Paren::default(),
102 expr: Box::new(syn::Expr::Unary(syn::ExprUnary {
103 attrs: Vec::new(),
104 op: syn::UnOp::Deref(parse_quote!(*)),
105 expr: Box::new(expr),
106 })),
107 })
108}
109
110pub fn trait_to_generic_ident(trait_: &syn::ItemTrait) -> syn::Ident {
116 let mut raw = trait_
117 .ident
118 .to_string()
119 .chars()
120 .filter(|c| c.is_uppercase())
121 .collect::<String>();
122 loop {
123 if !trait_.generics.params.iter().any(|g| match g {
124 syn::GenericParam::Type(param) if param.ident == raw => true,
125 syn::GenericParam::Const(param) if param.ident == raw => true,
126 _ => false,
127 }) {
128 break;
129 } else {
130 raw.push('_');
131 }
132 }
133
134 syn::Ident::new(&raw, trait_.ident.span())
135}
136
137pub fn generics_declaration_to_generics(
141 generics: &Punctuated<GenericParam, Token![,]>,
142) -> syn::Result<Punctuated<GenericParam, Token![,]>> {
143 generics
144 .iter()
145 .map(|gen| match gen {
146 syn::GenericParam::Type(t) => Ok(syn::GenericParam::Type(syn::TypeParam {
147 attrs: t.attrs.clone(),
148 ident: t.ident.clone(),
149 colon_token: None,
150 bounds: Punctuated::new(),
151 eq_token: None,
152 default: None,
153 })),
154 syn::GenericParam::Lifetime(l) => Ok(syn::GenericParam::Lifetime(syn::LifetimeParam {
155 attrs: l.attrs.clone(),
156 lifetime: l.lifetime.clone(),
157 colon_token: None,
158 bounds: Punctuated::new(),
159 })),
160 syn::GenericParam::Const(c) => {
161 Err(syn::Error::new(c.span(), "cannot handle const generics"))
162 }
163 })
164 .collect()
165}
166
167#[cfg(test)]
168mod tests {
169
170 use syn::parse_quote;
171
172 #[test]
173 fn prepend_function_path() {
174 let path = parse_quote!(crate::qualified::path);
175 let mut call = parse_quote!(myfunction(arg1, arg2));
176 super::prepend_function_path(&mut call, path).unwrap();
177 assert_eq!(
178 call,
179 parse_quote!(crate::qualified::path::myfunction(arg1, arg2))
180 );
181 }
182
183 #[test]
184 fn deref_expr() {
185 let expr = parse_quote!(self);
186 let dereffed = super::deref_expr(expr);
187 assert_eq!(dereffed, parse_quote!((*self)));
188 }
189
190 #[test]
191 fn trait_to_generic_ident() {
192 let trait_ = syn::parse_quote!(
193 trait Trait {}
194 );
195 let expected: syn::Ident = syn::parse_quote!(T);
196 assert_eq!(super::trait_to_generic_ident(&trait_), expected);
197
198 let trait_ = syn::parse_quote!(
199 trait SomeTrait {}
200 );
201 let expected: syn::Ident = syn::parse_quote!(ST);
202 assert_eq!(super::trait_to_generic_ident(&trait_), expected);
203
204 let trait_ = syn::parse_quote!(
205 trait Trait<T> {}
206 );
207 let expected: syn::Ident = syn::parse_quote!(T_);
208 assert_eq!(super::trait_to_generic_ident(&trait_), expected);
209 }
210}