Skip to content

Use procedural macros #340

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 88 commits into from
Jan 28, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
88 commits
Select commit Hold shift + click to select a range
09dcfb4
Empty rpc trait with proc macro attribute
ascjones Nov 21, 2018
f33f36d
Generate skeleton to_delegate method
ascjones Nov 22, 2018
26116aa
WIP: wrap rpc methods in to_delegate
ascjones Nov 23, 2018
0159923
Generate basic to_delegate
ascjones Nov 27, 2018
493496c
Add derive examples and tests
ascjones Nov 27, 2018
33ed0fb
Add async rpc method example
ascjones Nov 27, 2018
3d8e1c9
Fix extern crate hygiene
ascjones Nov 28, 2018
3778cdd
Add where clause bounds to to_delegate function
ascjones Nov 29, 2018
c840bc3
WIP: Support one way serialisation for generics
ascjones Nov 29, 2018
408c16e
Add Serialize bounds to generic RPC return types
ascjones Dec 3, 2018
82295ba
Add Serialize bounds for RPC args
ascjones Dec 3, 2018
148aba5
Clean up imports
ascjones Dec 3, 2018
a721094
Refactor and read aliases from rpc trait
ascjones Dec 4, 2018
9e7e578
Wire up aliases
ascjones Dec 4, 2018
364a110
Derive rpc with metadata associated type
ascjones Dec 5, 2018
2a2690e
Refactor
ascjones Dec 5, 2018
bb73396
Rename trait level attribute to rpc
ascjones Dec 5, 2018
42843bd
Refactor: move entry point function into lib
ascjones Dec 5, 2018
4ff351e
WIP: implement pubsub
ascjones Dec 5, 2018
898b792
Implement pubsub macro
ascjones Dec 6, 2018
d8dcead
Register pub/sub method aliases
ascjones Dec 6, 2018
e909327
Remove delegates file prematurely copied to core
ascjones Dec 6, 2018
343c6c3
Fix TCP tests?
tomusdrw Dec 6, 2018
d85076e
Merge branch 'master' into aj-proc-macro
ascjones Dec 17, 2018
49a9cb9
Inline rpc method registration
ascjones Dec 18, 2018
8bfc98a
Extract return type when creating RpcMethod
ascjones Dec 19, 2018
ab58951
Handle methods with no params
ascjones Dec 19, 2018
82ef5dd
WIP: Add support for optional trailing params
ascjones Dec 19, 2018
ae79b74
Handle optional trailing params
ascjones Dec 21, 2018
a163810
Bring back aliases
ascjones Dec 21, 2018
121074c
Inline into_future to remove extraneous types/fns
ascjones Dec 21, 2018
922f748
Refactor extra args for use in pubsub
ascjones Dec 21, 2018
76e0e41
WIP: migrate pubsub delegate registration
ascjones Dec 21, 2018
6e9d9e6
Extract special args from delegate
ascjones Dec 23, 2018
e00fc7d
Register sub/unsub using generated delgate closure
ascjones Dec 23, 2018
5ccd298
WIP: move macro delegates to core and pubsub
ascjones Dec 23, 2018
3bc2468
WIP: refactor to handle subscription method
ascjones Jan 7, 2019
728e52e
Handle pubsub error
ascjones Jan 7, 2019
7b5838a
Add pub/sub IoDelegate
ascjones Jan 8, 2019
385bb8d
Refactor and fix pubsub compiler errors
ascjones Jan 8, 2019
d74b79c
Restore original delegates file and fix auto_args
ascjones Jan 8, 2019
c925f49
Wrap subscriber in typed subscriber
ascjones Jan 9, 2019
6f5254f
Handle pubsub unsubscribe method
ascjones Jan 9, 2019
202aec1
Uncomment pubsub example
ascjones Jan 9, 2019
7b80555
Merge branch 'master' into aj-proc-macro
ascjones Jan 9, 2019
9283e86
Unsubscribe optional metadata
ascjones Jan 9, 2019
55f3518
Copy macro tests over and make them compile with derive
ascjones Jan 9, 2019
827b3b4
Fix pubsub trailing test
ascjones Jan 9, 2019
ff54ce6
Rename to_delegate
ascjones Jan 9, 2019
d6f7ed5
Remove errant printlns
ascjones Jan 9, 2019
c3de179
Copy and modify module docs from macros
ascjones Jan 10, 2019
d1629b4
Fix derive doc test
ascjones Jan 10, 2019
c99cdae
Mark subscribe/unsubscribe methods with attribute
ascjones Jan 10, 2019
b2d928d
Generic type param with metadata example, update some error messages
ascjones Jan 10, 2019
61619f3
Refactor: extract a couple of functions for readability
ascjones Jan 11, 2019
b61df80
Add compiletests to test compile errors
ascjones Jan 11, 2019
04700f9
Remove test both for now
ascjones Jan 11, 2019
abeb43e
Remove top level future imports
ascjones Jan 11, 2019
b697699
Merge branch 'master' into aj-proc-macro
ascjones Jan 11, 2019
3f66fca
Fix unsubscribe missing import
ascjones Jan 11, 2019
3b8371b
Correct derive crate author
ascjones Jan 14, 2019
a47b46b
Rust 2018: cargo fix --edition --package jsonrpc-derive
ascjones Jan 14, 2019
1df7d4b
Remove redundant `extern crate` rust 2018
ascjones Jan 14, 2019
2f898bb
Fix doc tests for edition 2018
ascjones Jan 14, 2019
6d18803
Add missing_docs warning
ascjones Jan 14, 2019
4f4f43c
Replace &str to_string() with into()
ascjones Jan 15, 2019
e303b0d
Move all magic strings to constants
ascjones Jan 15, 2019
e2dcbb1
WIP
ascjones Jan 16, 2019
e9e8118
Bring pubsub methods back into same trait
ascjones Jan 18, 2019
5e4c19d
Geoup pubsub methods by subscription name
ascjones Jan 21, 2019
2071ea5
Refactor attribute parsing
ascjones Jan 21, 2019
be82056
Update compilefail tests for new pubsub
ascjones Jan 21, 2019
0e913f6
Fix combined rpc and pubsub trait
ascjones Jan 21, 2019
7323f03
Fix compilefail tests
ascjones Jan 22, 2019
fc77cf0
added some tests (failing)
svyatonik Jan 11, 2019
a7c1e40
Remove multiple trailing params tests, will implement in later PR
ascjones Jan 22, 2019
586fba1
Fix parse of single param tuple with trailing comma
ascjones Jan 22, 2019
00cb328
Specify subscription name in missing annotation error
ascjones Jan 22, 2019
add1282
Add tests for trailing args
ascjones Jan 23, 2019
656511c
Handle single trailing param
ascjones Jan 23, 2019
8e0491b
Replace extern crates in macro output
ascjones Jan 23, 2019
2ee3239
Reduce recursion limit
ascjones Jan 23, 2019
7430f87
Add comment for `to_delegate` trait method
ascjones Jan 23, 2019
c70a252
Deprecate `to_delegate` method generated by jsonrpc-macros
ascjones Jan 24, 2019
6d23846
Update README with derive example
ascjones Jan 25, 2019
324ffc3
Add pubsub example and rpc attribute docs
ascjones Jan 25, 2019
2a8b5ea
Remove commented out code
ascjones Jan 28, 2019
a54721a
Bump major version
ascjones Jan 28, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ members = [
"http",
"ipc",
"macros",
"derive",
"minihttp",
"pubsub",
"pubsub/more-examples",
Expand Down
25 changes: 11 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ Transport-agnostic `core` and transport servers for `http`, `ipc`, `websockets`
- [jsonrpc-tcp-server](./tcp) [![crates.io][tcp-server-image]][tcp-server-url]
- [jsonrpc-ws-server](./ws)
- [jsonrpc-stdio-server](./stdio)
- [jsonrpc-macros](./macros) [![crates.io][macros-image]][macros-url]
- [jsonrpc-macros](./macros) [![crates.io][macros-image]][macros-url] *deprecated:* use `derive` instead
- [jsonrpc-derive](./derive)
- [jsonrpc-server-utils](./server-utils) [![crates.io][server-utils-image]][server-utils-url]
- [jsonrpc-pubsub](./pubsub) [![crates.io][pubsub-image]][pubsub-url]

Expand All @@ -38,7 +39,8 @@ Transport-agnostic `core` and transport servers for `http`, `ipc`, `websockets`
## Examples

- [core](./core/examples)
- [macros](./macros/examples)
- [derive](./derive/examples)
- [macros](./macros/examples) *deprecated*
- [pubsub](./pubsub/examples)

### Basic Usage (with HTTP transport)
Expand All @@ -65,21 +67,17 @@ fn main() {
}
```

### Basic usage with macros
### Basic usage with derive

```rust
extern crate jsonrpc_core;
#[macro_use]
extern crate jsonrpc_macros;

use jsonrpc_core::Result;
use jsonrpc_derive::rpc;

build_rpc_trait! {
pub trait Rpc {
/// Adds two numbers and returns a result
#[rpc(name = "add")]
fn add(&self, u64, u64) -> Result<u64>;
}
#[rpc]
pub trait Rpc {
/// Adds two numbers and returns a result
#[rpc(name = "add")]
fn add(&self, u64, u64) -> Result<u64>;
}

pub struct RpcImpl;
Expand All @@ -89,7 +87,6 @@ impl Rpc for RpcImpl {
}
}


fn main() {
let mut io = jsonrpc_core::IoHandler::new();
io.extend_with(RpcImpl.to_delegate())
Expand Down
2 changes: 1 addition & 1 deletion core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ homepage = "https://github.com/paritytech/jsonrpc"
repository = "https://github.com/paritytech/jsonrpc"
license = "MIT"
name = "jsonrpc-core"
version = "9.0.0"
version = "10.0.0"
authors = ["debris <[email protected]>"]
keywords = ["jsonrpc", "json-rpc", "json", "rpc", "serde"]
documentation = "https://paritytech.github.io/jsonrpc/jsonrpc_core/index.html"
Expand Down
144 changes: 144 additions & 0 deletions core/src/delegates.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
//! Delegate rpc calls

use std::sync::Arc;
use std::collections::HashMap;

use types::{Params, Value, Error};
use calls::{Metadata, RemoteProcedure, RpcMethod, RpcNotification};
use futures::IntoFuture;
use BoxFuture;

struct DelegateAsyncMethod<T, F> {
delegate: Arc<T>,
closure: F,
}

impl<T, M, F, I> RpcMethod<M> for DelegateAsyncMethod<T, F> where
M: Metadata,
F: Fn(&T, Params) -> I,
I: IntoFuture<Item = Value, Error = Error>,
T: Send + Sync + 'static,
F: Send + Sync + 'static,
I::Future: Send + 'static,
{
fn call(&self, params: Params, _meta: M) -> BoxFuture<Value> {
let closure = &self.closure;
Box::new(closure(&self.delegate, params).into_future())
}
}

struct DelegateMethodWithMeta<T, F> {
delegate: Arc<T>,
closure: F,
}

impl<T, M, F, I> RpcMethod<M> for DelegateMethodWithMeta<T, F> where
M: Metadata,
F: Fn(&T, Params, M) -> I,
I: IntoFuture<Item = Value, Error = Error>,
T: Send + Sync + 'static,
F: Send + Sync + 'static,
I::Future: Send + 'static,
{
fn call(&self, params: Params, meta: M) -> BoxFuture<Value> {
let closure = &self.closure;
Box::new(closure(&self.delegate, params, meta).into_future())
}
}

struct DelegateNotification<T, F> {
delegate: Arc<T>,
closure: F,
}

impl<T, M, F> RpcNotification<M> for DelegateNotification<T, F> where
F: Fn(&T, Params) + 'static,
F: Send + Sync + 'static,
T: Send + Sync + 'static,
M: Metadata,
{
fn execute(&self, params: Params, _meta: M) {
let closure = &self.closure;
closure(&self.delegate, params)
}
}

/// A set of RPC methods and notifications tied to single `delegate` struct.
pub struct IoDelegate<T, M = ()> where
T: Send + Sync + 'static,
M: Metadata,
{
delegate: Arc<T>,
methods: HashMap<String, RemoteProcedure<M>>,
}

impl<T, M> IoDelegate<T, M> where
T: Send + Sync + 'static,
M: Metadata,
{
/// Creates new `IoDelegate`
pub fn new(delegate: Arc<T>) -> Self {
IoDelegate {
delegate: delegate,
methods: HashMap::new(),
}
}

/// Adds an alias to existing method.
/// NOTE: Aliases are not transitive, i.e. you cannot create alias to an alias.
pub fn add_alias(&mut self, from: &str, to: &str) {
self.methods.insert(from.into(), RemoteProcedure::Alias(to.into()));
}

/// Adds async method to the delegate.
pub fn add_method<F, I>(&mut self, name: &str, method: F) where
F: Fn(&T, Params) -> I,
I: IntoFuture<Item = Value, Error = Error>,
F: Send + Sync + 'static,
I::Future: Send + 'static,
{
self.methods.insert(name.into(), RemoteProcedure::Method(Arc::new(
DelegateAsyncMethod {
delegate: self.delegate.clone(),
closure: method,
}
)));
}

/// Adds async method with metadata to the delegate.
pub fn add_method_with_meta<F, I>(&mut self, name: &str, method: F) where
F: Fn(&T, Params, M) -> I,
I: IntoFuture<Item = Value, Error = Error>,
F: Send + Sync + 'static,
I::Future: Send + 'static,
{
self.methods.insert(name.into(), RemoteProcedure::Method(Arc::new(
DelegateMethodWithMeta {
delegate: self.delegate.clone(),
closure: method,
}
)));
}

/// Adds notification to the delegate.
pub fn add_notification<F>(&mut self, name: &str, notification: F) where
F: Fn(&T, Params),
F: Send + Sync + 'static,
{
self.methods.insert(name.into(), RemoteProcedure::Notification(Arc::new(
DelegateNotification {
delegate: self.delegate.clone(),
closure: notification,
}
)));
}
}

impl<T, M> Into<HashMap<String, RemoteProcedure<M>>> for IoDelegate<T, M> where
T: Send + Sync + 'static,
M: Metadata,
{
fn into(self) -> HashMap<String, RemoteProcedure<M>> {
self.methods
}
}
2 changes: 2 additions & 0 deletions core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ mod io;

pub mod middleware;
pub mod types;
pub mod delegates;

/// A `Future` trait object.
pub type BoxFuture<T> = Box<futures::Future<Item = T, Error = Error> + Send>;
Expand All @@ -45,6 +46,7 @@ pub type BoxFuture<T> = Box<futures::Future<Item = T, Error = Error> + Send>;
pub type Result<T> = ::std::result::Result<T, Error>;

pub use calls::{RemoteProcedure, Metadata, RpcMethodSimple, RpcMethod, RpcNotificationSimple, RpcNotification};
pub use delegates::IoDelegate;
pub use io::{Compatibility, IoHandler, MetaIoHandler, FutureOutput, FutureResult, FutureResponse, FutureRpcResult};
pub use middleware::{Middleware, Noop as NoopMiddleware};
pub use types::*;
13 changes: 13 additions & 0 deletions core/src/types/error.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
//! jsonrpc errors
use std::fmt;
use serde::de::{Deserialize, Deserializer};
use serde::ser::{Serialize, Serializer};
use super::Value;
Expand Down Expand Up @@ -124,6 +125,18 @@ impl Error {
}
}

/// Creates `InvalidParams` for given parameter, with details.
pub fn invalid_params_with_details<M, T>(message: M, details: T) -> Error where
M: Into<String>,
T: fmt::Debug
{
Error {
code: ErrorCode::InvalidParams,
message: format!("Invalid parameters: {}", message.into()),
data: Some(Value::String(format!("{:?}", details))),
}
}

/// Creates new `InternalError`
pub fn internal_error() -> Self {
Self::new(ErrorCode::InternalError)
Expand Down
15 changes: 15 additions & 0 deletions core/src/types/params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,15 @@ impl Params {
Error::invalid_params(format!("Invalid params: {}.", e))
})
}

/// Check for no params, returns Err if any params
pub fn expect_no_params(self) -> Result<(), Error> {
match self {
Params::None => Ok(()),
Params::Array(ref v) if v.is_empty() => Ok(()),
p => Err(Error::invalid_params_with_details("No parameters were expected", p)),
}
}
}

#[cfg(test)]
Expand Down Expand Up @@ -75,4 +84,10 @@ mod tests {
assert_eq!(err2.message, "Invalid params: invalid length 2, expected a tuple of size 3.");
assert_eq!(err2.data, None);
}

#[test]
fn single_param_parsed_as_tuple() {
let params: (u64,) = Params::Array(vec![Value::from(1)]).parse().unwrap();
assert_eq!(params, (1,));
}
}
22 changes: 22 additions & 0 deletions derive/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[package]
name = "jsonrpc-derive"
version = "10.0.0"
authors = ["Parity Technologies <[email protected]>"]
edition = "2018"

[lib]
proc-macro = true

[dependencies]
syn = { version = "^0.15.22", features = ["full", "extra-traits", "visit", "fold"] }
proc-macro2 = "0.4"
quote = "0.6"

[dev-dependencies]
jsonrpc-core = { version = "10.0", path = "../core" }
jsonrpc-pubsub = { version = "10.0", path = "../pubsub" }
jsonrpc-tcp-server = { version = "10.0", path = "../tcp" }
serde = "1.0"
serde_derive = "1.0"
serde_json = "1.0"
compiletest_rs = { version = "*", features = ["stable"] }
61 changes: 61 additions & 0 deletions derive/examples/generic-trait-bounds.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
use serde_derive::{Serialize, Deserialize};

use jsonrpc_core::{IoHandler, Error, Result};
use jsonrpc_core::futures::future::{self, FutureResult};
use jsonrpc_derive::rpc;

// One is both parameter and a result so requires both Serialize and DeserializeOwned
// Two is only a parameter so only requires DeserializeOwned
// Three is only a result so only requires Serialize
#[rpc]
pub trait Rpc<One, Two, Three>
{
/// Get One type.
#[rpc(name = "getOne")]
fn one(&self) -> Result<One>;

/// Adds two numbers and returns a result
#[rpc(name = "setTwo")]
fn set_two(&self, _: Two) -> Result<()>;

#[rpc(name = "getThree")]
fn get_three(&self) -> Result<Three>;

/// Performs asynchronous operation
#[rpc(name = "beFancy")]
fn call(&self, _: One) -> FutureResult<(One, u64), Error>;
}

struct RpcImpl;

#[derive(Serialize, Deserialize)]
struct InAndOut { foo: u64 }
#[derive(Deserialize)]
struct In {}
#[derive(Serialize)]
struct Out {}

impl Rpc<InAndOut, In, Out> for RpcImpl {
fn one(&self) -> Result<InAndOut> {
Ok(InAndOut { foo: 1u64 })
}

fn set_two(&self, _x: In) -> Result<()> {
Ok(())
}

fn get_three(&self) -> Result<Out> {
Ok(Out {})
}

fn call(&self, num: InAndOut) -> FutureResult<(InAndOut, u64), Error> {
crate::future::finished((InAndOut {foo: num.foo + 999}, num.foo))
}
}

fn main() {
let mut io = IoHandler::new();

io.extend_with(Rpc::to_delegate(RpcImpl));
}

Loading