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:
parent
84040caa70
commit
1b4aba1d80
|
@ -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
|
||||
|
|
12
Cargo.toml
12
Cargo.toml
|
@ -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"
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
}
|
||||
);
|
||||
|
|
|
@ -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);
|
||||
})
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
101
src/util/hash.rs
101
src/util/hash.rs
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue