From 6ba7758b30c91bbe0caebd5b373839739e51bf3e Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Tue, 7 May 2024 14:30:08 +1000 Subject: [PATCH] Improve array macros Currently we have two macros used when creating array wrapper types, one is in `internals` and the other in `bitcoin::internal_macros`. It is not immediately obvious what is what and why there are two. Improve the macros by: - Move the inherent functions to `impl_array_newtype` - Use `*_byte_array` for the names instead of `*_bytes` for functions that return arrays - Add `as_bytes` to return a slice - Add `to_bytes` to return a vector - Re-name the other macro to match what it now does --- bitcoin/src/bip152.rs | 4 ++-- bitcoin/src/bip32.rs | 6 +++--- bitcoin/src/blockdata/constants.rs | 4 ++-- bitcoin/src/internal_macros.rs | 33 +++++++++--------------------- bitcoin/src/psbt/serialize.rs | 2 +- internals/src/macros.rs | 28 +++++++++++++++++++++++++ 6 files changed, 46 insertions(+), 31 deletions(-) diff --git a/bitcoin/src/bip152.rs b/bitcoin/src/bip152.rs index 2d2c0fea0..e68e717d3 100644 --- a/bitcoin/src/bip152.rs +++ b/bitcoin/src/bip152.rs @@ -14,7 +14,7 @@ use internals::impl_array_newtype; use io::{BufRead, Write}; use crate::consensus::encode::{self, Decodable, Encodable, VarInt}; -use crate::internal_macros::{impl_bytes_newtype, impl_consensus_encoding}; +use crate::internal_macros::{impl_array_newtype_stringify, impl_consensus_encoding}; use crate::prelude::*; use crate::{block, Block, BlockHash, Transaction}; @@ -95,7 +95,7 @@ impl Decodable for PrefilledTransaction { #[derive(PartialEq, Eq, Clone, Copy, Hash, Default, PartialOrd, Ord)] pub struct ShortId([u8; 6]); impl_array_newtype!(ShortId, u8, 6); -impl_bytes_newtype!(ShortId, 6); +impl_array_newtype_stringify!(ShortId, 6); impl ShortId { /// Calculate the SipHash24 keys used to calculate short IDs. diff --git a/bitcoin/src/bip32.rs b/bitcoin/src/bip32.rs index 1014ffdc7..fda920ae8 100644 --- a/bitcoin/src/bip32.rs +++ b/bitcoin/src/bip32.rs @@ -16,7 +16,7 @@ use io::Write; use secp256k1::{Secp256k1, XOnlyPublicKey}; use crate::crypto::key::{CompressedPublicKey, Keypair, PrivateKey}; -use crate::internal_macros::impl_bytes_newtype; +use crate::internal_macros::impl_array_newtype_stringify; use crate::network::NetworkKind; use crate::prelude::*; @@ -41,7 +41,7 @@ pub type ExtendedPrivKey = Xpriv; #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct ChainCode([u8; 32]); impl_array_newtype!(ChainCode, u8, 32); -impl_bytes_newtype!(ChainCode, 32); +impl_array_newtype_stringify!(ChainCode, 32); impl ChainCode { fn from_hmac(hmac: Hmac) -> Self { @@ -53,7 +53,7 @@ impl ChainCode { #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] pub struct Fingerprint([u8; 4]); impl_array_newtype!(Fingerprint, u8, 4); -impl_bytes_newtype!(Fingerprint, 4); +impl_array_newtype_stringify!(Fingerprint, 4); hash_newtype! { /// Extended key identifier as defined in BIP-32. diff --git a/bitcoin/src/blockdata/constants.rs b/bitcoin/src/blockdata/constants.rs index 0b01831fe..57fb24193 100644 --- a/bitcoin/src/blockdata/constants.rs +++ b/bitcoin/src/blockdata/constants.rs @@ -18,7 +18,7 @@ use crate::blockdata::script; use crate::blockdata::transaction::{self, OutPoint, Sequence, Transaction, TxIn, TxOut}; use crate::blockdata::witness::Witness; use crate::consensus::Params; -use crate::internal_macros::impl_bytes_newtype; +use crate::internal_macros::impl_array_newtype_stringify; use crate::network::Network; use crate::pow::CompactTarget; use crate::Amount; @@ -141,7 +141,7 @@ pub fn genesis_block(params: impl AsRef) -> Block { #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct ChainHash([u8; 32]); impl_array_newtype!(ChainHash, u8, 32); -impl_bytes_newtype!(ChainHash, 32); +impl_array_newtype_stringify!(ChainHash, 32); impl ChainHash { // Mainnet value can be verified at https://github.com/lightning/bolts/blob/master/00-introduction.md diff --git a/bitcoin/src/internal_macros.rs b/bitcoin/src/internal_macros.rs index b8d20694d..918500296 100644 --- a/bitcoin/src/internal_macros.rs +++ b/bitcoin/src/internal_macros.rs @@ -44,30 +44,17 @@ macro_rules! impl_consensus_encoding { } pub(crate) use impl_consensus_encoding; -/// Implements several traits for byte-based newtypes. -/// Implements: -/// - core::fmt::LowerHex -/// - core::fmt::UpperHex -/// - core::fmt::Display -/// - core::str::FromStr -macro_rules! impl_bytes_newtype { +/// Implements several string-ish traits for byte-based newtypes. +/// +/// - `fmt::Display` and `str::FromStr` (using lowercase hex) +/// - `fmt::LowerHex` and `UpperHex` +/// - `fmt::Debug` (using `LowerHex`) +/// - `serde::Serialize` and `Deserialize` (using lowercase hex) +/// +/// As well as an inherent `from_hex` method. +macro_rules! impl_array_newtype_stringify { ($t:ident, $len:literal) => { impl $t { - /// Returns a reference the underlying bytes. - #[inline] - pub fn as_bytes(&self) -> &[u8; $len] { &self.0 } - - /// Returns the underlying bytes. - #[inline] - pub fn to_bytes(self) -> [u8; $len] { - // We rely on `Copy` being implemented for $t so conversion - // methods use the correct Rust naming conventions. - fn check_copy() {} - check_copy::<$t>(); - - self.0 - } - /// Creates `Self` from a hex string. pub fn from_hex(s: &str) -> Result { Ok($t($crate::hex::FromHex::from_hex(s)?)) @@ -186,7 +173,7 @@ macro_rules! impl_bytes_newtype { } }; } -pub(crate) use impl_bytes_newtype; +pub(crate) use impl_array_newtype_stringify; #[rustfmt::skip] macro_rules! impl_hashencode { diff --git a/bitcoin/src/psbt/serialize.rs b/bitcoin/src/psbt/serialize.rs index f9e0564a5..06df0fc96 100644 --- a/bitcoin/src/psbt/serialize.rs +++ b/bitcoin/src/psbt/serialize.rs @@ -185,7 +185,7 @@ impl Serialize for KeySource { fn serialize(&self) -> Vec { let mut rv: Vec = Vec::with_capacity(key_source_len(self)); - rv.append(&mut self.0.to_bytes().to_vec()); + rv.append(&mut self.0.to_byte_array().to_vec()); for cnum in self.1.into_iter() { rv.append(&mut serialize(&u32::from(*cnum))) diff --git a/internals/src/macros.rs b/internals/src/macros.rs index 7ec8e2447..0003e42f9 100644 --- a/internals/src/macros.rs +++ b/internals/src/macros.rs @@ -8,6 +8,34 @@ macro_rules! impl_array_newtype { ($thing:ident, $ty:ty, $len:literal) => { impl $thing { + /// Creates `Self` by wrapping `bytes`. + #[inline] + pub fn from_byte_array(bytes: [u8; $len]) -> Self { Self(bytes) } + + /// Returns a reference the underlying byte array. + #[inline] + pub fn as_byte_array(&self) -> &[u8; $len] { &self.0 } + + /// Returns the underlying byte array. + #[inline] + pub fn to_byte_array(self) -> [u8; $len] { + // We rely on `Copy` being implemented for $thing so conversion + // methods use the correct Rust naming conventions. + fn check_copy() {} + check_copy::<$thing>(); + + self.0 + } + + /// Returns a slice of the underlying bytes. + #[inline] + pub fn as_bytes(&self) -> &[u8] { &self.0 } + + /// Copies the underlying bytes into a new `Vec`. + #[cfg(feature = "alloc")] + #[inline] + pub fn to_bytes(&self) -> alloc::vec::Vec { self.0.to_vec() } + /// Converts the object to a raw pointer. #[inline] pub fn as_ptr(&self) -> *const $ty {