1#![recursion_limit = "2048"]
2
3extern crate proc_macro;
4
5use proc_macro::TokenStream;
6use proc_macro2::Span;
7use quote::quote;
8
9use syn::*;
10
11struct CustomOuterAttrs(Vec<Attribute>);
12
13impl parse::Parse for CustomOuterAttrs {
14 fn parse(input: parse::ParseStream) -> Result<Self> {
15 Ok(CustomOuterAttrs(input.call(Attribute::parse_outer)?))
16 }
17}
18
19#[proc_macro_attribute]
20pub fn jsonrpc_v2_method(attrs: TokenStream, item: TokenStream) -> TokenStream {
21 let method = parse_macro_input!(item as ItemFn);
22
23 let method_ident = &method.sig.ident;
24
25 let attrs = parse_macro_input!(attrs as AttributeArgs);
26
27 let params = &method
28 .sig
29 .inputs
30 .iter()
31 .filter_map(|x| match *x {
32 FnArg::Typed(ref y) => Some(y),
33 _ => None
34 })
35 .filter_map(|x| match *x.pat {
36 Pat::Ident(ref y) => Some(y),
37 _ => None
38 })
39 .map(|x| &x.ident)
40 .collect::<Vec<_>>();
41
42 let mut wrapped_fn_ident = None;
43 let wrapped_fn_path: Path = parse_quote!(wrapped_fn);
44 let externify_path: Path = parse_quote!(externify);
45
46 if let Some(wrapped_fn_name_lit) = attrs
47 .iter()
48 .filter_map(|x| match x {
49 NestedMeta::Meta(y) => Some(y),
50 _ => None
51 })
52 .filter_map(|x| match x {
53 Meta::NameValue(y) => Some(y),
54 _ => None
55 })
56 .find(|x| &x.path == &wrapped_fn_path)
57 .and_then(|x| match x.lit {
58 Lit::Str(ref y) => Some(y),
59 _ => None
60 })
61 {
62 wrapped_fn_ident = Some(Ident::new(&wrapped_fn_name_lit.value(), Span::call_site()));
63 }
64
65 let externify = attrs
66 .iter()
67 .filter_map(|x| match x {
68 NestedMeta::Meta(y) => Some(y),
69 _ => None
70 })
71 .filter_map(|x| match x {
72 Meta::NameValue(y) => Some(y),
73 _ => None
74 })
75 .find(|x| &x.path == &externify_path)
76 .map(|x| match x.lit {
77 Lit::Bool(ref y) => y.value,
78 _ => false
79 }).unwrap_or(false);
80
81 let mut method_as_outer = quote!();
82
83 let wrapped_fn = {
84
85 let ItemFn { sig: Signature { inputs, output, .. }, .. } = parse_quote! {
86 fn fn__(jsonrpc_v2::Params(params): jsonrpc_v2::Params<Option<jsonrpc_v2::exp::serde_json::Value>>)
87 -> std::pin::Pin<Box<dyn std::future::Future<Output=Result<jsonrpc_v2::exp::serde_json::Value, jsonrpc_v2::Error>> + Send>> {}
88 };
89
90 let mut wrapped_fn = method.clone();
91 wrapped_fn.sig.asyncness = None;
92 wrapped_fn.sig.inputs = inputs;
93 wrapped_fn.sig.output = output;
94
95 if externify {
96
97 let mut no_mangle: CustomOuterAttrs = parse_quote!(#[no_mangle]);
98
99 wrapped_fn.attrs.append(&mut no_mangle.0);
100
101 wrapped_fn.vis = parse_quote!(pub);
102 wrapped_fn.sig.abi = Some(parse_quote!(extern));
103 }
104
105 let mut method_as_inner = quote!();
106 let mut method_call_ident = method_ident.clone();
107
108 if let Some(wrapped_fn_ident) = wrapped_fn_ident {
109 wrapped_fn.sig.ident = wrapped_fn_ident;
110 method_as_outer = quote!(#method);
111 } else {
112 let jsonrpc_v2_inner_ident = Ident::new("jsonrpc_v2_inner", Span::call_site());
113 method_as_inner = {
114 let mut method = method.clone();
115 method.sig.ident = jsonrpc_v2_inner_ident.clone();
116 quote!(#method)
117 };
118 method_call_ident = jsonrpc_v2_inner_ident.clone();
119 }
120
121 let inner_call = quote!(#method_call_ident(#(#params),*).await?);
122
123 let block: Block = if params.is_empty() {
124 parse_quote!{{
125 #method_as_inner
126 Box::pin(async move {
127 if params.as_ref()
128 .map(|x| x.as_object().map(|y| !y.is_empty()).unwrap_or(false) ||
129 x.as_array().map(|y| !y.is_empty()).unwrap_or(false) )
130 .unwrap_or(false) {
131 Err(jsonrpc_v2::Error::INVALID_PARAMS)
132 } else {
133 let res = #inner_call;
134 let val = jsonrpc_v2::exp::serde_json::to_value(res)?;
135 Ok(val)
136 }
137 })
138 }}
139 } else {
140 let extract_positional = extract_positional(params.len());
141 let extract_named = extract_named(params.len());
142
143 let param_names = ¶ms
144 .iter()
145 .map(|id| id.to_string() )
146 .collect::<Vec<_>>();
147
148 parse_quote!{{
149 #method_as_inner
150
151 Box::pin(async move {
152 match params {
153 Some(jsonrpc_v2::exp::serde_json::Value::Object(map)) => {
154 #extract_named
155 if let Ok((#(#params),*)) = extract(map, #(#param_names),*) {
156 let res = #inner_call;
157 let val = jsonrpc_v2::exp::serde_json::to_value(res)?;
158 return Ok(val);
159 }
160 },
161 Some(jsonrpc_v2::exp::serde_json::Value::Array(vals)) => {
162 #extract_positional
163 if let Ok((#(#params),*)) = extract(vals) {
164 let res = #inner_call;
165 let val = jsonrpc_v2::exp::serde_json::to_value(res)?;
166 return Ok(val);
167 }
168 },
169 _ => {}
170 }
171 Err(jsonrpc_v2::Error::INVALID_PARAMS)
172 })
173 }}
174 };
175
176 wrapped_fn.block = Box::new(block);
177
178 wrapped_fn
179 };
180
181 let out = quote! {
182 #method_as_outer
183 #wrapped_fn
184 };
185
186 out.into()
189}
190
191fn extract_positional(up_to: usize) -> proc_macro2::TokenStream {
192 let tys =
193 (0..up_to).map(|i| Ident::new(&format!("T{}", i), Span::call_site())).collect::<Vec<_>>();
194 let gen = tys
195 .iter()
196 .map(|x| quote!(#x: jsonrpc_v2::exp::serde::de::DeserializeOwned))
197 .collect::<Vec<_>>();
198
199 let ts =
200 (0..up_to).map(|i| Ident::new(&format!("t{}", i), Span::call_site())).collect::<Vec<_>>();
201
202 let mut ts_rev = ts.clone();
203 ts_rev.reverse();
204
205 let exprs = (0..up_to)
206 .map(|_| quote!(jsonrpc_v2::exp::serde_json::from_value(vals.pop().unwrap()).map_err(|_| ())?))
207 .collect::<Vec<_>>();
208
209 quote! {
210 fn extract<#(#gen),*>(mut vals: Vec<jsonrpc_v2::exp::serde_json::Value>) -> Result<(#(#tys),*), ()> {
211 if vals.len() != #up_to {
212 return Err(());
213 }
214 let (#(#ts_rev),*) = (#(#exprs),*);
215 Ok((#(#ts),*))
216 }
217 }
218}
219
220fn extract_named(up_to: usize) -> proc_macro2::TokenStream {
221 let tys =
222 (0..up_to).map(|i| Ident::new(&format!("T{}", i), Span::call_site())).collect::<Vec<_>>();
223 let gen = tys
224 .iter()
225 .map(|x| quote!(#x: jsonrpc_v2::exp::serde::de::DeserializeOwned))
226 .collect::<Vec<_>>();
227
228 let ts =
229 (0..up_to).map(|i| Ident::new(&format!("t{}", i), Span::call_site())).collect::<Vec<_>>();
230
231 let names =
232 (0..up_to).map(|i| Ident::new(&format!("n{}", i), Span::call_site())).collect::<Vec<_>>();
233
234 let names_and_tys = names.iter().map(|x| quote!(#x: &'static str)).collect::<Vec<_>>();
235
236 let mains = ts
237 .iter()
238 .zip(names.iter())
239 .map(|(t, n)| {
240 quote! {
241 let #t = if let Some(val) = map.remove(#n) {
242 jsonrpc_v2::exp::serde_json::from_value(val).map_err(|_| ())?
243 } else {
244 return Err(());
245 };
246 }
247 })
248 .collect::<Vec<_>>();
249
250 quote! {
251 fn extract<#(#gen),*>(mut map: jsonrpc_v2::exp::serde_json::Map<String, jsonrpc_v2::exp::serde_json::Value>, #(#names_and_tys),*)
252 -> Result<(#(#tys),*), ()> {
253 #(#mains)*
254 Ok((#(#ts),*))
255 }
256 }
257}