Move `impl_array_newtype` to `internals`
What changed, and why it matters
This commit is a routine code reorganization. It moves a helper macro that generates standard methods for array-like types from the main `bitcoin` crate into the shared `internals` crate. The goal is to let other crates (specifically `p2p`) use the macro without depending directly on `bitcoin`. The generated behavior is essentially unchanged, though a couple of deprecated `to_bytes` methods are moved from the macro into individual type definitions.
No security action required. Treat as normal maintenance/refactoring.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The impl_array_newtype! macro is relocated from bitcoin/src/internal_macros.rs to internals/src/macros.rs and exported with #[macro_export]. Call sites in bitcoin/src/bip152.rs, bitcoin/src/bip32.rs, and bitcoin/src/blockdata/constants.rs are updated from internal_macros::impl_array_newtype! to internals::impl_array_newtype!. The macro body is mostly identical, except the deprecated to_bytes method is removed from the macro and instead added explicitly to ChainCode and ChainHash impl blocks. This is a refactoring step toward decoupling the p2p crate from bitcoin.
Changed components
bitcoin/src/internal_macros.rsinternals/src/macros.rsbitcoin/src/bip152.rsbitcoin/src/bip32.rsbitcoin/src/blockdata/constants.rsInspect captured patch +134 / −127
diff --git a/bitcoin/src/bip152.rs b/bitcoin/src/bip152.rs
index 38b4be42..9c6347fe 100644
--- a/bitcoin/src/bip152.rs
+++ b/bitcoin/src/bip152.rs
@@ -17,7 +17,7 @@ use internals::ToU64 as _;
use io::{BufRead, Write};
use crate::consensus::encode::{self, Decodable, Encodable, ReadExt, WriteExt};
-use crate::internal_macros::{self, impl_array_newtype, impl_array_newtype_stringify};
+use crate::internal_macros::{self, impl_array_newtype_stringify};
use crate::prelude::Vec;
use crate::transaction::TxIdentifier;
use crate::{block, consensus, Block, BlockChecked, BlockHash, Transaction};
@@ -99,7 +99,7 @@ impl Decodable for PrefilledTransaction {
/// Short transaction IDs are used to represent a transaction without sending a full 256-bit hash.
#[derive(PartialEq, Eq, Clone, Copy, Hash, Default, PartialOrd, Ord)]
pub struct ShortId([u8; 6]);
-impl_array_newtype!(ShortId, u8, 6);
+internals::impl_array_newtype!(ShortId, u8, 6);
impl_array_newtype_stringify!(ShortId, 6);
impl ShortId {
diff --git a/bitcoin/src/bip32.rs b/bitcoin/src/bip32.rs
index 8f0926ee..013548b7 100644
--- a/bitcoin/src/bip32.rs
+++ b/bitcoin/src/bip32.rs
@@ -39,19 +39,24 @@ pub type ExtendedPrivKey = Xpriv;
/// A chain code
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ChainCode([u8; 32]);
-internal_macros::impl_array_newtype!(ChainCode, u8, 32);
+internals::impl_array_newtype!(ChainCode, u8, 32);
internal_macros::impl_array_newtype_stringify!(ChainCode, 32);
impl ChainCode {
fn from_hmac(hmac: Hmac<sha512::Hash>) -> Self {
Self(*hmac.as_byte_array().split_array::<32, 32>().1)
}
+
+ /// Copies the underlying bytes into a new `Vec`.
+ #[inline]
+ #[deprecated(since = "TBD", note = "use to_vec instead")]
+ pub fn to_bytes(self) -> alloc::vec::Vec<u8> { self.to_vec() }
}
/// A fingerprint
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct Fingerprint([u8; 4]);
-internal_macros::impl_array_newtype!(Fingerprint, u8, 4);
+internals::impl_array_newtype!(Fingerprint, u8, 4);
internal_macros::impl_array_newtype_stringify!(Fingerprint, 4);
hash_newtype! {
diff --git a/bitcoin/src/blockdata/constants.rs b/bitcoin/src/blockdata/constants.rs
index d6ba583f..d44d35ae 100644
--- a/bitcoin/src/blockdata/constants.rs
+++ b/bitcoin/src/blockdata/constants.rs
@@ -7,7 +7,7 @@
//! single transaction.
use crate::block::{self, Block, Checked};
-use crate::internal_macros::{impl_array_newtype, impl_array_newtype_stringify};
+use crate::internal_macros::impl_array_newtype_stringify;
use crate::locktime::absolute;
use crate::network::{Network, Params};
use crate::opcodes::all::*;
@@ -192,7 +192,7 @@ pub fn genesis_block(params: impl AsRef<Params>) -> Block<Checked> {
/// The uniquely identifying hash of the target blockchain.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ChainHash([u8; 32]);
-impl_array_newtype!(ChainHash, u8, 32);
+internals::impl_array_newtype!(ChainHash, u8, 32);
impl_array_newtype_stringify!(ChainHash, 32);
impl ChainHash {
@@ -261,6 +261,11 @@ impl ChainHash {
pub fn from_genesis_block_hash(block_hash: crate::BlockHash) -> Self {
Self(block_hash.to_byte_array())
}
+
+ /// Copies the underlying bytes into a new `Vec`.
+ #[inline]
+ #[deprecated(since = "TBD", note = "use to_vec instead")]
+ pub fn to_bytes(self) -> alloc::vec::Vec<u8> { self.to_vec() }
}
#[cfg(test)]
diff --git a/bitcoin/src/internal_macros.rs b/bitcoin/src/internal_macros.rs
index b7a469d2..da38582b 100644
--- a/bitcoin/src/internal_macros.rs
+++ b/bitcoin/src/internal_macros.rs
@@ -278,125 +278,4 @@ macro_rules! define_extension_trait {
}
pub(crate) use define_extension_trait;
-/// Implements standard array methods for a given wrapper type.
-macro_rules! impl_array_newtype {
- ($thing:ident, $ty:ty, $len:literal) => {
- impl $thing {
- /// Constructs a new `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
- }
-
- /// Copies the underlying bytes into a new `Vec`.
- #[inline]
- pub fn to_vec(self) -> alloc::vec::Vec<u8> { self.0.to_vec() }
-
- /// Returns a slice of the underlying bytes.
- #[inline]
- pub fn as_bytes(&self) -> &[u8] { &self.0 }
-
- /// Copies the underlying bytes into a new `Vec`.
- #[inline]
- #[deprecated(since = "TBD", note = "use to_vec instead")]
- pub fn to_bytes(self) -> alloc::vec::Vec<u8> { self.to_vec() }
-
- /// Converts the object to a raw pointer.
- #[inline]
- pub fn as_ptr(&self) -> *const $ty {
- let &$thing(ref dat) = self;
- dat.as_ptr()
- }
-
- /// Converts the object to a mutable raw pointer.
- #[inline]
- pub fn as_mut_ptr(&mut self) -> *mut $ty {
- let &mut $thing(ref mut dat) = self;
- dat.as_mut_ptr()
- }
-
- /// Returns the length of the object as an array.
- #[inline]
- pub fn len(&self) -> usize { $len }
-
- /// Returns whether the object, as an array, is empty. Always false.
- #[inline]
- pub fn is_empty(&self) -> bool { false }
- }
-
- impl<'a> core::convert::From<[$ty; $len]> for $thing {
- fn from(data: [$ty; $len]) -> Self { $thing(data) }
- }
-
- impl<'a> core::convert::From<&'a [$ty; $len]> for $thing {
- fn from(data: &'a [$ty; $len]) -> Self { $thing(*data) }
- }
-
- impl<'a> core::convert::TryFrom<&'a [$ty]> for $thing {
- type Error = core::array::TryFromSliceError;
-
- fn try_from(data: &'a [$ty]) -> core::result::Result<Self, Self::Error> {
- use core::convert::TryInto;
-
- Ok($thing(data.try_into()?))
- }
- }
-
- impl AsRef<[$ty; $len]> for $thing {
- fn as_ref(&self) -> &[$ty; $len] { &self.0 }
- }
-
- impl AsMut<[$ty; $len]> for $thing {
- fn as_mut(&mut self) -> &mut [$ty; $len] { &mut self.0 }
- }
-
- impl AsRef<[$ty]> for $thing {
- fn as_ref(&self) -> &[$ty] { &self.0 }
- }
-
- impl AsMut<[$ty]> for $thing {
- fn as_mut(&mut self) -> &mut [$ty] { &mut self.0 }
- }
- impl core::borrow::Borrow<[$ty; $len]> for $thing {
- fn borrow(&self) -> &[$ty; $len] { &self.0 }
- }
-
- impl core::borrow::BorrowMut<[$ty; $len]> for $thing {
- fn borrow_mut(&mut self) -> &mut [$ty; $len] { &mut self.0 }
- }
-
- // The following two are valid because `[T; N]: Borrow<[T]>`
- impl core::borrow::Borrow<[$ty]> for $thing {
- fn borrow(&self) -> &[$ty] { &self.0 }
- }
-
- impl core::borrow::BorrowMut<[$ty]> for $thing {
- fn borrow_mut(&mut self) -> &mut [$ty] { &mut self.0 }
- }
-
- impl<I> core::ops::Index<I> for $thing
- where
- [$ty]: core::ops::Index<I>,
- {
- type Output = <[$ty] as core::ops::Index<I>>::Output;
-
- #[inline]
- fn index(&self, index: I) -> &Self::Output { &self.0[index] }
- }
- };
-}
-pub(crate) use impl_array_newtype;
diff --git a/internals/src/macros.rs b/internals/src/macros.rs
index 7de7193f..1119fcde 100644
--- a/internals/src/macros.rs
+++ b/internals/src/macros.rs
@@ -244,3 +244,121 @@ macro_rules! _emit_alloc {
macro_rules! _emit_alloc {
($($tokens:tt)*) => {};
}
+
+/// Implements standard array methods for a given wrapper type.
+#[macro_export]
+macro_rules! impl_array_newtype {
+ ($thing:ident, $ty:ty, $len:literal) => {
+ impl $thing {
+ /// Constructs a new `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
+ }
+
+ /// Copies the underlying bytes into a new `Vec`.
+ #[inline]
+ pub fn to_vec(self) -> alloc::vec::Vec<u8> { self.0.to_vec() }
+
+ /// Returns a slice of the underlying bytes.
+ #[inline]
+ pub fn as_bytes(&self) -> &[u8] { &self.0 }
+
+ /// Converts the object to a raw pointer.
+ #[inline]
+ pub fn as_ptr(&self) -> *const $ty {
+ let &$thing(ref dat) = self;
+ dat.as_ptr()
+ }
+
+ /// Converts the object to a mutable raw pointer.
+ #[inline]
+ pub fn as_mut_ptr(&mut self) -> *mut $ty {
+ let &mut $thing(ref mut dat) = self;
+ dat.as_mut_ptr()
+ }
+
+ /// Returns the length of the object as an array.
+ #[inline]
+ pub fn len(&self) -> usize { $len }
+
+ /// Returns whether the object, as an array, is empty. Always false.
+ #[inline]
+ pub fn is_empty(&self) -> bool { false }
+ }
+
+ impl<'a> core::convert::From<[$ty; $len]> for $thing {
+ fn from(data: [$ty; $len]) -> Self { $thing(data) }
+ }
+
+ impl<'a> core::convert::From<&'a [$ty; $len]> for $thing {
+ fn from(data: &'a [$ty; $len]) -> Self { $thing(*data) }
+ }
+
+ impl<'a> core::convert::TryFrom<&'a [$ty]> for $thing {
+ type Error = core::array::TryFromSliceError;
+
+ fn try_from(data: &'a [$ty]) -> core::result::Result<Self, Self::Error> {
+ use core::convert::TryInto;
+
+ Ok($thing(data.try_into()?))
+ }
+ }
+
+ impl AsRef<[$ty; $len]> for $thing {
+ fn as_ref(&self) -> &[$ty; $len] { &self.0 }
+ }
+
+ impl AsMut<[$ty; $len]> for $thing {
+ fn as_mut(&mut self) -> &mut [$ty; $len] { &mut self.0 }
+ }
+
+ impl AsRef<[$ty]> for $thing {
+ fn as_ref(&self) -> &[$ty] { &self.0 }
+ }
+
+ impl AsMut<[$ty]> for $thing {
+ fn as_mut(&mut self) -> &mut [$ty] { &mut self.0 }
+ }
+
+ impl core::borrow::Borrow<[$ty; $len]> for $thing {
+ fn borrow(&self) -> &[$ty; $len] { &self.0 }
+ }
+
+ impl core::borrow::BorrowMut<[$ty; $len]> for $thing {
+ fn borrow_mut(&mut self) -> &mut [$ty; $len] { &mut self.0 }
+ }
+
+ // The following two are valid because `[T; N]: Borrow<[T]>`
+ impl core::borrow::Borrow<[$ty]> for $thing {
+ fn borrow(&self) -> &[$ty] { &self.0 }
+ }
+
+ impl core::borrow::BorrowMut<[$ty]> for $thing {
+ fn borrow_mut(&mut self) -> &mut [$ty] { &mut self.0 }
+ }
+
+ impl<I> core::ops::Index<I> for $thing
+ where
+ [$ty]: core::ops::Index<I>,
+ {
+ type Output = <[$ty] as core::ops::Index<I>>::Output;
+
+ #[inline]
+ fn index(&self, index: I) -> &Self::Output { &self.0[index] }
+ }
+ };
+}
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.