@@ -173,15 +173,17 @@ impl RpcMethod {
173
173
. map ( |x| ident ( & ( ( x + 'a' as u8 ) as char ) . to_string ( ) ) )
174
174
. collect ( ) ;
175
175
let param_types = & param_types;
176
- let parse_params =
177
- // if the last argument is an `Option` then it can be made an optional 'trailing' argument
178
- if let Some ( ref trailing) = param_types. iter ( ) . last ( ) . and_then ( try_get_option) {
179
- self . params_with_trailing ( trailing, param_types, tuple_fields)
176
+ let parse_params = {
177
+ // last arguments that are `Option`-s are optional 'trailing' arguments
178
+ let trailing_args_num = param_types. iter ( ) . rev ( ) . take_while ( |t| is_option_type ( t) ) . count ( ) ;
179
+ if trailing_args_num != 0 {
180
+ self . params_with_trailing ( trailing_args_num, param_types, tuple_fields)
180
181
} else if param_types. is_empty ( ) {
181
182
quote ! { let params = params. expect_no_params( ) ; }
182
183
} else {
183
184
quote ! { let params = params. parse:: <( #( #param_types, ) * ) >( ) ; }
184
- } ;
185
+ }
186
+ } ;
185
187
186
188
let method_ident = self . ident ( ) ;
187
189
let result = & self . trait_item . sig . decl . output ;
@@ -257,48 +259,52 @@ impl RpcMethod {
257
259
258
260
fn params_with_trailing (
259
261
& self ,
260
- trailing : & syn :: Type ,
262
+ trailing_args_num : usize ,
261
263
param_types : & [ syn:: Type ] ,
262
264
tuple_fields : & [ syn:: Ident ] ,
263
265
) -> proc_macro2:: TokenStream {
264
- let param_types_no_trailing: Vec < _ > =
265
- param_types. iter ( ) . cloned ( ) . filter ( |arg| arg != trailing) . collect ( ) ;
266
- let tuple_fields_no_trailing: & Vec < _ > =
267
- & tuple_fields. iter ( ) . take ( tuple_fields. len ( ) - 1 ) . collect ( ) ;
268
- let num = param_types_no_trailing. len ( ) ;
269
- let all_params_len = param_types. len ( ) ;
270
- let no_trailing_branch =
271
- if all_params_len > 1 {
272
- quote ! {
273
- params. parse:: <( #( #param_types_no_trailing, ) * ) >( )
274
- . map( |( #( #tuple_fields_no_trailing, ) * ) |
275
- ( #( #tuple_fields_no_trailing, ) * None ) )
276
- . map_err( Into :: into)
266
+ let total_args_num = param_types. len ( ) ;
267
+ let required_args_num = total_args_num - trailing_args_num;
268
+
269
+ let switch_branches = ( 0 ..trailing_args_num+1 )
270
+ . map ( |passed_trailing_args_num| {
271
+ let passed_args_num = required_args_num + passed_trailing_args_num;
272
+ let passed_param_types = & param_types[ ..passed_args_num] ;
273
+ let passed_tuple_fields = & tuple_fields[ ..passed_args_num] ;
274
+ let missed_args_num = total_args_num - passed_args_num;
275
+ let missed_params_values = :: std:: iter:: repeat ( quote ! { None } ) . take ( missed_args_num) . collect :: < Vec < _ > > ( ) ;
276
+
277
+ if passed_args_num == 0 {
278
+ quote ! {
279
+ #passed_args_num => params. expect_no_params( )
280
+ . map( |_| ( #( #missed_params_values, ) * ) )
281
+ . map_err( Into :: into)
282
+ }
283
+ } else {
284
+ quote ! {
285
+ #passed_args_num => params. parse:: <( #( #passed_param_types, ) * ) >( )
286
+ . map( |( #( #passed_tuple_fields, ) * ) |
287
+ ( #( #passed_tuple_fields, ) * #( #missed_params_values, ) * ) )
288
+ . map_err( Into :: into)
289
+ }
277
290
}
278
- } else if all_params_len == 1 {
279
- quote ! ( Ok ( ( None , ) ) )
280
- } else {
281
- panic ! ( "Should be at least one trailing param; qed" )
282
- } ;
291
+ } ) . collect :: < Vec < _ > > ( ) ;
292
+
283
293
quote ! {
284
- let params_len = match params {
294
+ let passed_args_num = match params {
285
295
_jsonrpc_core:: Params :: Array ( ref v) => Ok ( v. len( ) ) ,
286
296
_jsonrpc_core:: Params :: None => Ok ( 0 ) ,
287
297
_ => Err ( _jsonrpc_core:: Error :: invalid_params( "`params` should be an array" ) )
288
298
} ;
289
299
290
- let params = params_len. and_then( |len| {
291
- match len. checked_sub( #num) {
292
- Some ( 0 ) => #no_trailing_branch,
293
- Some ( 1 ) => params. parse:: <( #( #param_types, ) * ) > ( )
294
- . map( |( #( #tuple_fields_no_trailing, ) * id, ) |
295
- ( #( #tuple_fields_no_trailing, ) * id, ) )
296
- . map_err( Into :: into) ,
297
- None => Err ( _jsonrpc_core:: Error :: invalid_params(
298
- format!( "`params` should have at least {} argument(s)" , #num) ) ) ,
300
+ let params = passed_args_num. and_then( |passed_args_num| {
301
+ match passed_args_num {
302
+ _ if passed_args_num < #required_args_num => Err ( _jsonrpc_core:: Error :: invalid_params(
303
+ format!( "`params` should have at least {} argument(s)" , #required_args_num) ) ) ,
304
+ #( #switch_branches) , * ,
299
305
_ => Err ( _jsonrpc_core:: Error :: invalid_params_with_details(
300
- format!( "Expected {} or {} parameters." , #num , #num + 1 ) ,
301
- format!( "Got: {}" , len ) ) ) ,
306
+ format!( "Expected from {} to {} parameters." , #required_args_num , #total_args_num ) ,
307
+ format!( "Got: {}" , passed_args_num ) ) ) ,
302
308
}
303
309
} ) ;
304
310
}
@@ -318,15 +324,14 @@ fn ident(s: &str) -> syn::Ident {
318
324
syn:: Ident :: new ( s, proc_macro2:: Span :: call_site ( ) )
319
325
}
320
326
321
- fn try_get_option ( ty : & syn:: Type ) -> Option < syn :: Type > {
327
+ fn is_option_type ( ty : & syn:: Type ) -> bool {
322
328
if let syn:: Type :: Path ( path) = ty {
323
329
path. path . segments
324
330
. first ( )
325
- . and_then ( |t| {
326
- if t. value ( ) . ident == "Option" { Some ( ty. clone ( ) ) } else { None }
327
- } )
331
+ . map ( |t| t. value ( ) . ident == "Option" )
332
+ . unwrap_or ( false )
328
333
} else {
329
- None
334
+ false
330
335
}
331
336
}
332
337
0 commit comments