Pull serde stuff out of impl_bytelike_traits macro

The `impl_bytelike_traits` macro is public and it is used in the
`hash_newtype` macro, also public.

Currently if a user calls the `hash_newtype` macro in a crate that
depends on `hashes` without the `serde` feature enabled and with no
`serde` dependency everything works. However if the user then adds a
dependency that happens to enable the `serde` feature in `hashes` their
build will blow up because `serde` code will start getting called from
the original crate's call to `hash_newtype`.

Pull the serde stuff out of `hash_newtype` and provide a macro to
implement it `impl_serde_for_newtype`.
This commit is contained in:
Tobin C. Harding 2024-11-13 12:21:28 +11:00
parent 73e33e5808
commit 766f498b33
No known key found for this signature in database
GPG Key ID: 40BF9E4C269D6607
11 changed files with 54 additions and 5 deletions

View File

@ -62,6 +62,9 @@ hashes::hash_newtype! {
pub struct FilterHeader(sha256d::Hash); pub struct FilterHeader(sha256d::Hash);
} }
#[cfg(feature = "serde")]
hashes::impl_serde_for_newtype!(FilterHash, FilterHeader);
impl_hashencode!(FilterHash); impl_hashencode!(FilterHash);
impl_hashencode!(FilterHeader); impl_hashencode!(FilterHeader);

View File

@ -58,6 +58,9 @@ hash_newtype! {
pub struct XKeyIdentifier(hash160::Hash); pub struct XKeyIdentifier(hash160::Hash);
} }
#[cfg(feature = "serde")]
hashes::impl_serde_for_newtype!(XKeyIdentifier);
/// Extended private key /// Extended private key
#[derive(Copy, Clone, PartialEq, Eq)] #[derive(Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(Debug))] #[cfg_attr(feature = "std", derive(Debug))]

View File

@ -92,6 +92,10 @@ hashes::hash_newtype! {
/// SegWit version of a Bitcoin Script bytecode hash. /// SegWit version of a Bitcoin Script bytecode hash.
pub struct WScriptHash(sha256::Hash); pub struct WScriptHash(sha256::Hash);
} }
#[cfg(feature = "serde")]
hashes::impl_serde_for_newtype!(ScriptHash, WScriptHash);
impl_asref_push_bytes!(ScriptHash, WScriptHash); impl_asref_push_bytes!(ScriptHash, WScriptHash);
impl ScriptHash { impl ScriptHash {

View File

@ -264,6 +264,10 @@ hashes::hash_newtype! {
/// SegWit version of a public key hash. /// SegWit version of a public key hash.
pub struct WPubkeyHash(hash160::Hash); pub struct WPubkeyHash(hash160::Hash);
} }
#[cfg(feature = "serde")]
hashes::impl_serde_for_newtype!(PubkeyHash, WPubkeyHash);
impl_asref_push_bytes!(PubkeyHash, WPubkeyHash); impl_asref_push_bytes!(PubkeyHash, WPubkeyHash);
impl From<PublicKey> for PubkeyHash { impl From<PublicKey> for PubkeyHash {

View File

@ -56,6 +56,9 @@ hash_newtype! {
pub struct SegwitV0Sighash(sha256d::Hash); pub struct SegwitV0Sighash(sha256d::Hash);
} }
#[cfg(feature = "serde")]
hashes::impl_serde_for_newtype!(LegacySighash, SegwitV0Sighash);
impl_message_from_hash!(LegacySighash); impl_message_from_hash!(LegacySighash);
impl_message_from_hash!(SegwitV0Sighash); impl_message_from_hash!(SegwitV0Sighash);
@ -82,6 +85,9 @@ hash_newtype! {
pub struct TapSighash(sha256t::Hash<TapSighashTag>); pub struct TapSighash(sha256t::Hash<TapSighashTag>);
} }
#[cfg(feature = "serde")]
hashes::impl_serde_for_newtype!(TapSighash);
impl_message_from_hash!(TapSighash); impl_message_from_hash!(TapSighash);
/// Efficiently calculates signature hash message for legacy, segwit and Taproot inputs. /// Efficiently calculates signature hash message for legacy, segwit and Taproot inputs.

View File

@ -28,6 +28,9 @@ macro_rules! hash_trait_impls {
fn from_engine(e: HashEngine) -> Hash<$($gen),*> { Self::from_engine(e) } fn from_engine(e: HashEngine) -> Hash<$($gen),*> { Self::from_engine(e) }
} }
#[cfg(feature = "serde")]
$crate::serde_impl!(Hash, { $bits / 8} $(, $gen: $gent)*);
impl<$($gen: $gent),*> $crate::Hash for Hash<$($gen),*> { impl<$($gen: $gent),*> $crate::Hash for Hash<$($gen),*> {
type Bytes = [u8; $bits / 8]; type Bytes = [u8; $bits / 8];

View File

@ -4,6 +4,7 @@
//! //!
//! - [`sha256t_tag`](crate::sha256t_tag) //! - [`sha256t_tag`](crate::sha256t_tag)
//! - [`hash_newtype`](crate::hash_newtype) //! - [`hash_newtype`](crate::hash_newtype)
//! - [`impl_serde_for_newtype`](crate::impl_serde_for_newtype)
/// Macro used to define a tag. /// Macro used to define a tag.
/// ///
@ -71,8 +72,7 @@ macro_rules! sha256t_tag {
/// ///
/// You can add arbitrary doc comments or other attributes to the struct or it's field. Note that /// You can add arbitrary doc comments or other attributes to the struct or it's field. Note that
/// the macro already derives [`Copy`], [`Clone`], [`Eq`], [`PartialEq`], /// the macro already derives [`Copy`], [`Clone`], [`Eq`], [`PartialEq`],
/// [`Hash`](core::hash::Hash), [`Ord`], [`PartialOrd`]. With the `serde` feature on, this also adds /// [`Hash`](core::hash::Hash), [`Ord`], [`PartialOrd`].
/// `Serialize` and `Deserialize` implementations.
/// ///
/// You can also define multiple newtypes within one macro call: /// You can also define multiple newtypes within one macro call:
/// ///
@ -201,7 +201,6 @@ macro_rules! hash_newtype {
/// * `str::FromStr` /// * `str::FromStr`
/// * `fmt::{LowerHex, UpperHex}` using `hex-conservative`. /// * `fmt::{LowerHex, UpperHex}` using `hex-conservative`.
/// * `fmt::{Display, Debug}` by calling `LowerHex` /// * `fmt::{Display, Debug}` by calling `LowerHex`
/// * `serde::{Deserialize, Serialize}`
/// * `AsRef[u8; $len]` /// * `AsRef[u8; $len]`
/// * `AsRef[u8]` /// * `AsRef[u8]`
/// * `Borrow<[u8; $len]>` /// * `Borrow<[u8; $len]>`
@ -247,8 +246,6 @@ macro_rules! impl_bytelike_traits {
} }
} }
$crate::serde_impl!($ty, $len $(, $gen: $gent)*);
impl<$($gen: $gent),*> $crate::_export::_core::convert::AsRef<[u8; { $len }]> for $ty<$($gen),*> { impl<$($gen: $gent),*> $crate::_export::_core::convert::AsRef<[u8; { $len }]> for $ty<$($gen),*> {
#[inline] #[inline]
fn as_ref(&self) -> &[u8; { $len }] { self.as_byte_array() } fn as_ref(&self) -> &[u8; { $len }] { self.as_byte_array() }
@ -433,6 +430,17 @@ pub mod serde_details {
} }
} }
/// Implements `Serialize` and `Deserialize` for a new type created with [`crate::hash_newtype`] macro.
#[macro_export]
#[cfg(feature = "serde")]
macro_rules! impl_serde_for_newtype {
($($newtype:ident),*) => {
$(
$crate::serde_impl!($newtype, { <$newtype as $crate::Hash>::LEN });
)*
}
}
/// Implements `Serialize` and `Deserialize` for a type `$t` which /// Implements `Serialize` and `Deserialize` for a type `$t` which
/// represents a newtype over a byte-slice over length `$len`. /// represents a newtype over a byte-slice over length `$len`.
#[doc(hidden)] #[doc(hidden)]

View File

@ -162,6 +162,9 @@ hashes::hash_newtype! {
pub struct WitnessCommitment(sha256d::Hash); pub struct WitnessCommitment(sha256d::Hash);
} }
#[cfg(feature = "serde")]
hashes::impl_serde_for_newtype!(BlockHash, WitnessCommitment);
impl BlockHash { impl BlockHash {
/// Dummy hash used as the previous blockhash of the genesis block. /// Dummy hash used as the previous blockhash of the genesis block.
pub const GENESIS_PREVIOUS_BLOCK_HASH: Self = Self::from_byte_array([0; 32]); pub const GENESIS_PREVIOUS_BLOCK_HASH: Self = Self::from_byte_array([0; 32]);

View File

@ -10,3 +10,6 @@ hashes::hash_newtype! {
/// A hash corresponding to the Merkle tree root for witness data. /// A hash corresponding to the Merkle tree root for witness data.
pub struct WitnessMerkleNode(sha256d::Hash); pub struct WitnessMerkleNode(sha256d::Hash);
} }
#[cfg(feature = "serde")]
hashes::impl_serde_for_newtype!(TxMerkleNode, WitnessMerkleNode);

View File

@ -18,6 +18,9 @@ hash_newtype! {
pub struct TapLeafHash(sha256t::Hash<TapLeafTag>); pub struct TapLeafHash(sha256t::Hash<TapLeafTag>);
} }
#[cfg(feature = "serde")]
hashes::impl_serde_for_newtype!(TapLeafHash);
sha256t_tag! { sha256t_tag! {
pub struct TapBranchTag = hash_str("TapBranch"); pub struct TapBranchTag = hash_str("TapBranch");
} }
@ -29,6 +32,9 @@ hash_newtype! {
pub struct TapNodeHash(sha256t::Hash<TapBranchTag>); pub struct TapNodeHash(sha256t::Hash<TapBranchTag>);
} }
#[cfg(feature = "serde")]
hashes::impl_serde_for_newtype!(TapNodeHash);
sha256t_tag! { sha256t_tag! {
pub struct TapTweakTag = hash_str("TapTweak"); pub struct TapTweakTag = hash_str("TapTweak");
} }
@ -40,6 +46,9 @@ hash_newtype! {
pub struct TapTweakHash(sha256t::Hash<TapTweakTag>); pub struct TapTweakHash(sha256t::Hash<TapTweakTag>);
} }
#[cfg(feature = "serde")]
hashes::impl_serde_for_newtype!(TapTweakHash);
impl From<TapLeafHash> for TapNodeHash { impl From<TapLeafHash> for TapNodeHash {
fn from(leaf: TapLeafHash) -> TapNodeHash { TapNodeHash::from_byte_array(leaf.to_byte_array()) } fn from(leaf: TapLeafHash) -> TapNodeHash { TapNodeHash::from_byte_array(leaf.to_byte_array()) }
} }

View File

@ -476,6 +476,9 @@ hashes::hash_newtype! {
pub struct Wtxid(sha256d::Hash); pub struct Wtxid(sha256d::Hash);
} }
#[cfg(feature = "serde")]
hashes::impl_serde_for_newtype!(Txid, Wtxid);
impl Txid { impl Txid {
/// The `Txid` used in a coinbase prevout. /// The `Txid` used in a coinbase prevout.
/// ///