diff --git a/Cargo.toml b/Cargo.toml index 0d38d87..b236541 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,7 +31,3 @@ secp256k1 = "0.6" serde = "0.6" strason = "0.3" -[dependencies.jsonrpc] -version = "0.8" # for serde macros -default-features = false - diff --git a/src/internal_macros.rs b/src/internal_macros.rs index 818711f..ece4b51 100644 --- a/src/internal_macros.rs +++ b/src/internal_macros.rs @@ -282,3 +282,303 @@ macro_rules! hex_script (($s:expr) => (Script::from($s.from_hex().unwrap()))); #[cfg(test)] macro_rules! hex_hash (($s:expr) => (Sha256dHash::from(&$s.from_hex().unwrap()[..]))); + +// Macros to replace serde's codegen while that is not stable +// Taken from rust-jsonrpc 8a50735712cb7870990314cc150ab9c2955dbfd5 + +#[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 + ); +} + + diff --git a/src/lib.rs b/src/lib.rs index 952a922..38c809f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -43,7 +43,6 @@ extern crate byteorder; extern crate crypto; -#[macro_use] extern crate jsonrpc; extern crate rand; extern crate rustc_serialize as serialize; extern crate secp256k1;