diff --git a/.travis.yml b/.travis.yml index 769366c7..9b52c64e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,4 +3,4 @@ rust: - stable - beta - nightly - + - 1.17.0 diff --git a/Cargo.toml b/Cargo.toml index b64f58a1..47bde725 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,23 +1,23 @@ - [package] -name = "jsonrpc" -version = "0.8.0" -authors = ["Andrew Poelstra "] -license = "CC0-1.0" -homepage = "https://github.com/apoelstra/rust-jsonrpc/" -repository = "https://github.com/apoelstra/rust-jsonrpc/" -documentation = "https://www.wpsoftware.net/rustdoc/jsonrpc/" -description = "Rust support for the JSON-RPC 2.0 protocol" -keywords = [ "protocol", "json", "http", "jsonrpc" ] -readme = "README.md" +name = "jsonrpc" +version = "0.9.0" +authors = ["Andrew Poelstra "] +license = "CC0-1.0" +homepage = "https://github.com/apoelstra/rust-jsonrpc/" +repository = "https://github.com/apoelstra/rust-jsonrpc/" +documentation = "https://www.wpsoftware.net/rustdoc/jsonrpc/" +description = "Rust support for the JSON-RPC 2.0 protocol" +keywords = [ "protocol", "json", "http", "jsonrpc" ] +readme = "README.md" [lib] name = "jsonrpc" path = "src/lib.rs" [dependencies] -serde = "0.6" -strason = "0.3" +serde = "1" +serde_derive = "1" +strason = "0.4" [dependencies.hyper] version = "0.9" diff --git a/src/client.rs b/src/client.rs index 7b32300d..2bfb53c8 100644 --- a/src/client.rs +++ b/src/client.rs @@ -25,7 +25,7 @@ use std::sync::{Arc, Mutex}; use hyper::client::Client as HyperClient; use hyper::header::{Headers, Authorization, Basic}; use hyper; -use strason::{self, Json}; +use strason::Json; use super::{Request, Response}; use error::Error; @@ -57,8 +57,7 @@ impl Client { /// Sends a request to a client pub fn send_request(&self, request: &Request) -> Result { // Build request - let request_json = try!(strason::from_serialize(request)); - let request_raw = request_json.to_bytes(); + let request_raw = Json::from_serialize(request)?.to_bytes(); // Setup connection let mut headers = Headers::new(); @@ -94,9 +93,8 @@ impl Client { // nb we ignore stream.status since we expect the body // to contain information about any error - let response_json = try!(Json::from_reader(&mut stream)); + let response: Response = Json::from_reader(&mut stream)?.into_deserialize()?; stream.bytes().count(); // Drain the stream so it can be reused - let response: Response = try!(response_json.into_deserialize()); if response.jsonrpc != None && response.jsonrpc != Some(From::from("2.0")) { return Err(Error::VersionMismatch); diff --git a/src/error.rs b/src/error.rs index 0d43fc24..fd6600fe 100644 --- a/src/error.rs +++ b/src/error.rs @@ -20,7 +20,6 @@ use std::{error, fmt}; use hyper; -use serde; use strason::{self, Json}; use Response; @@ -123,7 +122,7 @@ pub enum StandardError { InternalError } -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)] /// A JSONRPC error object pub struct RpcError { /// The integer identifier of the error @@ -173,13 +172,6 @@ pub fn result_to_response(result: Result, id: Json) -> Response } } -serde_struct_impl!( - RpcError, - code, - message, - data -); - #[cfg(test)] mod tests { use super::StandardError::{ParseError, InvalidRequest, MethodNotFound, InvalidParams, InternalError}; diff --git a/src/lib.rs b/src/lib.rs index e5c16e0c..d7c62e36 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,10 +30,12 @@ #![warn(missing_docs)] extern crate hyper; + extern crate serde; +#[macro_use] +extern crate serde_derive; extern crate strason; -#[macro_use] mod macros; pub mod client; pub mod error; @@ -41,7 +43,7 @@ use strason::Json; // Re-export error type pub use error::Error; -#[derive(Clone, Debug, PartialEq)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] /// A JSONRPC request object pub struct Request { /// The name of the RPC call @@ -54,7 +56,7 @@ pub struct Request { pub jsonrpc: Option } -#[derive(Clone, Debug, PartialEq)] +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] /// A JSONRPC response object pub struct Response { /// A result if there is one, or null @@ -69,7 +71,7 @@ pub struct Response { impl Response { /// Extract the result from a response - pub fn result(&self) -> Result { + pub fn result(&self) -> Result { if let Some(ref e) = self.error { return Err(Error::Rpc(e.clone())); } @@ -80,12 +82,13 @@ impl Response { } /// Extract the result from a response, consuming the response - pub fn into_result(self) -> Result { + pub fn into_result(self) -> Result { if let Some(e) = self.error { return Err(Error::Rpc(e)); } + match self.result { - Some(res) => res.into_deserialize().map_err(Error::Json), + Some(ref res) => res.clone().into_deserialize().map_err(Error::Json), None => Err(Error::NoErrorOrResult) } } @@ -103,27 +106,11 @@ impl Response { pub fn is_none(&self) -> bool { self.result.is_none() } } -serde_struct_impl!( - Request, - method, - params, - id, - jsonrpc -); - -serde_struct_impl!( - Response, - result, - error, - id, - jsonrpc -); - #[cfg(test)] mod tests { use super::{Request, Response}; use super::error::RpcError; - use strason::{self, Json}; + use strason::Json; #[test] fn request_serialize_round_trip() { @@ -137,7 +124,7 @@ mod tests { jsonrpc: Some(String::from("2.0")) }; - let ser = strason::from_serialize(&original).unwrap(); + let ser = Json::from_serialize(&original).unwrap(); let des = ser.into_deserialize().unwrap(); assert_eq!(original, des); @@ -161,7 +148,7 @@ mod tests { jsonrpc: Some(String::from("2.0")) }; - let ser = strason::from_serialize(&original).unwrap(); + let ser = Json::from_serialize(&original).unwrap(); let des = ser.into_deserialize().unwrap(); assert_eq!(original, des); @@ -191,7 +178,7 @@ mod tests { fn response_extract() { let obj = vec!["Mary", "had", "a", "little", "lamb"]; let response = Response { - result: Some(strason::from_serialize(&obj).unwrap()), + result: Some(Json::from_serialize(&obj).unwrap()), error: None, id: From::from(()), jsonrpc: Some(String::from("2.0")) diff --git a/src/macros.rs b/src/macros.rs deleted file mode 100644 index 958f863e..00000000 --- a/src/macros.rs +++ /dev/null @@ -1,314 +0,0 @@ -// Rust JSON-RPC Library -// Written in 2015 by -// Andrew Poelstra -// -// To the extent possible under law, the author(s) have dedicated all -// copyright and related and neighboring rights to this software to -// the public domain worldwide. This software is distributed without -// any warranty. -// -// You should have received a copy of the CC0 Public Domain Dedication -// along with this software. -// If not, see . -// - -//! # Macros -//! -//! Macros to replace serde's codegen while that is not stable -//! - -#[macro_export] -macro_rules! __rust_jsonrpc_internal__define_anything_type { - () => ( - struct Anything; - struct AnythingVisitor; - impl ::serde::de::Visitor for AnythingVisitor { - type Value = Anything; - - fn visit_bool(&mut self, _: bool) -> Result { Ok(Anything) } - fn visit_i64(&mut self, _: i64) -> Result { Ok(Anything) } - fn visit_u64(&mut self, _: u64) -> Result { Ok(Anything) } - fn visit_f64(&mut self, _: f64) -> Result { Ok(Anything) } - fn visit_str(&mut self, _: &str) -> Result { Ok(Anything) } - fn visit_string(&mut self, _: String) -> Result { Ok(Anything) } - fn visit_unit(&mut self) -> Result { Ok(Anything) } - fn visit_none(&mut self) -> Result { Ok(Anything) } - - fn visit_some(&mut self, d: &mut D) -> Result { - serde::de::Deserialize::deserialize(d) - } - - fn visit_seq(&mut self, v: V) -> Result { - let _: Vec = try!(::serde::de::impls::VecVisitor::new().visit_seq(v)); - Ok(Anything) - } - - fn visit_map(&mut self, mut v: V) -> Result { - while let Some((Anything, Anything)) = try!(v.visit()) { } - try!(v.end()); - Ok(Anything) - } - } - - impl ::serde::Deserialize for Anything { - fn deserialize(deserializer: &mut D) -> Result - where D: ::serde::de::Deserializer - { - deserializer.visit(AnythingVisitor) - } - } - ) -} - -#[macro_export] -macro_rules! serde_struct_impl { - ($name:ident, $($fe:ident $(<- $alt:expr)*),*) => ( - impl ::serde::Deserialize for $name { - fn deserialize(deserializer: &mut D) -> Result<$name, D::Error> - where D: serde::de::Deserializer - { - // begin type defs - __rust_jsonrpc_internal__define_anything_type!(); - - #[allow(non_camel_case_types)] - enum Enum { Unknown__Field, $($fe),* } - - struct EnumVisitor; - impl ::serde::de::Visitor for EnumVisitor { - type Value = Enum; - - fn visit_str(&mut self, value: &str) -> Result - where E: ::serde::de::Error - { - match value { - $( - stringify!($fe) => Ok(Enum::$fe) - $(, $alt => Ok(Enum::$fe))* - ),*, - _ => Ok(Enum::Unknown__Field) - } - } - } - - impl ::serde::Deserialize for Enum { - fn deserialize(deserializer: &mut D) -> Result - where D: ::serde::de::Deserializer - { - deserializer.visit_str(EnumVisitor) - } - } - - struct Visitor; - - impl ::serde::de::Visitor for Visitor { - type Value = $name; - - fn visit_map(&mut self, mut v: V) -> Result<$name, V::Error> - where V: ::serde::de::MapVisitor - { - $(let mut $fe = None;)* - - loop { - match try!(v.visit_key()) { - Some(Enum::Unknown__Field) => { let _: Anything = try!(v.visit_value()); } - $(Some(Enum::$fe) => { $fe = Some(try!(v.visit_value())); })* - None => { break; } - } - } - - $(let $fe = match $fe { - Some(x) => x, - None => try!(v.missing_field(stringify!($fe))), - };)* - try!(v.end()); - Ok($name{ $($fe: $fe),* }) - } - } - // end type defs - - static FIELDS: &'static [&'static str] = &[$(stringify!($fe)),*]; - - deserializer.visit_struct(stringify!($name), FIELDS, Visitor) - } - } - - impl ::serde::Serialize for $name { - fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> - where S: ::serde::Serializer - { - // begin type defs - #[repr(u16)] - #[derive(Copy, Clone)] - #[allow(non_camel_case_types)] - #[allow(dead_code)] - enum State { $($fe),* , Finished } - - struct MapVisitor<'a> { - value: &'a $name, - state: State, - } - - impl<'a> ::serde::ser::MapVisitor for MapVisitor<'a> { - fn visit(&mut self, serializer: &mut S) -> Result, S::Error> - where S: ::serde::Serializer - { - match self.state { - $(State::$fe => { - self.state = unsafe { ::std::mem::transmute(self.state as u16 + 1) }; - // Use the last alternate name for serialization; in the common case - // with zero or one alternates this does the RIght Thing - let names = [stringify!($fe), $($alt),*]; - Ok(Some(try!(serializer.visit_struct_elt(names[names.len() - 1], &self.value.$fe)))) - })* - State::Finished => { - Ok(None) - } - } - } - } - // end type defs - - serializer.visit_struct(stringify!($name), MapVisitor { - value: self, - state: unsafe { ::std::mem::transmute(0u16) }, - }) - } - } - ) -} - -#[macro_export] -macro_rules! serde_struct_enum_impl { - ($name:ident, - $($varname:ident, $structname:ident, $($fe:ident $(<- $alt:expr)*),*);* - ) => ( - impl ::serde::Deserialize for $name { - fn deserialize(deserializer: &mut D) -> Result<$name, D::Error> - where D: serde::de::Deserializer - { - // start type defs - __rust_jsonrpc_internal__define_anything_type!(); - - $(#[allow(non_camel_case_types)] enum $varname { $($fe),* })* - #[allow(non_camel_case_types)] - enum Enum { Unknown__Field, $($varname($varname)),* } - - struct EnumVisitor; - impl ::serde::de::Visitor for EnumVisitor { - type Value = Enum; - - fn visit_str(&mut self, value: &str) -> Result - where E: ::serde::de::Error - { - $($( - if value == stringify!($fe) $(|| value == $alt)* { - Ok(Enum::$varname($varname::$fe)) - } else)*)* { - Ok(Enum::Unknown__Field) - } - } - } - - impl ::serde::Deserialize for Enum { - fn deserialize(deserializer: &mut D) -> Result - where D: ::serde::de::Deserializer - { - deserializer.visit_str(EnumVisitor) - } - } - - struct Visitor; - - impl ::serde::de::Visitor for Visitor { - type Value = $name; - - #[allow(non_snake_case)] //for $structname - #[allow(unused_assignments)] // for `$fe = None` hack - fn visit_map(&mut self, mut v: V) -> Result<$name, V::Error> - where V: ::serde::de::MapVisitor - { - $( - $(let mut $fe = None;)* - // In case of multiple variants having the same field, some of - // the above lets will get shadowed. We therefore need to tell - // rustc its type, since it otherwise cannot infer it, causing - // a compilation error. Hence this hack, which the denizens of - // #rust and I had a good laugh over: - if false { let _ = $structname { $($fe: $fe.unwrap()),* }; } - // The above expression moved $fe so we have to reassign it :) - $($fe = None;)* - )* - - loop { - match try!(v.visit_key()) { - Some(Enum::Unknown__Field) => { let _: Anything = try!(v.visit_value()); } - $($(Some(Enum::$varname($varname::$fe)) => { - $fe = Some(try!(v.visit_value())); })*)* - None => { break; } - } - } - - // try to find a variant for which we have all fields - $( - let mut $structname = true; - $(if $fe.is_none() { $structname = false })* - // if we found one, success. extra fields is not an error, - // it'd be too much of a PITA to manage overlapping field - // sets otherwise. - if $structname { - $(let $fe = $fe.unwrap();)* - try!(v.end()); - return Ok($name::$varname($structname { $($fe: $fe),* })) - } - )* - // If we get here we failed - Err(::serde::de::Error::syntax("did not get all fields")) - } - } - // end type defs - - static FIELDS: &'static [&'static str] = &[$($(stringify!($fe)),*),*]; - - deserializer.visit_struct(stringify!($name), FIELDS, Visitor) - } - } - - // impl Serialize (and Deserialize, tho we don't need it) for the underlying structs - $( serde_struct_impl!($structname, $($fe $(<- $alt)*),*); )* - // call serialize on the right one - impl ::serde::Serialize for $name { - fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> - where S: ::serde::Serializer - { - match *self { - $($name::$varname(ref x) => x.serialize(serializer)),* - } - } - } - ) -} - -#[cfg(test)] -mod tests { - use serde; - - pub struct Variant1 { - success: bool, - success_message: String - } - - pub struct Variant2 { - success: bool, - errors: Vec - } - - pub enum Reply { - Good(Variant1), - Bad(Variant2), - } - serde_struct_enum_impl!(Reply, - Good, Variant1, success, success_message; - Bad, Variant2, success, errors - ); -} -