1use std::iter;
2
3use darling::{ast, util, FromDeriveInput, FromField, FromMeta};
4use proc_macro2::TokenStream;
5use quote::{quote, ToTokens};
6use syn::{
7 ext::IdentExt as _,
8 parse::{Parse, ParseStream},
9 parse_macro_input, parse_quote,
10 punctuated::Punctuated,
11 DeriveInput, Ident, Token,
12};
13
14#[proc_macro_derive(DeserializePositional, attributes(jsonrpc))]
15pub fn deserialize_positional(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
16 let item = parse_macro_input!(item as DeriveInput);
17 expand_deserialize_positional(item)
18 .unwrap_or_else(syn::Error::into_compile_error)
19 .into()
20}
21
22#[proc_macro_derive(SerializePositional, attributes(jsonrpc))]
23pub fn serialize_positional(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
24 let item = parse_macro_input!(item as DeriveInput);
25 expand_serialize_positional(item)
26 .unwrap_or_else(syn::Error::into_compile_error)
27 .into()
28}
29
30#[proc_macro_derive(DeserializeNamed, attributes(jsonrpc))]
31pub fn deserialize_named(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
32 let item = parse_macro_input!(item as DeriveInput);
33 expand_deserialize_named(item)
34 .unwrap_or_else(syn::Error::into_compile_error)
35 .into()
36}
37
38#[proc_macro_derive(SerializeNamed, attributes(jsonrpc))]
39pub fn serialize_named(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
40 let item = parse_macro_input!(item as DeriveInput);
41 expand_serialize_named(item)
42 .unwrap_or_else(syn::Error::into_compile_error)
43 .into()
44}
45
46fn expand_serialize_named(item: DeriveInput) -> syn::Result<TokenStream> {
47 let Strukt {
48 ident,
49 fields,
50 krate,
51 ..
52 } = Strukt::new(&item)?;
53 let Exports {
54 SerializeNamed,
55 SerializeMap,
56 Result,
57 ..
58 } = Exports::new(krate);
59 let ser_fields = fields.iter().map(|Field { ident, rename, .. }| {
60 let name = rename.clone().unwrap_or(ident.unraw().to_string());
61 quote! {serializer.serialize_entry(&#name, &self.#ident)?;}
62 });
63 Ok(quote! {
64 const _: () = {
65 impl #SerializeNamed for #ident {
66 fn ser_named<S: #SerializeMap>(&self, mut serializer: S) -> #Result<S::Ok, S::Error> {
67 #(#ser_fields)*
68 serializer.end()
69 }
70 }
71 };
72 })
73}
74
75fn expand_deserialize_named(item: DeriveInput) -> syn::Result<TokenStream> {
76 let Strukt {
77 ident,
78 fields,
79 deny_unknown_fields,
80 krate,
81 } = Strukt::new(&item)?;
82 let Exports {
83 DeserializeNamed,
84 MapAccess,
85 Deserialize,
86 MapAccessDeserializer,
87 Result,
88 serde,
89 ..
90 } = Exports::new(krate);
91 let shim = syn::Ident::new(&format!("_{}", ident.unraw()), ident.span());
92 let deny_unknown_fields = deny_unknown_fields.then_some(quote! {#[serde(deny_unknown_fields)]});
93 let fields = fields.iter().map(
94 |Field {
95 ident,
96 ty,
97 rename,
98 default,
99 }| {
100 let default = default.then_some(quote! {#[serde(default)]});
101 let rename = rename.as_ref().map(|it| quote! {#[serde(rename = #it)]});
102 quote! {
103 #default
104 #rename
105 #ident: #ty,
106 }
107 },
108 );
109 let remote = ident.to_string();
110 let serde = serde.to_string();
111 Ok(quote! {
112 const _: () = {
113 impl<'de> #DeserializeNamed<'de> for #ident {
114 fn de_named<D: #MapAccess<'de>>(deserializer: D) -> #Result<Self, D::Error> {
115 #[derive(#Deserialize)]
116 #[serde(remote = #remote, crate = #serde)]
117 #deny_unknown_fields
118 struct #shim {
119 #(#fields)*
120 }
121 #shim::deserialize(#MapAccessDeserializer::new(deserializer))
122 }
123 }
124 };
125 })
126}
127
128fn expand_deserialize_positional(item: DeriveInput) -> syn::Result<TokenStream> {
129 let Strukt {
130 ident,
131 fields,
132 deny_unknown_fields,
133 krate,
134 } = Strukt::new(&item)?;
135 for ((ix, l), r) in iter::zip(fields.iter().enumerate(), fields.iter().skip(1)) {
136 if l.default && !r.default {
137 return Err(syn::Error::new(
138 fields[ix].ident.span(),
139 "#[default] fields must follow other fields",
140 ));
141 }
142 }
143 let Exports {
144 DeserializePositional,
145 de_Error,
146 IgnoredAny,
147 SeqAccess,
148 Result,
149 Err_,
150 None_,
151 Ok_,
152 ..
153 } = Exports::new(krate);
154 let field_ctors = fields.iter().enumerate().map(
155 |(
156 ix,
157 Field {
158 ident, ty, default, ..
159 },
160 )| {
161 let missing_required_parameter = format!("missing required parameter at index {ix}");
162 match default {
163 false => quote! {
164 #ident: deserializer.next_element::<#ty>()?
165 .ok_or_else(|| #de_Error::custom(#missing_required_parameter))?,
166 },
167 true => quote! {
168 #ident: deserializer.next_element::<#ty>()?.unwrap_or_default(),
169 },
170 }
171 },
172 );
173 let deny_unknown_fields = deny_unknown_fields.then_some(quote! {
174 let #Ok_(#None_) = deserializer.next_element::<#IgnoredAny>() else {
175 return #Err_(
176 #de_Error::custom("unknown trailing arguments")
177 );
178 };
179 });
180 Ok(quote! {
181 const _: () = {
182 impl<'de> #DeserializePositional<'de> for #ident {
183 fn de_positional<D: #SeqAccess<'de>>(mut deserializer: D) -> #Result<Self, D::Error> {
184 let this = Self {
185 #(#field_ctors)*
186 };
187 #deny_unknown_fields;
188 #Ok_(this)
189 }
190 }
191 };
192 })
193}
194
195fn expand_serialize_positional(item: DeriveInput) -> syn::Result<TokenStream> {
196 let Strukt {
197 ident,
198 krate,
199 fields,
200 ..
201 } = Strukt::new(&item)?;
202 let Exports {
203 SerializePositional,
204 SerializeSeq,
205 Result,
206 ..
207 } = Exports::new(krate);
208 let ser_fields = fields
209 .iter()
210 .map(|Field { ident, .. }| quote! { serializer.serialize_element(&self.#ident)?; });
211
212 Ok(quote! {
213 const _: () = {
214 impl #SerializePositional for #ident {
215 fn ser_positional<S: #SerializeSeq>(&self, mut serializer: S) -> #Result<S::Ok, S::Error> {
216 #(#ser_fields)*
217 serializer.end()
218 }
219 }
220 };
221 })
222}
223
224#[derive(Debug)]
225struct Strukt {
226 ident: Ident,
227 fields: Vec<Field>,
228 deny_unknown_fields: bool,
229 krate: Option<ModulePath>,
230}
231
232macro_rules! exports {
233 ($($path:path as $ident:ident);* $(;)?) => {
234 #[allow(non_snake_case)]
235 struct Exports {
236 $(
237 #[doc = stringify!($path)]
238 $ident: TokenStream,
239 )*
240 }
241 impl Exports {
242 fn new(path_to_ez_jsonrpc: Option<ModulePath>) -> Self {
243 let path_to_ez_jsonrpc = path_to_ez_jsonrpc.unwrap_or(parse_quote!(::ez_jsonrpc)).into_token_stream();
244 Self {
245 $(
246 $ident: quote! { #path_to_ez_jsonrpc::__private::exports::$ident }
247 ),*
248 }
249 }
250 }
251 };
252}
253
254exports! { crate::params::DeserializeNamed as DeserializeNamed;
256 crate::params::DeserializePositional as DeserializePositional;
257 crate::params::SerializeNamed as SerializeNamed;
258 crate::params::SerializePositional as SerializePositional;
259 Err as Err_;
260 None as None_;
261 Ok as Ok_;
262 Result as Result;
263 serde as serde;
264 serde::de::Error as de_Error;
265 serde::de::IgnoredAny as IgnoredAny;
266 serde::de::MapAccess as MapAccess;
267 serde::de::SeqAccess as SeqAccess;
268 serde::de::value::MapAccessDeserializer as MapAccessDeserializer;
269 serde::Deserialize as Deserialize;
270 serde::ser::SerializeMap as SerializeMap;
271 serde::ser::SerializeSeq as SerializeSeq;
272}
273
274impl Strukt {
275 fn new(input: &DeriveInput) -> darling::Result<Self> {
276 #[derive(FromDeriveInput)]
277 #[darling(attributes(jsonrpc))]
278 struct _Strukt {
279 ident: Ident,
280 data: ast::Data<util::Ignored, Field>,
281 #[darling(default)]
282 deny_unknown_fields: bool,
283 #[darling(rename = "crate")]
284 krate: Option<ModulePath>,
285 }
286 if !input.generics.params.is_empty()
287 || input
288 .generics
289 .where_clause
290 .as_ref()
291 .is_some_and(|it| !it.predicates.is_empty())
292 {
293 return Err(darling::Error::unsupported_shape("generics").with_span(&input.generics));
294 }
295 let _Strukt {
296 ident,
297 data,
298 deny_unknown_fields,
299 krate,
300 } = FromDeriveInput::from_derive_input(input)?;
301 Ok(Self {
302 ident,
303 fields: match data {
304 ast::Data::Enum(_) => return Err(darling::Error::unsupported_shape("enum")),
305 ast::Data::Struct(fields) => fields.fields,
306 },
307 deny_unknown_fields,
308 krate,
309 })
310 }
311}
312
313#[derive(Debug)]
314struct ModulePath {
315 leading_colon: Option<Token![::]>,
316 segments: Punctuated<Ident, Token![::]>,
317}
318
319impl Parse for ModulePath {
320 fn parse(input: ParseStream) -> syn::Result<Self> {
321 let syn::Path {
322 leading_colon,
323 segments,
324 } = input.call(syn::Path::parse_mod_style)?;
325 Ok(Self {
326 leading_colon,
327 segments: segments.into_iter().map(|it| it.ident).collect(),
328 })
329 }
330}
331
332impl ToTokens for ModulePath {
333 fn to_tokens(&self, tokens: &mut TokenStream) {
334 let Self {
335 leading_colon,
336 segments,
337 } = self;
338 leading_colon.to_tokens(tokens);
339 segments.to_tokens(tokens);
340 }
341}
342
343impl FromMeta for ModulePath {
344 fn from_expr(expr: &syn::Expr) -> darling::Result<Self> {
345 Ok(syn::parse2(expr.to_token_stream())?)
346 }
347}
348
349#[derive(Debug)]
350struct Field {
351 ident: Ident,
352 ty: syn::Type,
353 rename: Option<String>,
354 default: bool,
355}
356
357impl FromField for Field {
358 fn from_field(field: &syn::Field) -> darling::Result<Self> {
359 #[derive(FromField)]
360 #[darling(attributes(jsonrpc))]
361 struct _Field {
362 ident: Option<Ident>,
363 ty: syn::Type,
364 rename: Option<String>,
365 #[darling(default)]
366 default: bool,
367 }
368
369 let _Field {
370 ident,
371 ty,
372 rename,
373 default,
374 } = FromField::from_field(field)?;
375 Ok(Self {
376 ident: ident.ok_or_else(|| {
377 darling::Error::unsupported_shape_with_expected(
378 "unnamed fields",
379 &"a struct with named fields",
380 )
381 })?,
382 ty,
383 rename,
384 default,
385 })
386 }
387}