Update serde to 1.0 and strason to 0.4

The `serde_struct_impl!` macro has been modified to be compatible
with the serde 1.0 crate, we use this macro and not the `serde_derive`
crate because the latter doesn't support Rust 1.14.0 which is shipped
on Debian stable and we should remain compatible with it.

Two new features were added:

- "serde": enables serialization/deserialization for common types, it pulls
the serde 1.0 dependency.
- "serde-decimal": enables serialization/deserialization for `UDecimal`/`Decimal`,
this pulls the strason 0.4 depdendency and the serde 1.0 dependency.

Signed-off-by: Jean Pierre Dudey <jeandudey@hotmail.com>
This commit is contained in:
Jean Pierre Dudey 2018-08-20 12:37:19 -04:00
parent 84040caa70
commit 1b4aba1d80
12 changed files with 372 additions and 416 deletions

View File

@ -14,4 +14,8 @@ script:
- cargo test --verbose
- cargo build --verbose --features=bitcoinconsensus
- cargo test --verbose --features=bitcoinconsensus
- cargo build --verbose --features=serde
- cargo test --verbose --features=serde
- cargo build --verbose --features=serde-decimal
- cargo test --verbose --features=serde-decimal
- if [ "$(rustup show | grep default | grep stable)" != "" ]; then cd fuzz && cargo test --verbose && ./travis-fuzz.sh; fi

View File

@ -17,16 +17,24 @@ path = "src/lib.rs"
[features]
fuzztarget = ["secp256k1/fuzztarget"]
serde-decimal = ["serde", "strason"]
[dependencies]
bitcoin-bech32 = "0.8.0"
byteorder = "1.1"
rand = "0.3"
rust-crypto = "0.2"
serde = "0.6"
strason = "0.3"
bitcoinconsensus = { version = "0.16", optional = true }
[dependencies.serde]
version = "1"
optional = true
[dependencies.strason]
version = "0.4"
optional = true
default-features = false
[dependencies.hex]
git = "https://github.com/KokaKiwi/rust-hex"
rev = "19fd37137686c30058bd9d11d21590e726ffdf31"

View File

@ -20,7 +20,7 @@
#![allow(non_camel_case_types)]
use serde;
#[cfg(feature = "serde")] use serde;
// Heavy stick to translate between opcode types
use std::mem::transmute;
@ -620,11 +620,13 @@ impl<S: SimpleEncoder> ConsensusEncodable<S> for All {
}
}
#[cfg(feature = "serde")]
impl serde::Serialize for All {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: serde::Serializer,
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.visit_str(&self.to_string())
serializer.serialize_str(&self.to_string())
}
}
@ -656,11 +658,13 @@ pub enum Class {
display_from_debug!(Class);
#[cfg(feature = "serde")]
impl serde::Serialize for Class {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: serde::Serializer,
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.visit_str(&self.to_string())
serializer.serialize_str(&self.to_string())
}
}

View File

@ -28,7 +28,7 @@ use std::default::Default;
use std::{error, fmt};
use crypto::digest::Digest;
use serde;
#[cfg(feature = "serde")] use serde;
use blockdata::opcodes;
use network::encodable::{ConsensusDecodable, ConsensusEncodable};
@ -561,39 +561,57 @@ impl From<Vec<u8>> for Builder {
impl_index_newtype!(Builder, u8);
// User-facing serialization
impl serde::Serialize for Script {
fn serialize<S>(&self, s: &mut S) -> Result<(), S::Error>
where S: serde::Serializer,
#[cfg(feature = "serde")]
impl<'de> serde::Deserialize<'de> for Script {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
s.visit_str(&format!("{:x}", self))
}
}
use std::fmt::{self, Formatter};
impl serde::Deserialize for Script {
fn deserialize<D>(d: &mut D) -> Result<Script, D::Error>
where D: serde::Deserializer
{
struct ScriptVisitor;
impl serde::de::Visitor for ScriptVisitor {
struct Visitor;
impl<'de> serde::de::Visitor<'de> for Visitor {
type Value = Script;
fn visit_string<E>(&mut self, v: String) -> Result<Script, E>
where E: serde::de::Error
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
formatter.write_str("a script")
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
let v: Vec<u8> = ::hex::decode(v).map_err(E::custom)?;
Ok(Script::from(v))
}
fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
self.visit_str(v)
}
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
self.visit_str(&v)
}
fn visit_str<E>(&mut self, hex_str: &str) -> Result<Script, E>
where E: serde::de::Error
{
let raw_vec: Vec<u8> = ::hex::decode(hex_str)
.map_err(|_| serde::de::Error::syntax("bad script hex"))?;
Ok(Script::from(raw_vec))
}
}
d.visit(ScriptVisitor)
deserializer.deserialize_str(Visitor)
}
}
#[cfg(feature = "serde")]
impl serde::Serialize for Script {
/// User-facing serialization for `Script`.
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(&format!("{:x}", self))
}
}
@ -704,11 +722,12 @@ mod test {
}
#[test]
#[cfg(all(feature = "serde", feature = "strason"))]
fn script_json_serialize() {
use strason;
use strason::Json;
let original = hex_script!("827651a0698faaa9a8a7a687");
let json = strason::from_serialize(&original).unwrap();
let json = Json::from_serialize(&original).unwrap();
assert_eq!(json.to_bytes(), b"\"827651a0698faaa9a8a7a687\"");
assert_eq!(json.string(), Some("827651a0698faaa9a8a7a687"));
let des = json.into_deserialize().unwrap();

View File

@ -27,7 +27,6 @@ use byteorder::{LittleEndian, WriteBytesExt};
use std::default::Default;
use std::fmt;
#[cfg(feature="bitcoinconsensus")] use std::collections::HashMap;
use serde;
use util::hash::Sha256dHash;
#[cfg(feature="bitcoinconsensus")] use blockdata::script;
@ -442,13 +441,16 @@ impl SigHashType {
#[cfg(test)]
mod tests {
use strason;
#[cfg(all(feature = "serde", feature = "strason"))]
use strason::Json;
use super::{Transaction, TxIn};
use blockdata::script::Script;
use network::serialize::BitcoinHash;
use network::serialize::{serialize, deserialize};
#[cfg(all(feature = "serde", feature = "strason"))]
use network::serialize::serialize;
use network::serialize::deserialize;
use util::hash::Sha256dHash;
use util::misc::hex_bytes;
@ -563,11 +565,12 @@ mod tests {
}
#[test]
#[cfg(all(feature = "serde", feature = "strason"))]
fn test_txn_encode_decode() {
let hex_tx = hex_bytes("0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000").unwrap();
let tx: Transaction = deserialize(&hex_tx).unwrap();
let encoded = strason::from_serialize(&tx).unwrap();
let encoded = Json::from_serialize(&tx).unwrap();
let decoded = encoded.into_deserialize().unwrap();
assert_eq!(tx, decoded);
}
@ -586,12 +589,13 @@ mod tests {
// Test decoding transaction `4be105f158ea44aec57bf12c5817d073a712ab131df6f37786872cfc70734188`
// from testnet, which is the first BIP144-encoded transaction I encountered.
#[test]
#[cfg(all(feature = "serde", feature = "strason"))]
fn test_segwit_tx_decode() {
let hex_tx = hex_bytes("010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff3603da1b0e00045503bd5704c7dd8a0d0ced13bb5785010800000000000a636b706f6f6c122f4e696e6a61506f6f6c2f5345475749542fffffffff02b4e5a212000000001976a914876fbb82ec05caa6af7a3b5e5a983aae6c6cc6d688ac0000000000000000266a24aa21a9edf91c46b49eb8a29089980f02ee6b57e7d63d33b18b4fddac2bcd7db2a39837040120000000000000000000000000000000000000000000000000000000000000000000000000").unwrap();
let tx: Transaction = deserialize(&hex_tx).unwrap();
assert_eq!(tx.get_weight(), 780);
let encoded = strason::from_serialize(&tx).unwrap();
let encoded = Json::from_serialize(&tx).unwrap();
let decoded = encoded.into_deserialize().unwrap();
assert_eq!(tx, decoded);

View File

@ -173,47 +173,50 @@ macro_rules! impl_array_newtype {
macro_rules! impl_array_newtype_encodable {
($thing:ident, $ty:ty, $len:expr) => {
impl ::serde::Deserialize for $thing {
fn deserialize<D>(d: &mut D) -> Result<$thing, D::Error>
where D: ::serde::Deserializer
#[cfg(feature = "serde")]
impl<'de> $crate::serde::Deserialize<'de> for $thing {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: $crate::serde::Deserializer<'de>,
{
// We have to define the Visitor struct inside the function
// to make it local ... what we really need is that it's
// local to the macro, but this is Close Enough.
struct Visitor {
marker: ::std::marker::PhantomData<$thing>,
}
impl ::serde::de::Visitor for Visitor {
use $crate::std::fmt::{self, Formatter};
struct Visitor;
impl<'de> $crate::serde::de::Visitor<'de> for Visitor {
type Value = $thing;
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
formatter.write_str("a fixed size array")
}
#[inline]
fn visit_seq<V>(&mut self, mut v: V) -> Result<$thing, V::Error>
where V: ::serde::de::SeqVisitor
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: $crate::serde::de::SeqAccess<'de>,
{
let mut ret: [$ty; $len] = [0; $len];
for item in ret.iter_mut() {
*item = match v.visit()? {
*item = match seq.next_element()? {
Some(c) => c,
None => return Err(::serde::de::Error::end_of_stream())
None => return Err($crate::serde::de::Error::custom("end of stream"))
};
}
v.end()?;
Ok($thing(ret))
}
}
// Begin actual function
d.visit(Visitor { marker: ::std::marker::PhantomData })
deserializer.deserialize_seq(Visitor)
}
}
impl ::serde::Serialize for $thing {
fn serialize<S>(&self, s: &mut S) -> Result<(), S::Error>
where S: ::serde::Serializer
#[cfg(feature = "serde")]
impl $crate::serde::Serialize for $thing {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: $crate::serde::Serializer,
{
let &$thing(ref dat) = self;
(&dat[..]).serialize(s)
(&dat[..]).serialize(serializer)
}
}
}
@ -286,303 +289,122 @@ macro_rules! hex_script (($s:expr) => (::blockdata::script::Script::from(::hex::
#[cfg(test)]
macro_rules! hex_hash (($s:expr) => (::util::hash::Sha256dHash::from(&::hex::decode($s).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<E>(&mut self, _: bool) -> Result<Anything, E> { Ok(Anything) }
fn visit_i64<E>(&mut self, _: i64) -> Result<Anything, E> { Ok(Anything) }
fn visit_u64<E>(&mut self, _: u64) -> Result<Anything, E> { Ok(Anything) }
fn visit_f64<E>(&mut self, _: f64) -> Result<Anything, E> { Ok(Anything) }
fn visit_str<E>(&mut self, _: &str) -> Result<Anything, E> { Ok(Anything) }
fn visit_string<E>(&mut self, _: String) -> Result<Anything, E> { Ok(Anything) }
fn visit_unit<E>(&mut self) -> Result<Anything, E> { Ok(Anything) }
fn visit_none<E>(&mut self) -> Result<Anything, E> { Ok(Anything) }
fn visit_some<D: ::serde::de::Deserializer>(&mut self, d: &mut D) -> Result<Anything, D::Error> {
serde::de::Deserialize::deserialize(d)
}
fn visit_seq<V: ::serde::de::SeqVisitor>(&mut self, v: V) -> Result<Anything, V::Error> {
let _: Vec<Anything> = ::serde::de::impls::VecVisitor::new().visit_seq(v)?;
Ok(Anything)
}
fn visit_map<V: ::serde::de::MapVisitor>(&mut self, mut v: V) -> Result<Anything, V::Error> {
while let Some((Anything, Anything)) = v.visit()? { }
v.end()?;
Ok(Anything)
}
}
impl ::serde::Deserialize for Anything {
fn deserialize<D>(deserializer: &mut D) -> Result<Anything, D::Error>
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<D>(deserializer: &mut D) -> Result<$name, D::Error>
where D: serde::de::Deserializer
($name:ident, $($fe:ident),*) => (
#[cfg(feature = "serde")]
impl<'de> $crate::serde::Deserialize<'de> for $name {
fn deserialize<D>(deserializer: D) -> Result<$name, D::Error>
where
D: $crate::serde::de::Deserializer<'de>,
{
// begin type defs
__rust_jsonrpc_internal__define_anything_type!();
use $crate::std::fmt::{self, Formatter};
use $crate::serde::de::IgnoredAny;
#[allow(non_camel_case_types)]
enum Enum { Unknown__Field, $($fe),* }
struct EnumVisitor;
impl ::serde::de::Visitor for EnumVisitor {
impl<'de> $crate::serde::de::Visitor<'de> for EnumVisitor {
type Value = Enum;
fn visit_str<E>(&mut self, value: &str) -> Result<Enum, E>
where E: ::serde::de::Error
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
formatter.write_str("a field name")
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: $crate::serde::de::Error,
{
match value {
match v {
$(
stringify!($fe) => Ok(Enum::$fe)
$(, $alt => Ok(Enum::$fe))*
),*,
_ => Ok(Enum::Unknown__Field)
}
}
}
impl ::serde::Deserialize for Enum {
fn deserialize<D>(deserializer: &mut D) -> Result<Enum, D::Error>
where D: ::serde::de::Deserializer
impl<'de> $crate::serde::Deserialize<'de> for Enum {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: ::serde::de::Deserializer<'de>,
{
deserializer.visit_str(EnumVisitor)
deserializer.deserialize_str(EnumVisitor)
}
}
struct Visitor;
impl ::serde::de::Visitor for Visitor {
impl<'de> $crate::serde::de::Visitor<'de> for Visitor {
type Value = $name;
fn visit_map<V>(&mut self, mut v: V) -> Result<$name, V::Error>
where V: ::serde::de::MapVisitor
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
formatter.write_str("a struct")
}
fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
where
A: $crate::serde::de::MapAccess<'de>,
{
use $crate::serde::de::Error;
$(let mut $fe = None;)*
loop {
match v.visit_key()? {
Some(Enum::Unknown__Field) => { let _: Anything = v.visit_value()?; }
$(Some(Enum::$fe) => { $fe = Some(v.visit_value()?); })*
match map.next_key::<Enum>()? {
Some(Enum::Unknown__Field) => {
map.next_value::<IgnoredAny>()?;
}
$(
Some(Enum::$fe) => {
$fe = Some(map.next_value()?);
}
)*
None => { break; }
}
}
$(let $fe = match $fe {
Some(x) => x,
None => v.missing_field(stringify!($fe))?,
};)*
v.end()?;
Ok($name{ $($fe: $fe),* })
$(
let $fe = match $fe {
Some(x) => x,
None => return Err(A::Error::missing_field(stringify!($fe))),
};
)*
let ret = $name {
$($fe: $fe),*
};
Ok(ret)
}
}
// end type defs
static FIELDS: &'static [&'static str] = &[$(stringify!($fe)),*];
deserializer.visit_struct(stringify!($name), FIELDS, Visitor)
deserializer.deserialize_struct(stringify!($name), FIELDS, Visitor)
}
}
impl ::serde::Serialize for $name {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: ::serde::Serializer
#[cfg(feature = "serde")]
impl<'de> $crate::serde::Serialize for $name {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: $crate::serde::Serializer,
{
// begin type defs
#[repr(u16)]
#[derive(Copy, Clone)]
#[allow(non_camel_case_types)]
#[allow(dead_code)]
enum State { $($fe),* , Finished }
use $crate::serde::ser::SerializeStruct;
struct MapVisitor<'a> {
value: &'a $name,
state: State,
}
// Only used to get the struct length.
static FIELDS: &'static [&'static str] = &[$(stringify!($fe)),*];
impl<'a> ::serde::ser::MapVisitor for MapVisitor<'a> {
fn visit<S>(&mut self, serializer: &mut S) -> Result<Option<()>, 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(serializer.visit_struct_elt(names[names.len() - 1], &self.value.$fe)?))
})*
State::Finished => {
Ok(None)
}
}
}
}
// end type defs
let mut st = serializer.serialize_struct(stringify!($name), FIELDS.len())?;
serializer.visit_struct(stringify!($name), MapVisitor {
value: self,
state: unsafe { ::std::mem::transmute(0u16) },
})
$(
st.serialize_field(stringify!($fe), &self.$fe)?;
)*
st.end()
}
}
)
}
#[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<D>(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<E>(&mut self, value: &str) -> Result<Enum, E>
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<D>(deserializer: &mut D) -> Result<Enum, D::Error>
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<V>(&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 v.visit_key()? {
Some(Enum::Unknown__Field) => { let _: Anything = v.visit_value()?; }
$($(Some(Enum::$varname($varname::$fe)) => {
$fe = Some(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();)*
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<S>(&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<String>
}
pub enum Reply {
Good(Variant1),
Bad(Variant2),
}
serde_struct_enum_impl!(Reply,
Good, Variant1, success, success_message;
Bad, Variant2, success, errors
);
}

View File

@ -47,8 +47,8 @@ extern crate crypto;
extern crate hex;
extern crate rand;
extern crate secp256k1;
extern crate serde;
extern crate strason;
#[cfg(feature = "serde")] extern crate serde;
#[cfg(feature = "strason")] extern crate strason;
#[cfg(all(test, feature = "unstable"))] extern crate test;
#[cfg(feature="bitcoinconsensus")] extern crate bitcoinconsensus;
@ -62,4 +62,3 @@ pub mod macros;
pub mod network;
pub mod blockdata;
pub mod util;

View File

@ -83,7 +83,13 @@ macro_rules! nu_select {
#[macro_export]
macro_rules! user_enum {
($(#[$attr:meta])* pub enum $name:ident { $(#[$doc:meta] $elem:ident <-> $txt:expr),* }) => (
(
$(#[$attr:meta])*
pub enum $name:ident {
$(#[$doc:meta]
$elem:ident <-> $txt:expr),*
}
) => (
$(#[$attr])*
pub enum $name {
$(#[$doc] $elem),*
@ -119,38 +125,62 @@ macro_rules! user_enum {
}
}
impl ::serde::Deserialize for $name {
#[cfg(feature = "serde")]
impl<'de> $crate::serde::Deserialize<'de> for $name {
#[inline]
fn deserialize<D>(d: &mut D) -> Result<$name, D::Error>
where D: ::serde::Deserializer
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: $crate::serde::Deserializer<'de>,
{
use $crate::std::fmt::{self, Formatter};
struct Visitor;
impl ::serde::de::Visitor for Visitor {
impl<'de> $crate::serde::de::Visitor<'de> for Visitor {
type Value = $name;
fn visit_string<E>(&mut self, v: String) -> Result<$name, E>
where E: ::serde::de::Error
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
formatter.write_str("an enum value")
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: $crate::serde::de::Error,
{
static FIELDS: &'static [&'static str] = &[$(stringify!($txt)),*];
$( if v == $txt { Ok($name::$elem) } )else*
else {
Err(E::unknown_variant(v, FIELDS))
}
}
fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
where
E: $crate::serde::de::Error,
{
self.visit_str(v)
}
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
where
E: $crate::serde::de::Error,
{
self.visit_str(&v)
}
fn visit_str<E>(&mut self, s: &str) -> Result<$name, E>
where E: ::serde::de::Error
{
$( if s == $txt { Ok($name::$elem) } )else*
else { Err(::serde::de::Error::syntax(stringify!($name))) }
}
}
d.visit(Visitor)
deserializer.deserialize_str(Visitor)
}
}
#[cfg(feature = "serde")]
impl ::serde::Serialize for $name {
fn serialize<S>(&self, s: &mut S) -> Result<(), S::Error>
where S: ::serde::Serializer
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: ::serde::Serializer,
{
s.visit_str(&self.to_string())
serializer.serialize_str(&self.to_string())
}
}
);

View File

@ -17,12 +17,13 @@
//! Internal macros used for unit tests
#[macro_export]
#[cfg(all(feature = "serde", feature = "strason"))]
macro_rules! serde_round_trip (
($var:expr) => ({
use strason;
use $crate::strason::Json;
let start = $var;
let encoded = strason::from_serialize(&start).unwrap();
let encoded = Json::from_serialize(&start).unwrap();
let decoded = encoded.into_deserialize().unwrap();
assert_eq!(start, decoded);
})

View File

@ -20,7 +20,7 @@ use std::default::Default;
use std::io::Cursor;
use std::{error, fmt};
use std::str::FromStr;
use serde::{Serialize, Deserialize, Serializer, Deserializer};
#[cfg(feature = "serde")] use serde;
use byteorder::{BigEndian, ByteOrder, ReadBytesExt};
use crypto::digest::Digest;
@ -167,17 +167,23 @@ impl fmt::Display for ChildNumber {
}
}
impl Serialize for ChildNumber {
fn serialize<S: Serializer>(&self, s: &mut S) -> Result<(), S::Error> {
u32::from(*self).serialize(s)
#[cfg(feature = "serde")]
impl<'de> serde::Deserialize<'de> for ChildNumber {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
u32::deserialize(deserializer).map(ChildNumber::from)
}
}
impl Deserialize for ChildNumber {
fn deserialize<D: Deserializer>(d: &mut D) -> Result<ChildNumber, D::Error> {
let n: u32 = Deserialize::deserialize(d)?;
Ok(ChildNumber::from(n))
#[cfg(feature = "serde")]
impl serde::Serialize for ChildNumber {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
u32::from(*self).serialize(serializer)
}
}
@ -673,6 +679,7 @@ mod tests {
}
#[test]
#[cfg(all(feature = "serde", feature = "strason"))]
pub fn encode_decode_childnumber() {
serde_round_trip!(ChildNumber::from_normal_idx(0));
serde_round_trip!(ChildNumber::from_normal_idx(1));

View File

@ -23,8 +23,8 @@
use std::{fmt, ops};
use serde::{ser, de};
use strason::Json;
#[cfg(feature = "serde-decimal")] use serde;
#[cfg(feature = "serde-decimal")] use strason::Json;
/// A fixed-point decimal type
#[derive(Copy, Clone, Debug, Eq, Ord)]
@ -128,20 +128,19 @@ impl Decimal {
pub fn nonnegative(&self) -> bool { self.mantissa >= 0 }
}
impl ser::Serialize for Decimal {
// Serialize through strason since it will not lose precision (when serializing
// to strason itself, the value will be passed through; otherwise it will be
// encoded as a string)
fn serialize<S: ser::Serializer>(&self, s: &mut S) -> Result<(), S::Error> {
let json = Json::from_str(&self.to_string()).unwrap();
ser::Serialize::serialize(&json, s)
}
}
impl de::Deserialize for Decimal {
// Deserialize through strason for the same reason as in `Serialize`
fn deserialize<D: de::Deserializer>(d: &mut D) -> Result<Decimal, D::Error> {
let json: Json = de::Deserialize::deserialize(d)?;
#[cfg(feature = "serde-decimal")]
impl<'de> serde::Deserialize<'de> for Decimal {
/// Deserialize a `Decimal`.
///
/// This type is deserialized through [`strason`][1] for the same reason as
/// it's explained in the `Serialize` implementation.
///
/// [1]: https://github.com/apoelstra/strason
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let json = Json::deserialize(deserializer)?;
match json.num() {
Some(s) => {
// We know this will be a well-formed Json number, so we can
@ -168,11 +167,28 @@ impl de::Deserialize for Decimal {
exponent: exponent,
})
}
None => Err(de::Error::syntax("expected decimal, got non-numeric"))
None => Err(serde::de::Error::custom("expected decimal, got non-numeric"))
}
}
}
#[cfg(feature = "serde-decimal")]
impl serde::Serialize for Decimal {
/// Serialize a `Decimal`.
///
/// This type is serialized through [`strason`][1] since it will not lose
/// precision (when serializing to [`strason`][1] itself, the value will be
/// passed through; otherwise it will be encoded as a string).
///
/// [1]: https://github.com/apoelstra/strason
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let json = Json::from_str(&self.to_string()).unwrap();
json.serialize(serializer)
}
}
impl PartialEq<UDecimal> for UDecimal {
fn eq(&self, other: &UDecimal) -> bool {
@ -246,20 +262,19 @@ impl UDecimal {
}
}
impl ser::Serialize for UDecimal {
// Serialize through strason since it will not lose precision (when serializing
// to strason itself, the value will be passed through; otherwise it will be
// encoded as a string)
fn serialize<S: ser::Serializer>(&self, s: &mut S) -> Result<(), S::Error> {
let json = Json::from_str(&self.to_string()).unwrap();
ser::Serialize::serialize(&json, s)
}
}
impl de::Deserialize for UDecimal {
// Deserialize through strason for the same reason as in `Serialize`
fn deserialize<D: de::Deserializer>(d: &mut D) -> Result<UDecimal, D::Error> {
let json: Json = de::Deserialize::deserialize(d)?;
#[cfg(feature = "serde-decimal")]
impl<'de> serde::Deserialize<'de> for UDecimal {
/// Deserialize an `UDecimal`.
///
/// This type is deserialized through [`strason`][1] for the same reason as
/// it's explained in the `Serialize` implementation.
///
/// [1]: https://github.com/apoelstra/strason
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let json = Json::deserialize(deserializer)?;
match json.num() {
Some(s) => {
// We know this will be a well-formed Json number, so we can
@ -283,16 +298,33 @@ impl de::Deserialize for UDecimal {
exponent: exponent,
})
}
None => Err(de::Error::syntax("expected decimal, got non-numeric"))
None => Err(serde::de::Error::custom("expected decimal, got non-numeric"))
}
}
}
#[cfg(feature = "serde-decimal")]
impl serde::Serialize for UDecimal {
/// Serialize an `UDecimal`.
///
/// This type is serialized through [`strason`][1] since it will not lose
/// precision (when serializing to [`strason`][1] itself, the value will be
/// passed through; otherwise it will be encoded as a string).
///
/// [1]: https://github.com/apoelstra/strason
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let json = Json::from_str(&self.to_string()).unwrap();
json.serialize(serializer)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(feature = "serde-decimal")]
use strason::Json;
#[test]
@ -326,6 +358,7 @@ mod tests {
assert_eq!(u.integer_value(8), 123456780000);
}
#[cfg(feature = "serde-decimal")]
macro_rules! deserialize_round_trip(
($dec:expr, $s:expr) => ({
let d = $dec;
@ -342,6 +375,7 @@ mod tests {
);
#[test]
#[cfg(feature = "serde-decimal")]
fn deserialize() {
deserialize_round_trip!(Decimal::new(0, 0), b"0.0");
deserialize_round_trip!(UDecimal::new(0, 0), b"0.0");
@ -412,6 +446,7 @@ mod tests {
}
#[test]
#[cfg(feature = "serde-decimal")]
fn json_parse() {
let json = Json::from_str("0.00980000").unwrap();
assert_eq!(json.to_bytes(), b"0.00980000");
@ -434,5 +469,3 @@ mod tests {
assert_eq!(dec, UDecimal::new(98000, 7));
}
}

View File

@ -22,7 +22,7 @@ use std::error;
use std::fmt;
use std::io::Cursor;
use std::mem;
use serde;
#[cfg(feature = "serde")] use serde;
use byteorder::{LittleEndian, WriteBytesExt};
use crypto::digest::Digest;
@ -307,50 +307,73 @@ impl Sha256dHash {
}
}
// Note that this outputs hashes as big endian hex numbers, so this should be
// used only for user-facing stuff. Internal and network serialization is
// little-endian and should be done using the consensus `encodable::ConsensusEncodable`
// interface.
impl serde::Serialize for Sha256dHash {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: serde::Serializer,
{
unsafe {
use std::{char, str};
let mut string = [0; 64];
for i in 0..32 {
string[2 * i] = char::from_digit((self.0[31 - i] / 0x10) as u32, 16).unwrap() as u8;
string[2 * i + 1] = char::from_digit((self.0[31 - i] & 0x0f) as u32, 16).unwrap() as u8;
}
serializer.visit_str(str::from_utf8_unchecked(&string))
}
}
}
impl serde::Deserialize for Sha256dHash {
#[cfg(feature = "serde")]
impl<'de> serde::Deserialize<'de> for Sha256dHash {
#[inline]
fn deserialize<D>(d: &mut D) -> Result<Sha256dHash, D::Error>
where D: serde::Deserializer
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
struct Sha256dHashVisitor;
impl serde::de::Visitor for Sha256dHashVisitor {
use std::fmt::{self, Formatter};
struct Visitor;
impl<'de> serde::de::Visitor<'de> for Visitor {
type Value = Sha256dHash;
fn visit_string<E>(&mut self, v: String) -> Result<Sha256dHash, E>
where E: serde::de::Error
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
formatter.write_str("a SHA256d hash")
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Sha256dHash::from_hex(v).map_err(E::custom)
}
fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
self.visit_str(v)
}
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
self.visit_str(&v)
}
fn visit_str<E>(&mut self, hex_str: &str) -> Result<Sha256dHash, E>
where E: serde::de::Error
{
Sha256dHash::from_hex(hex_str).map_err(|e| serde::de::Error::syntax(&e.to_string()))
}
}
d.visit(Sha256dHashVisitor)
deserializer.deserialize_str(Visitor)
}
}
#[cfg(feature = "serde")]
impl serde::Serialize for Sha256dHash {
/// Serialize a `Sha256dHash`.
///
/// Note that this outputs hashes as big endian hex numbers, so this should be
/// used only for user-facing stuff. Internal and network serialization is
/// little-endian and should be done using the consensus
/// [`ConsensusEncodable`][1] interface.
///
/// [1]: ../../network/encodable/trait.ConsensusEncodable.html
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
use std::{char, str};
let mut string = [0; 64];
for i in 0..32 {
string[2 * i] = char::from_digit((self.0[31 - i] / 0x10) as u32, 16).unwrap() as u8;
string[2 * i + 1] = char::from_digit((self.0[31 - i] & 0x0f) as u32, 16).unwrap() as u8;
}
let hex_str = unsafe { str::from_utf8_unchecked(&string) };
serializer.serialize_str(hex_str)
}
}
@ -456,7 +479,8 @@ impl <T: BitcoinHash> MerkleRoot for Vec<T> {
#[cfg(test)]
mod tests {
use strason;
#[cfg(all(feature = "serde", feature = "strason"))]
use strason::Json;
use network::encodable::{ConsensusEncodable, VarInt};
use network::serialize::{serialize, deserialize};
@ -539,9 +563,10 @@ mod tests {
}
#[test]
#[cfg(all(feature = "serde", feature = "strason"))]
fn test_hash_encode_decode() {
let hash = Sha256dHash::from_data(&[]);
let encoded = strason::from_serialize(&hash).unwrap();
let encoded = Json::from_serialize(&hash).unwrap();
assert_eq!(encoded.to_bytes(),
"\"56944c5d3f98413ef45cf54545538103cc9f298e0575820ad3591376e2e0f65d\"".as_bytes());
let decoded = encoded.into_deserialize().unwrap();