#json-rpc #proc-macro #traits #handler #procedural #generate #definition

macro easy-jsonrpc-proc-macro-mw

Procedural macro portion of easy-jsonrpc. Don't use this crate directly. Use easy-jsonrpc instead.

1 unstable release

0.5.1 Aug 19, 2019

#185 in #handler

Download history 162/week @ 2024-11-15 199/week @ 2024-11-22 318/week @ 2024-11-29 353/week @ 2024-12-06 443/week @ 2024-12-13 333/week @ 2024-12-20 122/week @ 2024-12-27 203/week @ 2025-01-03 220/week @ 2025-01-10 316/week @ 2025-01-17 351/week @ 2025-01-24 149/week @ 2025-01-31 281/week @ 2025-02-07 223/week @ 2025-02-14 200/week @ 2025-02-21 212/week @ 2025-02-28

949 downloads per month
Used in 59 crates (via easy-jsonrpc-mw)

Apache-2.0

15KB
298 lines

Build Status

Easy JSON RPC

Generates an rpc handler and client helpers based on a trait definition. docs

Defining an api

use easy_jsonrpc;

#[easy_jsonrpc::rpc]
pub trait Adder {
    fn checked_add(&self, a: isize, b: isize) -> Option<isize>;
    fn wrapping_add(&self, a: isize, b: isize) -> isize;
    fn is_some(&self, a: Option<usize>) -> bool {
        a.is_some()
    }
    fn takes_ref(&self, rf: &isize);
}

The rpc macro generates

  1. An implementaion of the Handler trait for &dyn Adder
  2. A helper module for rpc clients

Server side usage

use easy_jsonrpc::{Handler, MaybeReply};
use serde_json::json;

struct AdderImpl;

impl Adder for AdderImpl {
    fn checked_add(&self, a: isize, b: isize) -> Option<isize> { a.checked_add(b) }
    fn wrapping_add(&self, a: isize, b: isize) -> isize { a.wrapping_add(b) }
    fn takes_ref(&self, rf: &isize) {}
}

let handler = (&AdderImpl {} as &dyn Adder);

assert_eq!(
    handler.handle_request(json!({
        "jsonrpc": "2.0",
        "method": "wrapping_add",
        "params": [1, 2],
        "id": 1
    })),
    MaybeReply::Reply(json!({
        "jsonrpc": "2.0",
        "result": 3,
        "id": 1
    }))
);

Client side usage

let bind = adder::checked_add(1, 2).unwrap();
let (call, tracker) = bind.call();
let json_response = match handler.handle_request(call.as_request()) {
   MaybeReply::Reply(resp) => resp,
   MaybeReply::DontReply => panic!(),
};
let mut response = easy_jsonrpc::Response::from_json_response(json_response).unwrap();
assert_eq!(tracker.get_return(&mut response).unwrap(), Some(3));

Bonus bits

Named arguments are handled for free.

assert_eq!(
    handler.handle_request(json!({
        "jsonrpc": "2.0",
        "method": "wrapping_add",
        "params": {
            "a": 1,
            "b": 2
        },
        "id": 1
    })),
    MaybeReply::Reply(json!({
        "jsonrpc": "2.0",
        "result": 3,
        "id": 1
    }))
);

Notifications (calls without an id) are handled sanely.

assert_eq!(
    handler.handle_request(json!({
        "jsonrpc": "2.0",
        "method": "wrapping_add",
        "params": [1, 1]
    })),
    MaybeReply::DontReply
);

Notification are easy to generate.

let bind = adder::checked_add(0, 0).unwrap();
let notification = bind.notification().as_request();
assert_eq!(handler.handle_request(notification), MaybeReply::DontReply);

Batch calls are possible.

use easy_jsonrpc::Call;
let bind0 = adder::checked_add(0, 0).unwrap();
let (call0, tracker0) = bind0.call();
let bind1 = adder::checked_add(1, 0).unwrap();
let (call1, tracker1) = bind1.call();
let bind2 = adder::wrapping_add(1, 1).unwrap();
let (call2, tracker2) = bind2.call();
let bind3 = adder::wrapping_add(1, 1).unwrap();
let call3 = bind3.notification();
let json_request = Call::batch_request(&[call0, call1, call2, call3]);
let json_response = match handler.handle_request(json_request) {
   MaybeReply::Reply(resp) => resp,
   MaybeReply::DontReply => panic!(),
};
let mut response = easy_jsonrpc::Response::from_json_response(json_response).unwrap();
assert_eq!(tracker1.get_return(&mut response).unwrap(), Some(1));
assert_eq!(tracker0.get_return(&mut response).unwrap(), Some(0));
assert_eq!(tracker2.get_return(&mut response).unwrap(), 2);

Dependencies

~2.5MB
~53K SLoC