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 test --verbose
|
||||||
- cargo build --verbose --features=bitcoinconsensus
|
- cargo build --verbose --features=bitcoinconsensus
|
||||||
- cargo test --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
|
- 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]
|
[features]
|
||||||
fuzztarget = ["secp256k1/fuzztarget"]
|
fuzztarget = ["secp256k1/fuzztarget"]
|
||||||
|
serde-decimal = ["serde", "strason"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bitcoin-bech32 = "0.8.0"
|
bitcoin-bech32 = "0.8.0"
|
||||||
byteorder = "1.1"
|
byteorder = "1.1"
|
||||||
rand = "0.3"
|
rand = "0.3"
|
||||||
rust-crypto = "0.2"
|
rust-crypto = "0.2"
|
||||||
serde = "0.6"
|
|
||||||
strason = "0.3"
|
|
||||||
bitcoinconsensus = { version = "0.16", optional = true }
|
bitcoinconsensus = { version = "0.16", optional = true }
|
||||||
|
|
||||||
|
[dependencies.serde]
|
||||||
|
version = "1"
|
||||||
|
optional = true
|
||||||
|
|
||||||
|
[dependencies.strason]
|
||||||
|
version = "0.4"
|
||||||
|
optional = true
|
||||||
|
default-features = false
|
||||||
|
|
||||||
[dependencies.hex]
|
[dependencies.hex]
|
||||||
git = "https://github.com/KokaKiwi/rust-hex"
|
git = "https://github.com/KokaKiwi/rust-hex"
|
||||||
rev = "19fd37137686c30058bd9d11d21590e726ffdf31"
|
rev = "19fd37137686c30058bd9d11d21590e726ffdf31"
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
|
|
||||||
#![allow(non_camel_case_types)]
|
#![allow(non_camel_case_types)]
|
||||||
|
|
||||||
use serde;
|
#[cfg(feature = "serde")] use serde;
|
||||||
|
|
||||||
// Heavy stick to translate between opcode types
|
// Heavy stick to translate between opcode types
|
||||||
use std::mem::transmute;
|
use std::mem::transmute;
|
||||||
|
@ -620,11 +620,13 @@ impl<S: SimpleEncoder> ConsensusEncodable<S> for All {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "serde")]
|
||||||
impl serde::Serialize for All {
|
impl serde::Serialize for All {
|
||||||
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where S: serde::Serializer,
|
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);
|
display_from_debug!(Class);
|
||||||
|
|
||||||
|
#[cfg(feature = "serde")]
|
||||||
impl serde::Serialize for Class {
|
impl serde::Serialize for Class {
|
||||||
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where S: serde::Serializer,
|
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 std::{error, fmt};
|
||||||
|
|
||||||
use crypto::digest::Digest;
|
use crypto::digest::Digest;
|
||||||
use serde;
|
#[cfg(feature = "serde")] use serde;
|
||||||
|
|
||||||
use blockdata::opcodes;
|
use blockdata::opcodes;
|
||||||
use network::encodable::{ConsensusDecodable, ConsensusEncodable};
|
use network::encodable::{ConsensusDecodable, ConsensusEncodable};
|
||||||
|
@ -561,39 +561,57 @@ impl From<Vec<u8>> for Builder {
|
||||||
|
|
||||||
impl_index_newtype!(Builder, u8);
|
impl_index_newtype!(Builder, u8);
|
||||||
|
|
||||||
// User-facing serialization
|
#[cfg(feature = "serde")]
|
||||||
impl serde::Serialize for Script {
|
impl<'de> serde::Deserialize<'de> for Script {
|
||||||
fn serialize<S>(&self, s: &mut S) -> Result<(), S::Error>
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
where S: serde::Serializer,
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
{
|
{
|
||||||
s.visit_str(&format!("{:x}", self))
|
use std::fmt::{self, Formatter};
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl serde::Deserialize for Script {
|
struct Visitor;
|
||||||
fn deserialize<D>(d: &mut D) -> Result<Script, D::Error>
|
impl<'de> serde::de::Visitor<'de> for Visitor {
|
||||||
where D: serde::Deserializer
|
|
||||||
{
|
|
||||||
struct ScriptVisitor;
|
|
||||||
impl serde::de::Visitor for ScriptVisitor {
|
|
||||||
type Value = Script;
|
type Value = Script;
|
||||||
|
|
||||||
fn visit_string<E>(&mut self, v: String) -> Result<Script, E>
|
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
|
||||||
where E: serde::de::Error
|
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)
|
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]
|
#[test]
|
||||||
|
#[cfg(all(feature = "serde", feature = "strason"))]
|
||||||
fn script_json_serialize() {
|
fn script_json_serialize() {
|
||||||
use strason;
|
use strason::Json;
|
||||||
|
|
||||||
let original = hex_script!("827651a0698faaa9a8a7a687");
|
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.to_bytes(), b"\"827651a0698faaa9a8a7a687\"");
|
||||||
assert_eq!(json.string(), Some("827651a0698faaa9a8a7a687"));
|
assert_eq!(json.string(), Some("827651a0698faaa9a8a7a687"));
|
||||||
let des = json.into_deserialize().unwrap();
|
let des = json.into_deserialize().unwrap();
|
||||||
|
|
|
@ -27,7 +27,6 @@ use byteorder::{LittleEndian, WriteBytesExt};
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
#[cfg(feature="bitcoinconsensus")] use std::collections::HashMap;
|
#[cfg(feature="bitcoinconsensus")] use std::collections::HashMap;
|
||||||
use serde;
|
|
||||||
|
|
||||||
use util::hash::Sha256dHash;
|
use util::hash::Sha256dHash;
|
||||||
#[cfg(feature="bitcoinconsensus")] use blockdata::script;
|
#[cfg(feature="bitcoinconsensus")] use blockdata::script;
|
||||||
|
@ -442,13 +441,16 @@ impl SigHashType {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use strason;
|
#[cfg(all(feature = "serde", feature = "strason"))]
|
||||||
|
use strason::Json;
|
||||||
|
|
||||||
use super::{Transaction, TxIn};
|
use super::{Transaction, TxIn};
|
||||||
|
|
||||||
use blockdata::script::Script;
|
use blockdata::script::Script;
|
||||||
use network::serialize::BitcoinHash;
|
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::hash::Sha256dHash;
|
||||||
use util::misc::hex_bytes;
|
use util::misc::hex_bytes;
|
||||||
|
|
||||||
|
@ -563,11 +565,12 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg(all(feature = "serde", feature = "strason"))]
|
||||||
fn test_txn_encode_decode() {
|
fn test_txn_encode_decode() {
|
||||||
let hex_tx = hex_bytes("0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000").unwrap();
|
let hex_tx = hex_bytes("0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000").unwrap();
|
||||||
let tx: Transaction = deserialize(&hex_tx).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();
|
let decoded = encoded.into_deserialize().unwrap();
|
||||||
assert_eq!(tx, decoded);
|
assert_eq!(tx, decoded);
|
||||||
}
|
}
|
||||||
|
@ -586,12 +589,13 @@ mod tests {
|
||||||
// Test decoding transaction `4be105f158ea44aec57bf12c5817d073a712ab131df6f37786872cfc70734188`
|
// Test decoding transaction `4be105f158ea44aec57bf12c5817d073a712ab131df6f37786872cfc70734188`
|
||||||
// from testnet, which is the first BIP144-encoded transaction I encountered.
|
// from testnet, which is the first BIP144-encoded transaction I encountered.
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg(all(feature = "serde", feature = "strason"))]
|
||||||
fn test_segwit_tx_decode() {
|
fn test_segwit_tx_decode() {
|
||||||
let hex_tx = hex_bytes("010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff3603da1b0e00045503bd5704c7dd8a0d0ced13bb5785010800000000000a636b706f6f6c122f4e696e6a61506f6f6c2f5345475749542fffffffff02b4e5a212000000001976a914876fbb82ec05caa6af7a3b5e5a983aae6c6cc6d688ac0000000000000000266a24aa21a9edf91c46b49eb8a29089980f02ee6b57e7d63d33b18b4fddac2bcd7db2a39837040120000000000000000000000000000000000000000000000000000000000000000000000000").unwrap();
|
let hex_tx = hex_bytes("010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff3603da1b0e00045503bd5704c7dd8a0d0ced13bb5785010800000000000a636b706f6f6c122f4e696e6a61506f6f6c2f5345475749542fffffffff02b4e5a212000000001976a914876fbb82ec05caa6af7a3b5e5a983aae6c6cc6d688ac0000000000000000266a24aa21a9edf91c46b49eb8a29089980f02ee6b57e7d63d33b18b4fddac2bcd7db2a39837040120000000000000000000000000000000000000000000000000000000000000000000000000").unwrap();
|
||||||
let tx: Transaction = deserialize(&hex_tx).unwrap();
|
let tx: Transaction = deserialize(&hex_tx).unwrap();
|
||||||
assert_eq!(tx.get_weight(), 780);
|
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();
|
let decoded = encoded.into_deserialize().unwrap();
|
||||||
assert_eq!(tx, decoded);
|
assert_eq!(tx, decoded);
|
||||||
|
|
||||||
|
|
|
@ -173,47 +173,50 @@ macro_rules! impl_array_newtype {
|
||||||
|
|
||||||
macro_rules! impl_array_newtype_encodable {
|
macro_rules! impl_array_newtype_encodable {
|
||||||
($thing:ident, $ty:ty, $len:expr) => {
|
($thing:ident, $ty:ty, $len:expr) => {
|
||||||
|
#[cfg(feature = "serde")]
|
||||||
impl ::serde::Deserialize for $thing {
|
impl<'de> $crate::serde::Deserialize<'de> for $thing {
|
||||||
fn deserialize<D>(d: &mut D) -> Result<$thing, D::Error>
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
where D: ::serde::Deserializer
|
where
|
||||||
|
D: $crate::serde::Deserializer<'de>,
|
||||||
{
|
{
|
||||||
// We have to define the Visitor struct inside the function
|
use $crate::std::fmt::{self, Formatter};
|
||||||
// to make it local ... what we really need is that it's
|
|
||||||
// local to the macro, but this is Close Enough.
|
struct Visitor;
|
||||||
struct Visitor {
|
impl<'de> $crate::serde::de::Visitor<'de> for Visitor {
|
||||||
marker: ::std::marker::PhantomData<$thing>,
|
|
||||||
}
|
|
||||||
impl ::serde::de::Visitor for Visitor {
|
|
||||||
type Value = $thing;
|
type Value = $thing;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
|
||||||
|
formatter.write_str("a fixed size array")
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn visit_seq<V>(&mut self, mut v: V) -> Result<$thing, V::Error>
|
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
|
||||||
where V: ::serde::de::SeqVisitor
|
where
|
||||||
|
A: $crate::serde::de::SeqAccess<'de>,
|
||||||
{
|
{
|
||||||
let mut ret: [$ty; $len] = [0; $len];
|
let mut ret: [$ty; $len] = [0; $len];
|
||||||
for item in ret.iter_mut() {
|
for item in ret.iter_mut() {
|
||||||
*item = match v.visit()? {
|
*item = match seq.next_element()? {
|
||||||
Some(c) => c,
|
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))
|
Ok($thing(ret))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Begin actual function
|
deserializer.deserialize_seq(Visitor)
|
||||||
d.visit(Visitor { marker: ::std::marker::PhantomData })
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::serde::Serialize for $thing {
|
#[cfg(feature = "serde")]
|
||||||
fn serialize<S>(&self, s: &mut S) -> Result<(), S::Error>
|
impl $crate::serde::Serialize for $thing {
|
||||||
where S: ::serde::Serializer
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: $crate::serde::Serializer,
|
||||||
{
|
{
|
||||||
let &$thing(ref dat) = self;
|
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)]
|
#[cfg(test)]
|
||||||
macro_rules! hex_hash (($s:expr) => (::util::hash::Sha256dHash::from(&::hex::decode($s).unwrap()[..])));
|
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 {
|
macro_rules! serde_struct_impl {
|
||||||
($name:ident, $($fe:ident $(<- $alt:expr)*),*) => (
|
($name:ident, $($fe:ident),*) => (
|
||||||
impl ::serde::Deserialize for $name {
|
#[cfg(feature = "serde")]
|
||||||
fn deserialize<D>(deserializer: &mut D) -> Result<$name, D::Error>
|
impl<'de> $crate::serde::Deserialize<'de> for $name {
|
||||||
where D: serde::de::Deserializer
|
fn deserialize<D>(deserializer: D) -> Result<$name, D::Error>
|
||||||
|
where
|
||||||
|
D: $crate::serde::de::Deserializer<'de>,
|
||||||
{
|
{
|
||||||
// begin type defs
|
use $crate::std::fmt::{self, Formatter};
|
||||||
__rust_jsonrpc_internal__define_anything_type!();
|
use $crate::serde::de::IgnoredAny;
|
||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
enum Enum { Unknown__Field, $($fe),* }
|
enum Enum { Unknown__Field, $($fe),* }
|
||||||
|
|
||||||
struct EnumVisitor;
|
struct EnumVisitor;
|
||||||
impl ::serde::de::Visitor for EnumVisitor {
|
impl<'de> $crate::serde::de::Visitor<'de> for EnumVisitor {
|
||||||
type Value = Enum;
|
type Value = Enum;
|
||||||
|
|
||||||
fn visit_str<E>(&mut self, value: &str) -> Result<Enum, E>
|
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
|
||||||
where E: ::serde::de::Error
|
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)
|
stringify!($fe) => Ok(Enum::$fe)
|
||||||
$(, $alt => Ok(Enum::$fe))*
|
|
||||||
),*,
|
),*,
|
||||||
_ => Ok(Enum::Unknown__Field)
|
_ => Ok(Enum::Unknown__Field)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::serde::Deserialize for Enum {
|
impl<'de> $crate::serde::Deserialize<'de> for Enum {
|
||||||
fn deserialize<D>(deserializer: &mut D) -> Result<Enum, D::Error>
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
where D: ::serde::de::Deserializer
|
where
|
||||||
|
D: ::serde::de::Deserializer<'de>,
|
||||||
{
|
{
|
||||||
deserializer.visit_str(EnumVisitor)
|
deserializer.deserialize_str(EnumVisitor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Visitor;
|
struct Visitor;
|
||||||
|
|
||||||
impl ::serde::de::Visitor for Visitor {
|
impl<'de> $crate::serde::de::Visitor<'de> for Visitor {
|
||||||
type Value = $name;
|
type Value = $name;
|
||||||
|
|
||||||
fn visit_map<V>(&mut self, mut v: V) -> Result<$name, V::Error>
|
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
|
||||||
where V: ::serde::de::MapVisitor
|
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;)*
|
$(let mut $fe = None;)*
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
match v.visit_key()? {
|
match map.next_key::<Enum>()? {
|
||||||
Some(Enum::Unknown__Field) => { let _: Anything = v.visit_value()?; }
|
Some(Enum::Unknown__Field) => {
|
||||||
$(Some(Enum::$fe) => { $fe = Some(v.visit_value()?); })*
|
map.next_value::<IgnoredAny>()?;
|
||||||
|
}
|
||||||
|
$(
|
||||||
|
Some(Enum::$fe) => {
|
||||||
|
$fe = Some(map.next_value()?);
|
||||||
|
}
|
||||||
|
)*
|
||||||
None => { break; }
|
None => { break; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$(let $fe = match $fe {
|
$(
|
||||||
Some(x) => x,
|
let $fe = match $fe {
|
||||||
None => v.missing_field(stringify!($fe))?,
|
Some(x) => x,
|
||||||
};)*
|
None => return Err(A::Error::missing_field(stringify!($fe))),
|
||||||
v.end()?;
|
};
|
||||||
Ok($name{ $($fe: $fe),* })
|
)*
|
||||||
|
|
||||||
|
let ret = $name {
|
||||||
|
$($fe: $fe),*
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(ret)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// end type defs
|
// end type defs
|
||||||
|
|
||||||
static FIELDS: &'static [&'static str] = &[$(stringify!($fe)),*];
|
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 {
|
#[cfg(feature = "serde")]
|
||||||
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
|
impl<'de> $crate::serde::Serialize for $name {
|
||||||
where S: ::serde::Serializer
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: $crate::serde::Serializer,
|
||||||
{
|
{
|
||||||
// begin type defs
|
use $crate::serde::ser::SerializeStruct;
|
||||||
#[repr(u16)]
|
|
||||||
#[derive(Copy, Clone)]
|
|
||||||
#[allow(non_camel_case_types)]
|
|
||||||
#[allow(dead_code)]
|
|
||||||
enum State { $($fe),* , Finished }
|
|
||||||
|
|
||||||
struct MapVisitor<'a> {
|
// Only used to get the struct length.
|
||||||
value: &'a $name,
|
static FIELDS: &'static [&'static str] = &[$(stringify!($fe)),*];
|
||||||
state: State,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> ::serde::ser::MapVisitor for MapVisitor<'a> {
|
let mut st = serializer.serialize_struct(stringify!($name), FIELDS.len())?;
|
||||||
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
|
|
||||||
|
|
||||||
serializer.visit_struct(stringify!($name), MapVisitor {
|
$(
|
||||||
value: self,
|
st.serialize_field(stringify!($fe), &self.$fe)?;
|
||||||
state: unsafe { ::std::mem::transmute(0u16) },
|
)*
|
||||||
})
|
|
||||||
|
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 hex;
|
||||||
extern crate rand;
|
extern crate rand;
|
||||||
extern crate secp256k1;
|
extern crate secp256k1;
|
||||||
extern crate serde;
|
#[cfg(feature = "serde")] extern crate serde;
|
||||||
extern crate strason;
|
#[cfg(feature = "strason")] extern crate strason;
|
||||||
#[cfg(all(test, feature = "unstable"))] extern crate test;
|
#[cfg(all(test, feature = "unstable"))] extern crate test;
|
||||||
#[cfg(feature="bitcoinconsensus")] extern crate bitcoinconsensus;
|
#[cfg(feature="bitcoinconsensus")] extern crate bitcoinconsensus;
|
||||||
|
|
||||||
|
@ -62,4 +62,3 @@ pub mod macros;
|
||||||
pub mod network;
|
pub mod network;
|
||||||
pub mod blockdata;
|
pub mod blockdata;
|
||||||
pub mod util;
|
pub mod util;
|
||||||
|
|
||||||
|
|
|
@ -83,7 +83,13 @@ macro_rules! nu_select {
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! user_enum {
|
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])*
|
$(#[$attr])*
|
||||||
pub enum $name {
|
pub enum $name {
|
||||||
$(#[$doc] $elem),*
|
$(#[$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]
|
#[inline]
|
||||||
fn deserialize<D>(d: &mut D) -> Result<$name, D::Error>
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
where D: ::serde::Deserializer
|
where
|
||||||
|
D: $crate::serde::Deserializer<'de>,
|
||||||
{
|
{
|
||||||
|
use $crate::std::fmt::{self, Formatter};
|
||||||
|
|
||||||
struct Visitor;
|
struct Visitor;
|
||||||
impl ::serde::de::Visitor for Visitor {
|
impl<'de> $crate::serde::de::Visitor<'de> for Visitor {
|
||||||
type Value = $name;
|
type Value = $name;
|
||||||
|
|
||||||
fn visit_string<E>(&mut self, v: String) -> Result<$name, E>
|
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
|
||||||
where E: ::serde::de::Error
|
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)
|
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 {
|
impl ::serde::Serialize for $name {
|
||||||
fn serialize<S>(&self, s: &mut S) -> Result<(), S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where S: ::serde::Serializer
|
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
|
//! Internal macros used for unit tests
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
|
#[cfg(all(feature = "serde", feature = "strason"))]
|
||||||
macro_rules! serde_round_trip (
|
macro_rules! serde_round_trip (
|
||||||
($var:expr) => ({
|
($var:expr) => ({
|
||||||
use strason;
|
use $crate::strason::Json;
|
||||||
|
|
||||||
let start = $var;
|
let start = $var;
|
||||||
let encoded = strason::from_serialize(&start).unwrap();
|
let encoded = Json::from_serialize(&start).unwrap();
|
||||||
let decoded = encoded.into_deserialize().unwrap();
|
let decoded = encoded.into_deserialize().unwrap();
|
||||||
assert_eq!(start, decoded);
|
assert_eq!(start, decoded);
|
||||||
})
|
})
|
||||||
|
|
|
@ -20,7 +20,7 @@ use std::default::Default;
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
use std::{error, fmt};
|
use std::{error, fmt};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use serde::{Serialize, Deserialize, Serializer, Deserializer};
|
#[cfg(feature = "serde")] use serde;
|
||||||
|
|
||||||
use byteorder::{BigEndian, ByteOrder, ReadBytesExt};
|
use byteorder::{BigEndian, ByteOrder, ReadBytesExt};
|
||||||
use crypto::digest::Digest;
|
use crypto::digest::Digest;
|
||||||
|
@ -167,17 +167,23 @@ impl fmt::Display for ChildNumber {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for ChildNumber {
|
#[cfg(feature = "serde")]
|
||||||
fn serialize<S: Serializer>(&self, s: &mut S) -> Result<(), S::Error> {
|
impl<'de> serde::Deserialize<'de> for ChildNumber {
|
||||||
u32::from(*self).serialize(s)
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
u32::deserialize(deserializer).map(ChildNumber::from)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deserialize for ChildNumber {
|
#[cfg(feature = "serde")]
|
||||||
fn deserialize<D: Deserializer>(d: &mut D) -> Result<ChildNumber, D::Error> {
|
impl serde::Serialize for ChildNumber {
|
||||||
let n: u32 = Deserialize::deserialize(d)?;
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
Ok(ChildNumber::from(n))
|
S: serde::Serializer,
|
||||||
|
{
|
||||||
|
u32::from(*self).serialize(serializer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -673,6 +679,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg(all(feature = "serde", feature = "strason"))]
|
||||||
pub fn encode_decode_childnumber() {
|
pub fn encode_decode_childnumber() {
|
||||||
serde_round_trip!(ChildNumber::from_normal_idx(0));
|
serde_round_trip!(ChildNumber::from_normal_idx(0));
|
||||||
serde_round_trip!(ChildNumber::from_normal_idx(1));
|
serde_round_trip!(ChildNumber::from_normal_idx(1));
|
||||||
|
|
|
@ -23,8 +23,8 @@
|
||||||
|
|
||||||
use std::{fmt, ops};
|
use std::{fmt, ops};
|
||||||
|
|
||||||
use serde::{ser, de};
|
#[cfg(feature = "serde-decimal")] use serde;
|
||||||
use strason::Json;
|
#[cfg(feature = "serde-decimal")] use strason::Json;
|
||||||
|
|
||||||
/// A fixed-point decimal type
|
/// A fixed-point decimal type
|
||||||
#[derive(Copy, Clone, Debug, Eq, Ord)]
|
#[derive(Copy, Clone, Debug, Eq, Ord)]
|
||||||
|
@ -128,20 +128,19 @@ impl Decimal {
|
||||||
pub fn nonnegative(&self) -> bool { self.mantissa >= 0 }
|
pub fn nonnegative(&self) -> bool { self.mantissa >= 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ser::Serialize for Decimal {
|
#[cfg(feature = "serde-decimal")]
|
||||||
// Serialize through strason since it will not lose precision (when serializing
|
impl<'de> serde::Deserialize<'de> for Decimal {
|
||||||
// to strason itself, the value will be passed through; otherwise it will be
|
/// Deserialize a `Decimal`.
|
||||||
// encoded as a string)
|
///
|
||||||
fn serialize<S: ser::Serializer>(&self, s: &mut S) -> Result<(), S::Error> {
|
/// This type is deserialized through [`strason`][1] for the same reason as
|
||||||
let json = Json::from_str(&self.to_string()).unwrap();
|
/// it's explained in the `Serialize` implementation.
|
||||||
ser::Serialize::serialize(&json, s)
|
///
|
||||||
}
|
/// [1]: https://github.com/apoelstra/strason
|
||||||
}
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
impl de::Deserialize for Decimal {
|
D: serde::Deserializer<'de>,
|
||||||
// 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::deserialize(deserializer)?;
|
||||||
let json: Json = de::Deserialize::deserialize(d)?;
|
|
||||||
match json.num() {
|
match json.num() {
|
||||||
Some(s) => {
|
Some(s) => {
|
||||||
// We know this will be a well-formed Json number, so we can
|
// We know this will be a well-formed Json number, so we can
|
||||||
|
@ -168,11 +167,28 @@ impl de::Deserialize for Decimal {
|
||||||
exponent: exponent,
|
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 {
|
impl PartialEq<UDecimal> for UDecimal {
|
||||||
fn eq(&self, other: &UDecimal) -> bool {
|
fn eq(&self, other: &UDecimal) -> bool {
|
||||||
|
@ -246,20 +262,19 @@ impl UDecimal {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ser::Serialize for UDecimal {
|
#[cfg(feature = "serde-decimal")]
|
||||||
// Serialize through strason since it will not lose precision (when serializing
|
impl<'de> serde::Deserialize<'de> for UDecimal {
|
||||||
// to strason itself, the value will be passed through; otherwise it will be
|
/// Deserialize an `UDecimal`.
|
||||||
// encoded as a string)
|
///
|
||||||
fn serialize<S: ser::Serializer>(&self, s: &mut S) -> Result<(), S::Error> {
|
/// This type is deserialized through [`strason`][1] for the same reason as
|
||||||
let json = Json::from_str(&self.to_string()).unwrap();
|
/// it's explained in the `Serialize` implementation.
|
||||||
ser::Serialize::serialize(&json, s)
|
///
|
||||||
}
|
/// [1]: https://github.com/apoelstra/strason
|
||||||
}
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
impl de::Deserialize for UDecimal {
|
D: serde::Deserializer<'de>,
|
||||||
// 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::deserialize(deserializer)?;
|
||||||
let json: Json = de::Deserialize::deserialize(d)?;
|
|
||||||
match json.num() {
|
match json.num() {
|
||||||
Some(s) => {
|
Some(s) => {
|
||||||
// We know this will be a well-formed Json number, so we can
|
// We know this will be a well-formed Json number, so we can
|
||||||
|
@ -283,16 +298,33 @@ impl de::Deserialize for UDecimal {
|
||||||
exponent: exponent,
|
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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
#[cfg(feature = "serde-decimal")]
|
||||||
use strason::Json;
|
use strason::Json;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -326,6 +358,7 @@ mod tests {
|
||||||
assert_eq!(u.integer_value(8), 123456780000);
|
assert_eq!(u.integer_value(8), 123456780000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "serde-decimal")]
|
||||||
macro_rules! deserialize_round_trip(
|
macro_rules! deserialize_round_trip(
|
||||||
($dec:expr, $s:expr) => ({
|
($dec:expr, $s:expr) => ({
|
||||||
let d = $dec;
|
let d = $dec;
|
||||||
|
@ -342,6 +375,7 @@ mod tests {
|
||||||
);
|
);
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg(feature = "serde-decimal")]
|
||||||
fn deserialize() {
|
fn deserialize() {
|
||||||
deserialize_round_trip!(Decimal::new(0, 0), b"0.0");
|
deserialize_round_trip!(Decimal::new(0, 0), b"0.0");
|
||||||
deserialize_round_trip!(UDecimal::new(0, 0), b"0.0");
|
deserialize_round_trip!(UDecimal::new(0, 0), b"0.0");
|
||||||
|
@ -412,6 +446,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg(feature = "serde-decimal")]
|
||||||
fn json_parse() {
|
fn json_parse() {
|
||||||
let json = Json::from_str("0.00980000").unwrap();
|
let json = Json::from_str("0.00980000").unwrap();
|
||||||
assert_eq!(json.to_bytes(), b"0.00980000");
|
assert_eq!(json.to_bytes(), b"0.00980000");
|
||||||
|
@ -434,5 +469,3 @@ mod tests {
|
||||||
assert_eq!(dec, UDecimal::new(98000, 7));
|
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::fmt;
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use serde;
|
#[cfg(feature = "serde")] use serde;
|
||||||
|
|
||||||
use byteorder::{LittleEndian, WriteBytesExt};
|
use byteorder::{LittleEndian, WriteBytesExt};
|
||||||
use crypto::digest::Digest;
|
use crypto::digest::Digest;
|
||||||
|
@ -307,50 +307,73 @@ impl Sha256dHash {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note that this outputs hashes as big endian hex numbers, so this should be
|
#[cfg(feature = "serde")]
|
||||||
// used only for user-facing stuff. Internal and network serialization is
|
impl<'de> serde::Deserialize<'de> for Sha256dHash {
|
||||||
// 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 {
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn deserialize<D>(d: &mut D) -> Result<Sha256dHash, D::Error>
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
where D: serde::Deserializer
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
{
|
{
|
||||||
struct Sha256dHashVisitor;
|
use std::fmt::{self, Formatter};
|
||||||
impl serde::de::Visitor for Sha256dHashVisitor {
|
|
||||||
|
struct Visitor;
|
||||||
|
impl<'de> serde::de::Visitor<'de> for Visitor {
|
||||||
type Value = Sha256dHash;
|
type Value = Sha256dHash;
|
||||||
|
|
||||||
fn visit_string<E>(&mut self, v: String) -> Result<Sha256dHash, E>
|
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
|
||||||
where E: serde::de::Error
|
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)
|
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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use strason;
|
#[cfg(all(feature = "serde", feature = "strason"))]
|
||||||
|
use strason::Json;
|
||||||
|
|
||||||
use network::encodable::{ConsensusEncodable, VarInt};
|
use network::encodable::{ConsensusEncodable, VarInt};
|
||||||
use network::serialize::{serialize, deserialize};
|
use network::serialize::{serialize, deserialize};
|
||||||
|
@ -539,9 +563,10 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg(all(feature = "serde", feature = "strason"))]
|
||||||
fn test_hash_encode_decode() {
|
fn test_hash_encode_decode() {
|
||||||
let hash = Sha256dHash::from_data(&[]);
|
let hash = Sha256dHash::from_data(&[]);
|
||||||
let encoded = strason::from_serialize(&hash).unwrap();
|
let encoded = Json::from_serialize(&hash).unwrap();
|
||||||
assert_eq!(encoded.to_bytes(),
|
assert_eq!(encoded.to_bytes(),
|
||||||
"\"56944c5d3f98413ef45cf54545538103cc9f298e0575820ad3591376e2e0f65d\"".as_bytes());
|
"\"56944c5d3f98413ef45cf54545538103cc9f298e0575820ad3591376e2e0f65d\"".as_bytes());
|
||||||
let decoded = encoded.into_deserialize().unwrap();
|
let decoded = encoded.into_deserialize().unwrap();
|
||||||
|
|
Loading…
Reference in New Issue