jsonrpsee_proc_macros/
render_server.rs1use std::collections::HashSet;
28
29use super::RpcDescription;
30use crate::{
31 helpers::{generate_where_clause, is_option, may_borrow},
32 rpc_macro::RpcFnArg,
33};
34use proc_macro2::{Span, TokenStream as TokenStream2};
35use quote::{quote, quote_spanned};
36
37impl RpcDescription {
38 pub(super) fn render_server(&self) -> Result<TokenStream2, syn::Error> {
39 let trait_name = quote::format_ident!("{}Server", &self.trait_def.ident);
40 let generics = self.trait_def.generics.clone();
41 let (impl_generics, _, where_clause) = generics.split_for_impl();
42
43 let method_impls = self.render_methods()?;
44 let into_rpc_impl = self.render_into_rpc()?;
45
46 let doc_comment =
48 format!("Server trait implementation for the `{}` RPC API.", self.trait_def.ident);
49
50 let trait_impl = quote! {
51 #[doc = #doc_comment]
52 pub trait #trait_name #impl_generics: Sized + Send + Sync + 'static #where_clause {
53 #method_impls
54 #into_rpc_impl
55 }
56 };
57
58 Ok(trait_impl)
59 }
60
61 fn render_methods(&self) -> Result<TokenStream2, syn::Error> {
62 let methods = self.methods.iter().map(|method| {
63 let docs = &method.docs;
64 let mut method_sig = method.signature.clone();
65 desugar_async(&mut method_sig);
66
67 quote! {
68 #docs
69 #method_sig
70 }
71 });
72
73 let subscriptions = self.subscriptions.iter().map(|sub| {
74 let docs = &sub.docs;
75 let subscription_sink_ty = self.jrps_server_item(quote! { PendingSubscriptionSink });
76
77 let subscription_sink: syn::FnArg =
79 syn::parse_quote!(subscription_sink: #subscription_sink_ty);
80 let mut sub_sig = sub.signature.clone();
81 sub_sig.sig.inputs.insert(1, subscription_sink);
82 desugar_async(&mut sub_sig);
83
84 quote! {
85 #docs
86 #sub_sig
87 }
88 });
89
90 Ok(quote! {
91 #(#methods)*
92 #(#subscriptions)*
93 })
94 }
95
96 fn handle_register_result(&self, tokens: TokenStream2) -> TokenStream2 {
102 let reexports = self.jrps_server_item(quote! { core::__reexports });
103 quote! {{
104 let _res = #tokens;
105 #[cfg(debug_assertions)]
106 if _res.is_err() {
107 #reexports::panic_fail_register();
108 }
109 }}
110 }
111
112 fn render_into_rpc(&self) -> Result<TokenStream2, syn::Error> {
113 let rpc_module = self.jrps_server_item(quote! { RpcModule });
114
115 let mut registered = HashSet::new();
116 let mut errors = Vec::new();
117 let mut check_name = |name: &str, span: Span| {
118 if registered.contains(name) {
119 let message = format!("{name:?} is already defined");
120 errors.push(quote_spanned!(span => compile_error!(#message);));
121 } else {
122 registered.insert(name.to_string());
123 }
124 };
125
126 let methods = self
127 .methods
128 .iter()
129 .map(|method| {
130 let rust_method_name = &method.signature.sig.ident;
132 let rpc_method_name = self.rpc_identifier(&method.name);
134 let (parsing, params_seq) = self.render_params_decoding(&method.params, None);
139
140 let into_response = self.jrps_server_item(quote! { IntoResponse });
141
142 check_name(&rpc_method_name, rust_method_name.span());
143
144 if method.signature.sig.asyncness.is_some() {
145 self.handle_register_result(quote! {
146 rpc.register_async_method(#rpc_method_name, |params, context| async move {
147 #parsing
148 #into_response::into_response(context.as_ref().#rust_method_name(#params_seq).await)
149 })
150 })
151 } else if method.blocking {
152 self.handle_register_result(quote! {
153 rpc.register_blocking_method(#rpc_method_name, |params, context| {
154 #parsing
155 #into_response::into_response(context.#rust_method_name(#params_seq))
156 })
157 })
158 } else {
159 self.handle_register_result(quote! {
160 rpc.register_method(#rpc_method_name, |params, context| {
161 #parsing
162 #into_response::into_response(context.#rust_method_name(#params_seq))
163 })
164 })
165 }
166 })
167 .collect::<Vec<_>>();
168
169 let subscriptions = self
170 .subscriptions
171 .iter()
172 .map(|sub| {
173 let rust_method_name = &sub.signature.sig.ident;
175 let rpc_sub_name = self.rpc_identifier(&sub.name);
177 let rpc_notif_name_override = sub.notif_name_override.as_ref().map(|m| self.rpc_identifier(m));
179 let rpc_unsub_name = self.rpc_identifier(&sub.unsubscribe);
181 let pending = proc_macro2::Ident::new("pending", rust_method_name.span());
185 let (parsing, params_seq) = self.render_params_decoding(&sub.params, Some(pending));
186 let sub_err = self.jrps_server_item(quote! { SubscriptionCloseResponse });
187 let into_sub_response = self.jrps_server_item(quote! { IntoSubscriptionCloseResponse });
188
189 check_name(&rpc_sub_name, rust_method_name.span());
190 check_name(&rpc_unsub_name, rust_method_name.span());
191
192 let rpc_notif_name = match rpc_notif_name_override {
193 Some(notif) => {
194 check_name(¬if, rust_method_name.span());
195 notif
196 }
197 None => rpc_sub_name.clone(),
198 };
199
200 if sub.signature.sig.asyncness.is_some() {
201 self.handle_register_result(quote! {
202 rpc.register_subscription(#rpc_sub_name, #rpc_notif_name, #rpc_unsub_name, |params, mut pending, context| async move {
203 #parsing
204 #into_sub_response::into_response(context.as_ref().#rust_method_name(pending, #params_seq).await)
205 })
206 })
207 } else {
208 self.handle_register_result(quote! {
209 rpc.register_subscription_raw(#rpc_sub_name, #rpc_notif_name, #rpc_unsub_name, |params, mut pending, context| {
210 #parsing
211 let _ = context.as_ref().#rust_method_name(pending, #params_seq);
212 #sub_err::None
213 })
214 })
215 }
216 })
217 .collect::<Vec<_>>();
218
219 let method_aliases = self
220 .methods
221 .iter()
222 .map(|method| {
223 let rpc_name = self.rpc_identifier(&method.name);
224 let rust_method_name = &method.signature.sig.ident;
225
226 let aliases: Vec<TokenStream2> = method
228 .aliases
229 .iter()
230 .map(|alias| {
231 check_name(alias, rust_method_name.span());
232 self.handle_register_result(quote! {
233 rpc.register_alias(#alias, #rpc_name)
234 })
235 })
236 .collect();
237
238 quote!( #(#aliases)* )
239 })
240 .collect::<Vec<_>>();
241
242 let subscription_aliases = self
243 .subscriptions
244 .iter()
245 .map(|method| {
246 let sub_name = self.rpc_identifier(&method.name);
247 let unsub_name = self.rpc_identifier(&method.unsubscribe);
248 let rust_method_name = &method.signature.sig.ident;
249
250 let sub: Vec<TokenStream2> = method
251 .aliases
252 .iter()
253 .map(|alias| {
254 check_name(alias, rust_method_name.span());
255 self.handle_register_result(quote! {
256 rpc.register_alias(#alias, #sub_name)
257 })
258 })
259 .collect();
260 let unsub: Vec<TokenStream2> = method
261 .unsubscribe_aliases
262 .iter()
263 .map(|alias| {
264 check_name(alias, rust_method_name.span());
265 self.handle_register_result(quote! {
266 rpc.register_alias(#alias, #unsub_name)
267 })
268 })
269 .collect();
270
271 quote! (
272 #(#sub)*
273 #(#unsub)*
274 )
275 })
276 .collect::<Vec<_>>();
277
278 let doc_comment = "Collects all the methods and subscriptions defined in the trait \
279 and adds them into a single `RpcModule`.";
280
281 let sub_tys: Vec<syn::Type> =
282 self.subscriptions.clone().into_iter().map(|s| s.item).collect();
283 let where_clause =
284 generate_where_clause(&self.trait_def, &sub_tys, self.server_bounds.as_ref());
285
286 Ok(quote! {
288 #[doc = #doc_comment]
289 fn into_rpc(self) -> #rpc_module<Self> where #(#where_clause,)* {
290 let mut rpc = #rpc_module::new(self);
291
292 #(#errors)*
293 #(#methods)*
294 #(#subscriptions)*
295 #(#method_aliases)*
296 #(#subscription_aliases)*
297
298 rpc
299 }
300 })
301 }
302
303 fn render_params_decoding(
304 &self,
305 params: &[RpcFnArg],
306 sub: Option<proc_macro2::Ident>,
307 ) -> (TokenStream2, TokenStream2) {
308 if params.is_empty() {
309 return (TokenStream2::default(), TokenStream2::default());
310 }
311
312 let params_fields_seq = params.iter().map(RpcFnArg::arg_pat);
313 let params_fields = quote! { #(#params_fields_seq),* };
314
315 let reexports = self.jrps_server_item(quote! { core::__reexports });
316
317 let error_ret = if let Some(pending) = &sub {
318 let tokio = quote! { #reexports::tokio };
319 let sub_err = self.jrps_server_item(quote! { SubscriptionCloseResponse });
320 quote! {
321 #tokio::spawn(#pending.reject(e));
322 return #sub_err::None;
323 }
324 } else {
325 let response_payload = self.jrps_server_item(quote! { ResponsePayload });
326 quote! {
327 return #response_payload::error(e);
328 }
329 };
330
331 let decode_array = {
333 let decode_fields = params.iter().map(|RpcFnArg { arg_pat, ty, .. }| {
334 let is_option = is_option(ty);
335 let next_method = if is_option { quote!(optional_next) } else { quote!(next) };
336 quote! {
337 let #arg_pat: #ty = match seq.#next_method() {
338 Ok(v) => v,
339 Err(e) => {
340 #reexports::log_fail_parse(stringify!(#arg_pat), stringify!(#ty), &e, #is_option);
341 #error_ret
342 }
343 };
344 }
345 });
346
347 let free_params = (!params.iter().any(|arg| may_borrow(&arg.ty)))
351 .then(|| quote! { let params = params; });
352
353 quote! {
354 #free_params
355 let mut seq = params.sequence();
356 #(#decode_fields);*
357 (#params_fields)
358 }
359 };
360
361 let parsing = quote! {
363 let (#params_fields) = {
364 #decode_array
365 };
366 };
367
368 (parsing, params_fields)
369 }
370}
371
372fn desugar_async(method: &mut syn::TraitItemFn) {
377 let sig = &mut method.sig;
378 if sig.asyncness.take().is_none() {
379 return;
380 }
381 let output = match &sig.output {
382 syn::ReturnType::Default => quote! { () },
383 syn::ReturnType::Type(_, ty) => quote! { #ty },
384 };
385 sig.output = syn::parse_quote! {
386 -> impl ::core::future::Future<Output = #output> + ::core::marker::Send
387 };
388 if let Some(body) = &mut method.default {
390 *body = syn::parse_quote!({ async move #body });
391 }
392}