From ebe6ace9cee3acf9f482f5921f3e4538e80d0bae Mon Sep 17 00:00:00 2001 From: Steven Roose Date: Wed, 29 May 2019 12:34:54 +0100 Subject: [PATCH] Add human-readable serde for OutPoint as `:` --- src/blockdata/transaction.rs | 2 +- src/internal_macros.rs | 164 +++++++++++++++++++++++++++++++++++ 2 files changed, 165 insertions(+), 1 deletion(-) diff --git a/src/blockdata/transaction.rs b/src/blockdata/transaction.rs index dbe1b11173..4af85d7eda 100644 --- a/src/blockdata/transaction.rs +++ b/src/blockdata/transaction.rs @@ -45,7 +45,7 @@ pub struct OutPoint { /// The index of the referenced output in its transaction's vout pub vout: u32, } -serde_struct_impl!(OutPoint, txid, vout); +serde_struct_human_string_impl!(OutPoint, "an OutPoint", txid, vout); impl OutPoint { /// Creates a "null" `OutPoint`. diff --git a/src/internal_macros.rs b/src/internal_macros.rs index 056d905e77..648a134cad 100644 --- a/src/internal_macros.rs +++ b/src/internal_macros.rs @@ -459,6 +459,170 @@ macro_rules! serde_string_impl { }; } +/// A combination of serde_struct_impl and serde_string_impl where string is +/// used for human-readable serialization and struct is used for +/// non-human-readable serialization. +macro_rules! serde_struct_human_string_impl { + ($name:ident, $expecting:expr, $($fe:ident),*) => ( + #[cfg(feature = "serde")] + impl<'de> $crate::serde::Deserialize<'de> for $name { + fn deserialize(deserializer: D) -> Result<$name, D::Error> + where + D: $crate::serde::de::Deserializer<'de>, + { + if deserializer.is_human_readable() { + use std::fmt::{self, Formatter}; + use std::str::FromStr; + + struct Visitor; + impl<'de> $crate::serde::de::Visitor<'de> for Visitor { + type Value = $name; + + fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { + formatter.write_str($expecting) + } + + fn visit_str(self, v: &str) -> Result + where + E: $crate::serde::de::Error, + { + $name::from_str(v).map_err(E::custom) + } + + fn visit_borrowed_str(self, v: &'de str) -> Result + where + E: $crate::serde::de::Error, + { + self.visit_str(v) + } + + fn visit_string(self, v: String) -> Result + where + E: $crate::serde::de::Error, + { + self.visit_str(&v) + } + } + + deserializer.deserialize_str(Visitor) + } else { + use $crate::std::fmt::{self, Formatter}; + use $crate::serde::de::IgnoredAny; + + #[allow(non_camel_case_types)] + enum Enum { Unknown__Field, $($fe),* } + + struct EnumVisitor; + impl<'de> $crate::serde::de::Visitor<'de> for EnumVisitor { + type Value = Enum; + + fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { + formatter.write_str("a field name") + } + + fn visit_str(self, v: &str) -> Result + where + E: $crate::serde::de::Error, + { + match v { + $( + stringify!($fe) => Ok(Enum::$fe) + ),*, + _ => Ok(Enum::Unknown__Field) + } + } + } + + impl<'de> $crate::serde::Deserialize<'de> for Enum { + fn deserialize(deserializer: D) -> Result + where + D: $crate::serde::de::Deserializer<'de>, + { + deserializer.deserialize_str(EnumVisitor) + } + } + + struct Visitor; + + impl<'de> $crate::serde::de::Visitor<'de> for Visitor { + type Value = $name; + + fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { + formatter.write_str("a struct") + } + + fn visit_map(self, mut map: A) -> Result + where + A: $crate::serde::de::MapAccess<'de>, + { + use $crate::serde::de::Error; + + $(let mut $fe = None;)* + + loop { + match map.next_key::()? { + Some(Enum::Unknown__Field) => { + map.next_value::()?; + } + $( + Some(Enum::$fe) => { + $fe = Some(map.next_value()?); + } + )* + None => { break; } + } + } + + $( + 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.deserialize_struct(stringify!($name), FIELDS, Visitor) + } + } + } + + #[cfg(feature = "serde")] + impl<'de> $crate::serde::Serialize for $name { + fn serialize(&self, serializer: S) -> Result + where + S: $crate::serde::Serializer, + { + if serializer.is_human_readable() { + serializer.serialize_str(&self.to_string()) + } else { + use $crate::serde::ser::SerializeStruct; + + // Only used to get the struct length. + static FIELDS: &'static [&'static str] = &[$(stringify!($fe)),*]; + + let mut st = serializer.serialize_struct(stringify!($name), FIELDS.len())?; + + $( + st.serialize_field(stringify!($fe), &self.$fe)?; + )* + + st.end() + } + } + } + ) +} + macro_rules! user_enum { ( $(#[$attr:meta])*