diff --git a/bitcoin/src/address.rs b/bitcoin/src/address.rs index 60979836..5fe1cc88 100644 --- a/bitcoin/src/address.rs +++ b/bitcoin/src/address.rs @@ -39,7 +39,6 @@ use crate::blockdata::{opcodes, script}; use crate::error::ParseIntError; use crate::hash_types::{PubkeyHash, ScriptHash}; use crate::hashes::{sha256, Hash, HashEngine}; -use crate::internal_macros::serde_string_impl; use crate::network::constants::Network; use crate::prelude::*; use crate::util::base58; @@ -565,7 +564,8 @@ pub struct Address { /// The network on which this address is usable. pub network: Network, } -serde_string_impl!(Address, "a Bitcoin address"); +#[cfg(feature = "serde")] +crate::serde_utils::serde_string_impl!(Address, "a Bitcoin address"); impl Address { /// Creates a pay to (compressed) public key hash address from a public key. diff --git a/bitcoin/src/bip32.rs b/bitcoin/src/bip32.rs index 844c6d06..d31a969e 100644 --- a/bitcoin/src/bip32.rs +++ b/bitcoin/src/bip32.rs @@ -19,7 +19,7 @@ use serde; use crate::hash_types::XpubIdentifier; use crate::hashes::{hex, sha512, Hash, HashEngine, Hmac, HmacEngine}; -use crate::internal_macros::{impl_bytes_newtype, serde_string_impl}; +use crate::internal_macros::impl_bytes_newtype; use crate::io::Write; use crate::network::constants::Network; use crate::prelude::*; @@ -55,7 +55,8 @@ pub struct ExtendedPrivKey { /// Chain code pub chain_code: ChainCode, } -serde_string_impl!(ExtendedPrivKey, "a BIP-32 extended private key"); +#[cfg(feature = "serde")] +crate::serde_utils::serde_string_impl!(ExtendedPrivKey, "a BIP-32 extended private key"); #[cfg(not(feature = "std"))] #[cfg_attr(docsrs, doc(cfg(not(feature = "std"))))] @@ -88,7 +89,8 @@ pub struct ExtendedPubKey { /// Chain code pub chain_code: ChainCode, } -serde_string_impl!(ExtendedPubKey, "a BIP-32 extended public key"); +#[cfg(feature = "serde")] +crate::serde_utils::serde_string_impl!(ExtendedPubKey, "a BIP-32 extended public key"); /// A child number for a derived key #[derive(Copy, Clone, PartialEq, Eq, Debug, PartialOrd, Ord, Hash)] @@ -233,7 +235,9 @@ pub trait IntoDerivationPath { /// A BIP-32 derivation path. #[derive(Clone, PartialEq, Eq, Ord, PartialOrd, Hash)] pub struct DerivationPath(Vec); -serde_string_impl!(DerivationPath, "a BIP-32 derivation path"); + +#[cfg(feature = "serde")] +crate::serde_utils::serde_string_impl!(DerivationPath, "a BIP-32 derivation path"); impl Index for DerivationPath where diff --git a/bitcoin/src/blockdata/transaction.rs b/bitcoin/src/blockdata/transaction.rs index 9569c5b7..1a432cd9 100644 --- a/bitcoin/src/blockdata/transaction.rs +++ b/bitcoin/src/blockdata/transaction.rs @@ -32,7 +32,7 @@ use crate::blockdata::locktime::relative; use crate::consensus::{encode, Decodable, Encodable}; use crate::hash_types::{Sighash, Txid, Wtxid}; use crate::VarInt; -use crate::internal_macros::{impl_consensus_encoding, serde_struct_human_string_impl}; +use crate::internal_macros::impl_consensus_encoding; use crate::parse::impl_parse_str_through_int; #[cfg(doc)] @@ -50,7 +50,8 @@ pub struct OutPoint { /// The index of the referenced output in its transaction's vout. pub vout: u32, } -serde_struct_human_string_impl!(OutPoint, "an OutPoint", txid, vout); +#[cfg(feature = "serde")] +crate::serde_utils::serde_struct_human_string_impl!(OutPoint, "an OutPoint", txid, vout); impl OutPoint { /// Creates a new [`OutPoint`]. diff --git a/bitcoin/src/internal_macros.rs b/bitcoin/src/internal_macros.rs index b2ff27e7..08325e99 100644 --- a/bitcoin/src/internal_macros.rs +++ b/bitcoin/src/internal_macros.rs @@ -110,227 +110,6 @@ mod test_macros { pub(crate) use hex_decode; } -macro_rules! serde_string_impl { - ($name:ident, $expecting:literal) => { - #[cfg(feature = "serde")] - #[cfg_attr(docsrs, doc(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>, - { - use core::fmt::{self, Formatter}; - use core::str::FromStr; - - struct Visitor; - impl<'de> $crate::serde::de::Visitor<'de> for Visitor { - type Value = $name; - - fn expecting(&self, f: &mut Formatter) -> fmt::Result { - f.write_str($expecting) - } - - fn visit_str(self, v: &str) -> Result - where - E: $crate::serde::de::Error, - { - $name::from_str(v).map_err(E::custom) - } - } - - deserializer.deserialize_str(Visitor) - } - } - - #[cfg(feature = "serde")] - #[cfg_attr(docsrs, doc(cfg(feature = "serde")))] - impl $crate::serde::Serialize for $name { - fn serialize(&self, serializer: S) -> Result - where - S: $crate::serde::Serializer, - { - serializer.collect_str(&self) - } - } - }; -} -pub(crate) use serde_string_impl; - -/// A combination macro where the human-readable serialization is done like -/// serde_string_impl and the non-human-readable impl is done as a struct. -macro_rules! serde_struct_human_string_impl { - ($name:ident, $expecting:literal, $($fe:ident),*) => ( - #[cfg(feature = "serde")] - #[cfg_attr(docsrs, doc(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 core::fmt::{self, Formatter}; - use core::str::FromStr; - - struct Visitor; - impl<'de> $crate::serde::de::Visitor<'de> for Visitor { - type Value = $name; - - fn expecting(&self, f: &mut Formatter) -> fmt::Result { - f.write_str($expecting) - } - - fn visit_str(self, v: &str) -> Result - where - E: $crate::serde::de::Error, - { - $name::from_str(v).map_err(E::custom) - } - - } - - deserializer.deserialize_str(Visitor) - } else { - use core::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, f: &mut Formatter) -> fmt::Result { - f.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, f: &mut Formatter) -> fmt::Result { - f.write_str("a struct") - } - - fn visit_seq(self, mut seq: V) -> Result - where - V: $crate::serde::de::SeqAccess<'de>, - { - use $crate::serde::de::Error; - - let length = 0; - $( - let $fe = seq.next_element()?.ok_or_else(|| { - Error::invalid_length(length, &self) - })?; - #[allow(unused_variables)] - let length = length + 1; - )* - - let ret = $name { - $($fe),* - }; - - Ok(ret) - } - - 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),* - }; - - Ok(ret) - } - } - // end type defs - - static FIELDS: &'static [&'static str] = &[$(stringify!($fe)),*]; - - deserializer.deserialize_struct(stringify!($name), FIELDS, Visitor) - } - } - } - - #[cfg(feature = "serde")] - #[cfg_attr(docsrs, doc(cfg(feature = "serde")))] - impl $crate::serde::Serialize for $name { - fn serialize(&self, serializer: S) -> Result - where - S: $crate::serde::Serializer, - { - if serializer.is_human_readable() { - serializer.collect_str(&self) - } 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() - } - } - } - ) -} -pub(crate) use serde_struct_human_string_impl; - /// Implements several traits for byte-based newtypes. /// Implements: /// - core::fmt::LowerHex (implies hashes::hex::ToHex) diff --git a/bitcoin/src/serde_utils.rs b/bitcoin/src/serde_utils.rs index 3c990b0d..9974b9fb 100644 --- a/bitcoin/src/serde_utils.rs +++ b/bitcoin/src/serde_utils.rs @@ -293,3 +293,216 @@ pub mod hex_bytes { } } } + +macro_rules! serde_string_impl { + ($name:ident, $expecting:literal) => { + impl<'de> $crate::serde::Deserialize<'de> for $name { + fn deserialize(deserializer: D) -> Result<$name, D::Error> + where + D: $crate::serde::de::Deserializer<'de>, + { + use core::fmt::{self, Formatter}; + use core::str::FromStr; + + struct Visitor; + impl<'de> $crate::serde::de::Visitor<'de> for Visitor { + type Value = $name; + + fn expecting(&self, f: &mut Formatter) -> fmt::Result { + f.write_str($expecting) + } + + fn visit_str(self, v: &str) -> Result + where + E: $crate::serde::de::Error, + { + $name::from_str(v).map_err(E::custom) + } + } + + deserializer.deserialize_str(Visitor) + } + } + + impl $crate::serde::Serialize for $name { + fn serialize(&self, serializer: S) -> Result + where + S: $crate::serde::Serializer, + { + serializer.collect_str(&self) + } + } + }; +} +pub(crate) use serde_string_impl; + +/// A combination macro where the human-readable serialization is done like +/// serde_string_impl and the non-human-readable impl is done as a struct. +macro_rules! serde_struct_human_string_impl { + ($name:ident, $expecting:literal, $($fe:ident),*) => ( + 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 core::fmt::{self, Formatter}; + use core::str::FromStr; + + struct Visitor; + impl<'de> $crate::serde::de::Visitor<'de> for Visitor { + type Value = $name; + + fn expecting(&self, f: &mut Formatter) -> fmt::Result { + f.write_str($expecting) + } + + fn visit_str(self, v: &str) -> Result + where + E: $crate::serde::de::Error, + { + $name::from_str(v).map_err(E::custom) + } + + } + + deserializer.deserialize_str(Visitor) + } else { + use core::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, f: &mut Formatter) -> fmt::Result { + f.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, f: &mut Formatter) -> fmt::Result { + f.write_str("a struct") + } + + fn visit_seq(self, mut seq: V) -> Result + where + V: $crate::serde::de::SeqAccess<'de>, + { + use $crate::serde::de::Error; + + let length = 0; + $( + let $fe = seq.next_element()?.ok_or_else(|| { + Error::invalid_length(length, &self) + })?; + #[allow(unused_variables)] + let length = length + 1; + )* + + let ret = $name { + $($fe),* + }; + + Ok(ret) + } + + 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),* + }; + + Ok(ret) + } + } + // end type defs + + static FIELDS: &'static [&'static str] = &[$(stringify!($fe)),*]; + + deserializer.deserialize_struct(stringify!($name), FIELDS, Visitor) + } + } + } + + impl $crate::serde::Serialize for $name { + fn serialize(&self, serializer: S) -> Result + where + S: $crate::serde::Serializer, + { + if serializer.is_human_readable() { + serializer.collect_str(&self) + } 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() + } + } + } + ) +} +pub(crate) use serde_struct_human_string_impl; diff --git a/bitcoin/src/util/sighash.rs b/bitcoin/src/util/sighash.rs index e08b5476..cbf31c11 100644 --- a/bitcoin/src/util/sighash.rs +++ b/bitcoin/src/util/sighash.rs @@ -19,7 +19,6 @@ use crate::consensus::{encode, Encodable}; use crate::error::impl_std_error; use crate::util::endian; use crate::hashes::{sha256, sha256d, Hash}; -use crate::internal_macros::serde_string_impl; use crate::prelude::*; use crate::util::taproot::{TapLeafHash, TAPROOT_ANNEX_PREFIX, TapSighashHash, LeafVersion}; @@ -121,7 +120,8 @@ pub enum SchnorrSighashType { /// 0x83: Sign one output and only this input (see `Single` for what "one output" means). SinglePlusAnyoneCanPay = 0x83, } -serde_string_impl!(SchnorrSighashType, "a SchnorrSighashType data"); +#[cfg(feature = "serde")] +crate::serde_utils::serde_string_impl!(SchnorrSighashType, "a SchnorrSighashType data"); impl fmt::Display for SchnorrSighashType { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -318,7 +318,8 @@ pub enum EcdsaSighashType { /// 0x83: Sign one output and only this input (see `Single` for what "one output" means). SinglePlusAnyoneCanPay = 0x83 } -serde_string_impl!(EcdsaSighashType, "a EcdsaSighashType data"); +#[cfg(feature = "serde")] +crate::serde_utils::serde_string_impl!(EcdsaSighashType, "a EcdsaSighashType data"); impl fmt::Display for EcdsaSighashType { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {