parity_scale_codec_derive/
lib.rs1#![recursion_limit = "128"]
18extern crate proc_macro;
19
20#[macro_use]
21extern crate syn;
22
23#[macro_use]
24extern crate quote;
25
26use crate::utils::{codec_crate_path, is_lint_attribute};
27use syn::{spanned::Spanned, Data, DeriveInput, Error, Field, Fields};
28
29mod decode;
30mod encode;
31mod max_encoded_len;
32mod trait_bounds;
33mod utils;
34
35fn wrap_with_dummy_const(
37 input: DeriveInput,
38 impl_block: proc_macro2::TokenStream,
39) -> proc_macro::TokenStream {
40 let attrs = input.attrs.into_iter().filter(is_lint_attribute);
41 let generated = quote! {
42 #[allow(deprecated)]
43 const _: () = {
44 #(#attrs)*
45 #impl_block
46 };
47 };
48
49 generated.into()
50}
51
52#[proc_macro_derive(Encode, attributes(codec))]
125pub fn encode_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
126 let mut input: DeriveInput = match syn::parse(input) {
127 Ok(input) => input,
128 Err(e) => return e.to_compile_error().into(),
129 };
130
131 if let Err(e) = utils::check_attributes(&input) {
132 return e.to_compile_error().into();
133 }
134
135 let crate_path = match codec_crate_path(&input.attrs) {
136 Ok(crate_path) => crate_path,
137 Err(error) => return error.into_compile_error().into(),
138 };
139
140 if let Err(e) = trait_bounds::add(
141 &input.ident,
142 &mut input.generics,
143 &input.data,
144 utils::custom_encode_trait_bound(&input.attrs),
145 parse_quote!(#crate_path::Encode),
146 None,
147 utils::has_dumb_trait_bound(&input.attrs),
148 &crate_path,
149 false,
150 ) {
151 return e.to_compile_error().into();
152 }
153
154 let name = &input.ident;
155 let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
156
157 let encode_impl = encode::quote(&input.data, name, &crate_path);
158
159 let impl_block = quote! {
160 #[automatically_derived]
161 impl #impl_generics #crate_path::Encode for #name #ty_generics #where_clause {
162 #encode_impl
163 }
164
165 #[automatically_derived]
166 impl #impl_generics #crate_path::EncodeLike for #name #ty_generics #where_clause {}
167 };
168
169 wrap_with_dummy_const(input, impl_block)
170}
171
172#[proc_macro_derive(Decode, attributes(codec))]
176pub fn decode_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
177 let mut input: DeriveInput = match syn::parse(input) {
178 Ok(input) => input,
179 Err(e) => return e.to_compile_error().into(),
180 };
181
182 if let Err(e) = utils::check_attributes(&input) {
183 return e.to_compile_error().into();
184 }
185
186 let crate_path = match codec_crate_path(&input.attrs) {
187 Ok(crate_path) => crate_path,
188 Err(error) => return error.into_compile_error().into(),
189 };
190
191 if let Err(e) = trait_bounds::add(
192 &input.ident,
193 &mut input.generics,
194 &input.data,
195 utils::custom_decode_trait_bound(&input.attrs),
196 parse_quote!(#crate_path::Decode),
197 Some(parse_quote!(Default)),
198 utils::has_dumb_trait_bound(&input.attrs),
199 &crate_path,
200 false,
201 ) {
202 return e.to_compile_error().into();
203 }
204
205 let name = &input.ident;
206 let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
207 let ty_gen_turbofish = ty_generics.as_turbofish();
208
209 let input_ = quote!(__codec_input_edqy);
210 let decoding =
211 decode::quote(&input.data, name, "e!(#ty_gen_turbofish), &input_, &crate_path);
212
213 let decode_into_body =
214 decode::quote_decode_into(&input.data, &crate_path, &input_, &input.attrs);
215
216 let impl_decode_into = if let Some(body) = decode_into_body {
217 quote! {
218 fn decode_into<__CodecInputEdqy: #crate_path::Input>(
219 #input_: &mut __CodecInputEdqy,
220 dst_: &mut ::core::mem::MaybeUninit<Self>,
221 ) -> ::core::result::Result<#crate_path::DecodeFinished, #crate_path::Error> {
222 #body
223 }
224 }
225 } else {
226 quote! {}
227 };
228
229 let impl_block = quote! {
230 #[automatically_derived]
231 impl #impl_generics #crate_path::Decode for #name #ty_generics #where_clause {
232 fn decode<__CodecInputEdqy: #crate_path::Input>(
233 #input_: &mut __CodecInputEdqy
234 ) -> ::core::result::Result<Self, #crate_path::Error> {
235 #decoding
236 }
237
238 #impl_decode_into
239 }
240 };
241
242 wrap_with_dummy_const(input, impl_block)
243}
244
245#[proc_macro_derive(DecodeWithMemTracking, attributes(codec))]
247pub fn decode_with_mem_tracking_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
248 let mut input: DeriveInput = match syn::parse(input) {
249 Ok(input) => input,
250 Err(e) => return e.to_compile_error().into(),
251 };
252
253 if let Err(e) = utils::check_attributes(&input) {
254 return e.to_compile_error().into();
255 }
256
257 let crate_path = match codec_crate_path(&input.attrs) {
258 Ok(crate_path) => crate_path,
259 Err(error) => return error.into_compile_error().into(),
260 };
261
262 if let Err(e) = trait_bounds::add(
263 &input.ident,
264 &mut input.generics,
265 &input.data,
266 utils::custom_decode_with_mem_tracking_trait_bound(&input.attrs),
267 parse_quote!(#crate_path::DecodeWithMemTracking),
268 Some(parse_quote!(Default)),
269 utils::has_dumb_trait_bound(&input.attrs),
270 &crate_path,
271 true,
272 ) {
273 return e.to_compile_error().into();
274 }
275
276 let name = &input.ident;
277 let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
278
279 let decode_with_mem_tracking_checks =
280 decode::quote_decode_with_mem_tracking_checks(&input.data, &crate_path);
281 let impl_block = quote! {
282 fn check_struct #impl_generics() #where_clause {
283 #decode_with_mem_tracking_checks
284 }
285
286 #[automatically_derived]
287 impl #impl_generics #crate_path::DecodeWithMemTracking for #name #ty_generics #where_clause {
288 }
289 };
290
291 wrap_with_dummy_const(input, impl_block)
292}
293
294#[proc_macro_derive(CompactAs, attributes(codec))]
309pub fn compact_as_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
310 let mut input: DeriveInput = match syn::parse(input) {
311 Ok(input) => input,
312 Err(e) => return e.to_compile_error().into(),
313 };
314
315 if let Err(e) = utils::check_attributes(&input) {
316 return e.to_compile_error().into();
317 }
318
319 let crate_path = match codec_crate_path(&input.attrs) {
320 Ok(crate_path) => crate_path,
321 Err(error) => return error.into_compile_error().into(),
322 };
323
324 if let Err(e) = trait_bounds::add::<()>(
325 &input.ident,
326 &mut input.generics,
327 &input.data,
328 None,
329 parse_quote!(#crate_path::CompactAs),
330 None,
331 utils::has_dumb_trait_bound(&input.attrs),
332 &crate_path,
333 false,
334 ) {
335 return e.to_compile_error().into();
336 }
337
338 let name = &input.ident;
339 let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
340
341 fn val_or_default(field: &Field) -> proc_macro2::TokenStream {
342 let skip = utils::should_skip(&field.attrs);
343 if skip {
344 quote_spanned!(field.span()=> Default::default())
345 } else {
346 quote_spanned!(field.span()=> x)
347 }
348 }
349
350 let (inner_ty, inner_field, constructor) = match input.data {
351 Data::Struct(ref data) => match data.fields {
352 Fields::Named(ref fields) if utils::filter_skip_named(fields).count() == 1 => {
353 let recurse = fields.named.iter().map(|f| {
354 let name_ident = &f.ident;
355 let val_or_default = val_or_default(f);
356 quote_spanned!(f.span()=> #name_ident: #val_or_default)
357 });
358 let field = utils::filter_skip_named(fields).next().expect("Exactly one field");
359 let field_name = &field.ident;
360 let constructor = quote!( #name { #( #recurse, )* });
361 (&field.ty, quote!(&self.#field_name), constructor)
362 },
363 Fields::Unnamed(ref fields) if utils::filter_skip_unnamed(fields).count() == 1 => {
364 let recurse = fields.unnamed.iter().map(|f| {
365 let val_or_default = val_or_default(f);
366 quote_spanned!(f.span()=> #val_or_default)
367 });
368 let (id, field) =
369 utils::filter_skip_unnamed(fields).next().expect("Exactly one field");
370 let id = syn::Index::from(id);
371 let constructor = quote!( #name(#( #recurse, )*));
372 (&field.ty, quote!(&self.#id), constructor)
373 },
374 _ =>
375 return Error::new(
376 data.fields.span(),
377 "Only structs with a single non-skipped field can derive CompactAs",
378 )
379 .to_compile_error()
380 .into(),
381 },
382 Data::Enum(syn::DataEnum { enum_token: syn::token::Enum { span }, .. }) |
383 Data::Union(syn::DataUnion { union_token: syn::token::Union { span }, .. }) =>
384 return Error::new(span, "Only structs can derive CompactAs").to_compile_error().into(),
385 };
386
387 let impl_block = quote! {
388 #[automatically_derived]
389 impl #impl_generics #crate_path::CompactAs for #name #ty_generics #where_clause {
390 type As = #inner_ty;
391 fn encode_as(&self) -> &#inner_ty {
392 #inner_field
393 }
394 fn decode_from(x: #inner_ty)
395 -> ::core::result::Result<#name #ty_generics, #crate_path::Error>
396 {
397 ::core::result::Result::Ok(#constructor)
398 }
399 }
400
401 #[automatically_derived]
402 impl #impl_generics From<#crate_path::Compact<#name #ty_generics>>
403 for #name #ty_generics #where_clause
404 {
405 fn from(x: #crate_path::Compact<#name #ty_generics>) -> #name #ty_generics {
406 x.0
407 }
408 }
409 };
410
411 wrap_with_dummy_const(input, impl_block)
412}
413
414#[cfg(feature = "max-encoded-len")]
428#[proc_macro_derive(MaxEncodedLen, attributes(max_encoded_len_mod))]
429pub fn derive_max_encoded_len(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
430 max_encoded_len::derive_max_encoded_len(input)
431}