Macro tokio_jsonrpc::jsonrpc_params
[−]
[src]
macro_rules! jsonrpc_params { ( $value:expr, ) => { ... }; ( $value:expr ) => { ... }; ( $value:expr, single $varname:ident : $vartype:ty ) => { ... }; ( arity $head:ident ) => { ... }; ( arity $head:ident, $( $tail:ident ),* ) => { ... }; ( $spl:expr, accum ( $( $result:tt )* ), positional_decode $vname:ident : $vtype:ty ) => { ... }; ( $spl:expr, accum ( $( $result:tt )* ), positional_decode $hname:ident : $htype:ty, $( $tname:ident : $ttype:ty ),+ ) => { ... }; ( $value:expr, positional $( $varname:ident : $vartype:ty ),+ ) => { ... }; ( $value:expr, named $( $varname:ident : $vartype:ty ),+ ) => { ... }; ( $value:expr, decide $( $varname:ident : $vartype:ty ),+ ) => { ... }; ( $value:expr, $varname: ident: $vartype: ty ) => { ... }; ( $value:expr, $( $varname:ident : $vartype:ty ),+ ) => { ... }; }
Parses the parameters of an RPC or a notification.
The Server
receives &Option<Value>
as the parameters when its
notification
or rpc
method is called and it needs to handle it. This means checking for
validity and converting it to appropriate types. This is tedious.
This macro helps with that. In it's basic usage, you pass the received parameters and parameter
definitions for what you want and receive a tuple of converted ones. In case the parameters are
invalid, it returns early with an Some(IntoFuture<_, Error = RpcError>)
directly from your
function (which is the return type of the callbacks).
By default, it accepts both parameters passed by a name (inside a JSON object) or by position
(inside an array). If you insist your clients must use named or positional parameters, prefix
the parameter definitions by named
or positional
respectively.
This also handles optional arguments in the named
case (and when auto-detecting and a JSON
object is provided).
If an empty parameter definition is provided, the macro checks that no parameters were sent
(accepts no parameters sent, null
sent as parameters and an empty object or array).
If a single parameter is passed, in addition to trying positional and named parameters, the
macro tries to convert the whole Value
into the given type. This allows you to ask for
a structure that holds all the named parameters.
If you want to force the single parameter conversion of the whole Value
, you can use the
macro as jsonrpc_params!(params, single name: Type)
. However, in this case it returns
Result<Type, RpcError>
‒ since it is expected you might want to try both named and
positional decoding yourself. Also, it expects &Value
, not &Option<Value>
.
The macro has other variants than the mentioned here. They are mostly used internally by the macro itself and aren't meant to be used directly.
Examples
Basic usage, parse an integer and a boolean:
fn parse(params: &Option<Value>) -> Option<Result<(i32, bool), RpcError>> { Some(Ok(jsonrpc_params!(params, num: i32, b: bool))) } assert_eq!((42, true), parse(&Some(json!([42, true]))).unwrap().unwrap()); assert_eq!((42, true), parse(&Some(json!({"num": 42, "b": true}))).unwrap().unwrap()); parse(&None).unwrap().unwrap_err(); parse(&Some(json!({"num": "hello", "b": false}))).unwrap().unwrap_err();
Usage with enforcing named parameters. Also, the integer is optional. Enforcing positional
works in a similar way, with the positional
token.
fn parse(params: &Option<Value>) -> Option<Result<(Option<i32>, bool), RpcError>> { Some(Ok(jsonrpc_params!(params, named num: Option<i32>, b: bool))) } parse(&Some(json!([42, true]))).unwrap().unwrap_err(); assert_eq!((Some(42), true), parse(&Some(json!({"num": 42, "b": true}))).unwrap().unwrap()); assert_eq!((None, false), parse(&Some(json!({"b": false, "extra": "ignored"}))).unwrap().unwrap()); parse(&None).unwrap().unwrap_err(); parse(&Some(json!({"num": "hello", "b": false}))).unwrap().unwrap_err();
Decoding into a structure works like this:
#[derive(PartialEq, Debug, Deserialize)] struct Params { num: Option<i32>, b: bool, } fn parse(params: &Option<Value>) -> Option<Result<Params, RpcError>> { let (params,) = jsonrpc_params!(params, params: Params); Some(Ok(params)) } let expected = Params { num: Some(42), b: true, }; let expected_optional = Params { num: None, b: false, }; assert_eq!(expected, parse(&Some(json!([42, true]))).unwrap().unwrap()); assert_eq!(expected, parse(&Some(json!({"num": 42, "b": true}))).unwrap().unwrap()); assert_eq!(expected_optional, parse(&Some(json!({"b": false}))).unwrap().unwrap()); // This is accepted mostly as a side effect. assert_eq!(expected, parse(&Some(json!([{"num": 42, "b": true}]))).unwrap().unwrap()); // As is this. assert_eq!(expected, parse(&Some(json!({"params": {"num": 42, "b": true}}))).unwrap().unwrap()); // If you mind the above limitations, you can ask directly for a single value decoding. // That returs a Result directly. assert_eq!(expected, jsonrpc_params!(&json!({"num": 42, "b": true}), single params: Params).unwrap()); jsonrpc_params!(&json!([{"num": 42, "b": true}]), single params: Params).unwrap_err();