parity_codec_derive/
lib.rs1extern crate proc_macro;
18use proc_macro2;
19
20#[macro_use]
21extern crate syn;
22
23#[macro_use]
24extern crate quote;
25
26use proc_macro::TokenStream;
27use proc_macro2::Span;
28use syn::{DeriveInput, Ident, parse::Error};
29use proc_macro_crate::crate_name;
30
31use std::env;
32
33mod decode;
34mod encode;
35mod utils;
36mod trait_bounds;
37
38fn include_parity_codec_crate() -> proc_macro2::TokenStream {
40 if env::var("CARGO_PKG_NAME").unwrap() == "parity-codec" {
42 quote!( extern crate parity_codec as _parity_codec; )
43 } else {
44 match crate_name("parity-codec") {
45 Ok(parity_codec_crate) => {
46 let ident = Ident::new(&parity_codec_crate, Span::call_site());
47 quote!( extern crate #ident as _parity_codec; )
48 },
49 Err(e) => Error::new(Span::call_site(), &e).to_compile_error(),
50 }
51 }
52}
53
54#[proc_macro_derive(Encode, attributes(codec))]
55pub fn encode_derive(input: TokenStream) -> TokenStream {
56 let mut input: DeriveInput = match syn::parse(input) {
57 Ok(input) => input,
58 Err(e) => return e.to_compile_error().into(),
59 };
60 if let Some(span) = utils::get_skip(&input.attrs) {
61 return Error::new(span, "invalid attribute `skip` on root input")
62 .to_compile_error().into();
63 }
64
65 if let Err(e) = trait_bounds::add(
66 &input.ident,
67 &mut input.generics,
68 &input.data,
69 parse_quote!(_parity_codec::Encode),
70 None,
71 ) {
72 return e.to_compile_error().into();
73 }
74
75 let name = &input.ident;
76 let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
77
78 let self_ = quote!(self);
79 let dest_ = quote!(dest);
80 let encoding = encode::quote(&input.data, name, &self_, &dest_);
81
82 let impl_block = quote! {
83 impl #impl_generics _parity_codec::Encode for #name #ty_generics #where_clause {
84 fn encode_to<EncOut: _parity_codec::Output>(&#self_, #dest_: &mut EncOut) {
85 #encoding
86 }
87 }
88 };
89
90 let mut new_name = "_IMPL_ENCODE_FOR_".to_string();
91 new_name.push_str(name.to_string().trim_start_matches("r#"));
92 let dummy_const = Ident::new(&new_name, Span::call_site());
93 let parity_codec_crate = include_parity_codec_crate();
94
95 let generated = quote! {
96 #[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
97 const #dummy_const: () = {
98 #[allow(unknown_lints)]
99 #[cfg_attr(feature = "cargo-clippy", allow(useless_attribute))]
100 #[allow(rust_2018_idioms)]
101 #parity_codec_crate
102 #impl_block
103 };
104 };
105
106 generated.into()
107}
108
109#[proc_macro_derive(Decode, attributes(codec))]
110pub fn decode_derive(input: TokenStream) -> TokenStream {
111 let mut input: DeriveInput = match syn::parse(input) {
112 Ok(input) => input,
113 Err(e) => return e.to_compile_error().into(),
114 };
115 if let Some(span) = utils::get_skip(&input.attrs) {
116 return Error::new(span, "invalid attribute `skip` on root input")
117 .to_compile_error().into();
118 }
119
120 if let Err(e) = trait_bounds::add(
121 &input.ident,
122 &mut input.generics,
123 &input.data,
124 parse_quote!(_parity_codec::Decode),
125 Some(parse_quote!(Default))
126 ) {
127 return e.to_compile_error().into();
128 }
129
130 let name = &input.ident;
131 let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
132
133 let input_ = quote!(input);
134 let decoding = decode::quote(&input.data, name, &input_);
135
136 let impl_block = quote! {
137 impl #impl_generics _parity_codec::Decode for #name #ty_generics #where_clause {
138 fn decode<DecIn: _parity_codec::Input>(#input_: &mut DecIn) -> Option<Self> {
139 #decoding
140 }
141 }
142 };
143
144 let mut new_name = "_IMPL_DECODE_FOR_".to_string();
145 new_name.push_str(name.to_string().trim_start_matches("r#"));
146 let dummy_const = Ident::new(&new_name, Span::call_site());
147 let parity_codec_crate = include_parity_codec_crate();
148
149 let generated = quote! {
150 #[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
151 const #dummy_const: () = {
152 #[allow(unknown_lints)]
153 #[cfg_attr(feature = "cargo-clippy", allow(useless_attribute))]
154 #[allow(rust_2018_idioms)]
155 #parity_codec_crate
156 #impl_block
157 };
158 };
159
160 generated.into()
161}