eth_jsonrpc_types_internals/
lib.rs1extern crate proc_macro;
16extern crate proc_macro2;
17#[macro_use]
18extern crate syn;
19#[macro_use]
20extern crate quote;
21
22use syn::parse::{Parse, ParseStream};
23use syn::punctuated::Punctuated;
24use syn::token;
25
26struct TypeWithAttrs {
27 attrs: Vec<syn::Attribute>,
28 typ: syn::Type,
29}
30
31impl Parse for TypeWithAttrs {
32 fn parse(input: ParseStream) -> syn::Result<Self> {
33 Ok(Self {
34 attrs: input.call(syn::Attribute::parse_outer)?,
35 typ: input.parse()?,
36 })
37 }
38}
39
40struct ParamsType {
41 name: syn::Ident,
42 colon_token: Token![:],
43 brace_token: token::Bracket,
44 fields: Punctuated<TypeWithAttrs, Token![,]>,
45 comma_token: Token![,],
46 resp: syn::Ident,
47}
48
49impl Parse for ParamsType {
50 fn parse(input: ParseStream) -> syn::Result<Self> {
51 let content;
52 Ok(ParamsType {
53 name: input.parse()?,
54 colon_token: input.parse()?,
55 brace_token: bracketed!(content in input),
56 fields: content.parse_terminated(TypeWithAttrs::parse)?,
57 comma_token: input.parse()?,
58 resp: input.parse()?,
59 })
60 }
61}
62
63fn construct_rpcname_from_params_name(params_name: &str) -> syn::LitStr {
66 if params_name.len() <= 6 {
67 panic!("The name of params [{}] is too short.", params_name);
68 }
69 if !params_name.ends_with("Params") {
70 panic!("Please named the params as: method_name + \"Params\".");
71 }
72 let rpcname = params_name[..1].to_ascii_lowercase() + ¶ms_name[1..params_name.len() - 6];
73 syn::LitStr::new(&rpcname, proc_macro2::Span::call_site())
74}
75
76#[proc_macro]
77pub fn construct_rpcname(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
78 let input: proc_macro2::TokenStream = input.into();
79 let output = {
80 let params_name: syn::Ident = syn::parse2(input).unwrap();
81 let rpcname = construct_rpcname_from_params_name(params_name.to_string().as_ref());
82 quote!(#rpcname)
83 };
84 output.into()
85}
86
87fn generate_attrs_list(attrs_vec: &[syn::Attribute]) -> proc_macro2::TokenStream {
88 let mut attrs = quote!();
89 for attr in attrs_vec.iter() {
90 attrs = quote!(#attrs #attr);
91 }
92 quote!(#attrs)
93}
94
95#[proc_macro]
96pub fn construct_params(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
97 let input = proc_macro2::TokenStream::from(input);
98
99 let output = {
100 let ParamsType {
101 name,
102 colon_token: _colon_token,
103 brace_token: _brace_token,
104 fields,
105 comma_token: _comma_token,
106 resp,
107 } = syn::parse2(input).unwrap();
108
109 let fields_size = fields.len();
110 let mut ele_req = fields_size;
111 let rpcname = construct_rpcname_from_params_name(name.to_string().as_ref());
112
113 let mut types = quote!();
114 let mut params_with_types = quote!();
115 let mut params = quote!();
116 let mut params_into_vec = quote!();
117
118 match fields_size {
119 0 => {}
120 1 => {
121 let TypeWithAttrs { attrs, typ } = &fields.iter().next().unwrap();
122 if !attrs.is_empty() {
123 ele_req = ele_req - 1;
124 }
125 let param_attrs = generate_attrs_list(attrs);
126 types = quote!(#param_attrs pub #typ, #[serde(skip)] OneItemTupleTrick);
127 params_with_types = quote!(param: #typ);
128 params = quote!(param, OneItemTupleTrick::default());
129 let index = syn::Index::from(0);
130 params_into_vec = quote!(serde_json::to_value(self.#index).unwrap())
131 }
132 _ => {
133 let mut param_num = 0;
134 for TypeWithAttrs { attrs, typ } in fields.iter() {
135 let param_attrs = generate_attrs_list(attrs.as_slice());
136 if !attrs.is_empty() {
137 ele_req = ele_req - 1;
138 }
139 let param_name = format!("p{}", param_num);
140 let param_name = syn::Ident::new(¶m_name, proc_macro2::Span::call_site());
141 types = quote!(#types #param_attrs pub #typ,);
142 params_with_types = quote!(#params_with_types #param_name: #typ,);
143 params = quote!(#params #param_name,);
144 let index = syn::Index::from(param_num);
145 params_into_vec = quote!(
146 #params_into_vec
147 serde_json::to_value(self.#index).unwrap(), );
148 param_num += 1;
149 }
150 }
151 };
152
153 quote!(
154 #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)]
155 pub struct #name (#types);
156
157 impl #name {
158 pub fn new(#params_with_types) -> #name {
159 #name(#params)
160 }
161 }
162
163 impl JsonRpcRequest for #name {
164
165 type Response = #resp;
166
167 fn required_len() -> usize {
168 #ele_req
169 }
170
171 fn valid_len() -> usize {
172 #fields_size
173 }
174
175 fn method_name(&self) -> &'static str {
176 #rpcname
177 }
178
179 fn value_vec(self) -> Vec<serde_json::Value> {
180 vec![#params_into_vec]
181 }
182 }
183 )
184 };
185
186 proc_macro::TokenStream::from(output)
187}