Skip to content

Commit

Permalink
Improve array macros
Browse files Browse the repository at this point in the history
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
  • Loading branch information
tcharding committed May 14, 2024
1 parent 2e8bd5f commit 6ba7758
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 31 deletions.
4 changes: 2 additions & 2 deletions bitcoin/src/bip152.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down Expand Up @@ -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.
Expand Down
6 changes: 3 additions & 3 deletions bitcoin/src/bip32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::*;

Expand All @@ -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<sha512::Hash>) -> Self {
Expand All @@ -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.
Expand Down
4 changes: 2 additions & 2 deletions bitcoin/src/blockdata/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -141,7 +141,7 @@ pub fn genesis_block(params: impl AsRef<Params>) -> 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
Expand Down
33 changes: 10 additions & 23 deletions bitcoin/src/internal_macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<T: Copy>() {}
check_copy::<$t>();

self.0
}

/// Creates `Self` from a hex string.
pub fn from_hex(s: &str) -> Result<Self, hex::HexToArrayError> {
Ok($t($crate::hex::FromHex::from_hex(s)?))
Expand Down Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion bitcoin/src/psbt/serialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ impl Serialize for KeySource {
fn serialize(&self) -> Vec<u8> {
let mut rv: Vec<u8> = 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)))
Expand Down
28 changes: 28 additions & 0 deletions internals/src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<T: 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<u8> { self.0.to_vec() }

/// Converts the object to a raw pointer.
#[inline]
pub fn as_ptr(&self) -> *const $ty {
Expand Down

0 comments on commit 6ba7758

Please sign in to comment.