hashes: Introduce impl_bytelike_traits macro

We have a couple of problems:

1. There are two macros currently for fmt stuff that do similar things,
`arr_newtype_fmt_impl` and `hex_fmt_impl` - the difference is not
immediately obvious, its the way that the byte array is iterated.

2. Our hash types are missing `AsRef<[u8; len]>` and `Borrow<[u8; len]>`.

Introduce a new macro and remove a bunch of other macros. Include
extensive docs but hide the macro from public docs because its not
really for consumers of the library.

The macro requires `$crate::hex` to point to `hex-conservative`.

Note the macro is pretty generic (as in general purpose), `hashes` might
not be the right home for it. Potentially a better place would be in
`hex` itself?
This commit is contained in:
Tobin C. Harding 2024-11-02 08:10:43 +11:00
parent 515c0f584a
commit 90b2ac03e3
No known key found for this signature in database
GPG Key ID: 40BF9E4C269D6607
3 changed files with 60 additions and 138 deletions

View File

@ -1970,7 +1970,7 @@ mod tests {
let display = "0000000000000000000000000000000000000000000000000000000000000000:4294967295";
assert_eq!(display, format!("{}", &outpoint));
let pretty_debug = "OutPoint {\n txid: 0000000000000000000000000000000000000000000000000000000000000000,\n vout: 4294967295,\n}";
let pretty_debug = "OutPoint {\n txid: 0x0000000000000000000000000000000000000000000000000000000000000000,\n vout: 4294967295,\n}";
assert_eq!(pretty_debug, format!("{:#?}", &outpoint));
let debug_txid = "0000000000000000000000000000000000000000000000000000000000000000";

View File

@ -2,49 +2,6 @@
//! Non-public macros
macro_rules! arr_newtype_fmt_impl {
($ty:ident, $bytes:expr $(, $gen:ident: $gent:ident)*) => {
impl<$($gen: $gent),*> $crate::_export::_core::fmt::LowerHex for $ty<$($gen),*> {
#[inline]
fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result {
let case = $crate::hex::Case::Lower;
if <$ty<$($gen),*> as crate::Hash>::DISPLAY_BACKWARD {
$crate::hex::fmt_hex_exact!(f, $bytes, self.0.iter().rev(), case)
} else {
$crate::hex::fmt_hex_exact!(f, $bytes, self.0.iter(), case)
}
}
}
impl<$($gen: $gent),*> $crate::_export::_core::fmt::UpperHex for $ty<$($gen),*> {
#[inline]
fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result {
let case = $crate::hex::Case::Upper;
if <$ty<$($gen),*> as crate::Hash>::DISPLAY_BACKWARD {
$crate::hex::fmt_hex_exact!(f, $bytes, self.0.iter().rev(), case)
} else {
$crate::hex::fmt_hex_exact!(f, $bytes, self.0.iter(), case)
}
}
}
impl<$($gen: $gent),*> $crate::_export::_core::fmt::Display for $ty<$($gen),*> {
#[inline]
fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result {
$crate::_export::_core::fmt::LowerHex::fmt(self, f)
}
}
impl<$($gen: $gent),*> $crate::_export::_core::fmt::Debug for $ty<$($gen),*> {
#[inline]
fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result {
write!(f, "{:#}", self)
}
}
}
}
pub(crate) use arr_newtype_fmt_impl;
/// Adds trait impls to the type called `Hash` in the current scope.
///
/// Implpements various conversion traits as well as the [`crate::Hash`] trait.
@ -63,28 +20,7 @@ pub(crate) use arr_newtype_fmt_impl;
/// `from_engine` obviously implements the finalization algorithm.
macro_rules! hash_trait_impls {
($bits:expr, $reverse:expr $(, $gen:ident: $gent:ident)*) => {
impl<$($gen: $gent),*> $crate::_export::_core::str::FromStr for Hash<$($gen),*> {
type Err = $crate::hex::HexToArrayError;
fn from_str(s: &str) -> $crate::_export::_core::result::Result<Self, Self::Err> {
use $crate::{hex::{FromHex}};
let mut bytes = <[u8; $bits / 8]>::from_hex(s)?;
if $reverse {
bytes.reverse();
}
Ok(Self::from_byte_array(bytes))
}
}
$crate::internal_macros::arr_newtype_fmt_impl!(Hash, $bits / 8 $(, $gen: $gent)*);
$crate::serde_impl!(Hash, { $bits / 8 } $(, $gen: $gent)*);
$crate::borrow_slice_impl!(Hash $(, $gen: $gent)*);
impl<$($gen: $gent),*> $crate::_export::_core::convert::AsRef<[u8; $bits / 8]> for Hash<$($gen),*> {
fn as_ref(&self) -> &[u8; $bits / 8] {
&self.0
}
}
$crate::impl_bytelike_traits!(Hash, { $bits / 8 }, $reverse $(, $gen: $gent)*);
impl<$($gen: $gent),*> $crate::GeneralHash for Hash<$($gen),*> {
type Engine = HashEngine;

View File

@ -133,9 +133,7 @@ macro_rules! hash_newtype {
$({ $($type_attrs)* })*
}
$crate::hex_fmt_impl!(<$newtype as $crate::Hash>::DISPLAY_BACKWARD, <$newtype as $crate::Hash>::LEN, $newtype);
$crate::serde_impl!($newtype, { <$newtype as $crate::Hash>::LEN });
$crate::borrow_slice_impl!($newtype);
$crate::impl_bytelike_traits!($newtype, { <$newtype as $crate::Hash>::LEN }, <$newtype as $crate::Hash>::DISPLAY_BACKWARD);
#[allow(unused)] // Private wrapper types may not need all functions.
impl $newtype {
@ -192,96 +190,84 @@ macro_rules! hash_newtype {
fn as_byte_array(&self) -> &Self::Bytes { self.as_byte_array() }
}
impl $crate::_export::_core::str::FromStr for $newtype {
type Err = $crate::hex::HexToArrayError;
fn from_str(s: &str) -> $crate::_export::_core::result::Result<$newtype, Self::Err> {
use $crate::{hex::FromHex};
let mut bytes = <[u8; <Self as $crate::Hash>::LEN]>::from_hex(s)?;
if <Self as $crate::Hash>::DISPLAY_BACKWARD {
bytes.reverse();
};
Ok($newtype(<$hash>::from_byte_array(bytes)))
}
}
impl $crate::_export::_core::convert::AsRef<[u8; <$hash as $crate::Hash>::LEN]> for $newtype {
fn as_ref(&self) -> &[u8; <$hash as $crate::Hash>::LEN] {
AsRef::<[u8; <$hash as $crate::Hash>::LEN]>::as_ref(&self.0)
}
}
)+
};
}
/// Adds hexadecimal formatting implementation of a trait `$imp` to a given type `$ty`.
/// Adds trait impls to a bytelike type.
///
/// Implements:
///
/// * `str::FromStr`
/// * `fmt::{LowerHex, UpperHex}` using `hex-conservative`.
/// * `fmt::{Display, Debug}` by calling `LowerHex`
/// * `serde::{Deserialize, Serialize}`
/// * `AsRef[u8; $len]`
/// * `AsRef[u8]`
/// * `Borrow<[u8; $len]>`
/// * `Borrow<[u8]>`
///
/// Requires:
///
/// * [`hex-conservative`] to publicly available as `$crate::hex`.
/// * `$ty` must implement `IntoIterator<Item=Borrow<u8>>`.
///
/// (See also [`hex-conservative::fmt_hex_exact`].)
///
/// ## Parameters
///
/// * `ty` - The bytelike type to implement the traits on.
/// * `$len` - The number of bytes this type has.
/// * `$reverse` - `true` if the type should be displayed backwards, `false` otherwise.
/// * `$gen: $gent` - generic type(s) and trait bound(s).
///
/// [`hex-conservative`]: <https://crates.io/crates/hex-conservative>
#[doc(hidden)]
#[macro_export]
macro_rules! hex_fmt_impl(
($reverse:expr, $len:expr, $ty:ident) => (
$crate::hex_fmt_impl!($reverse, $len, $ty, );
);
($reverse:expr, $len:expr, $ty:ident, $($gen:ident: $gent:ident),*) => (
impl<$($gen: $gent),*> $crate::_export::_core::fmt::LowerHex for $ty<$($gen),*> {
#[inline]
fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result {
macro_rules! impl_bytelike_traits {
($ty:ident, $len:expr, $reverse:expr $(, $gen:ident: $gent:ident)*) => {
impl<$($gen: $gent),*> $crate::_export::_core::str::FromStr for $ty<$($gen),*> {
type Err = $crate::hex::HexToArrayError;
fn from_str(s: &str) -> $crate::_export::_core::result::Result<Self, Self::Err> {
use $crate::hex::FromHex;
let mut bytes = <[u8; { $len }]>::from_hex(s)?;
if $reverse {
$crate::hex::fmt_hex_exact!(f, $len, <Self as $crate::Hash>::as_byte_array(&self).iter().rev(), $crate::hex::Case::Lower)
} else {
$crate::hex::fmt_hex_exact!(f, $len, <Self as $crate::Hash>::as_byte_array(&self), $crate::hex::Case::Lower)
bytes.reverse();
}
Ok(Self::from_byte_array(bytes))
}
}
impl<$($gen: $gent),*> $crate::_export::_core::fmt::UpperHex for $ty<$($gen),*> {
$crate::hex::impl_fmt_traits! {
#[display_backward($reverse)]
impl<$($gen: $gent),*> fmt_traits for $ty<$($gen),*> {
const LENGTH: usize = ($len); // parens required due to rustc parser weirdness
}
}
$crate::serde_impl!($ty, $len $(, $gen: $gent)*);
impl<$($gen: $gent),*> $crate::_export::_core::convert::AsRef<[u8; { $len }]> for $ty<$($gen),*> {
#[inline]
fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result {
if $reverse {
$crate::hex::fmt_hex_exact!(f, $len, <Self as $crate::Hash>::as_byte_array(&self).iter().rev(), $crate::hex::Case::Upper)
} else {
$crate::hex::fmt_hex_exact!(f, $len, <Self as $crate::Hash>::as_byte_array(&self), $crate::hex::Case::Upper)
}
}
}
impl<$($gen: $gent),*> $crate::_export::_core::fmt::Display for $ty<$($gen),*> {
#[inline]
fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result {
$crate::_export::_core::fmt::LowerHex::fmt(&self, f)
}
}
impl<$($gen: $gent),*> $crate::_export::_core::fmt::Debug for $ty<$($gen),*> {
#[inline]
fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result {
write!(f, "{}", self)
}
}
);
);
/// Adds slicing traits implementations to a given type `$ty`
#[doc(hidden)]
#[macro_export]
macro_rules! borrow_slice_impl(
($ty:ident) => (
$crate::borrow_slice_impl!($ty, );
);
($ty:ident, $($gen:ident: $gent:ident),*) => (
impl<$($gen: $gent),*> $crate::_export::_core::borrow::Borrow<[u8]> for $ty<$($gen),*> {
fn borrow(&self) -> &[u8] {
self.as_byte_array()
}
fn as_ref(&self) -> &[u8; { $len }] { self.as_byte_array() }
}
impl<$($gen: $gent),*> $crate::_export::_core::convert::AsRef<[u8]> for $ty<$($gen),*> {
fn as_ref(&self) -> &[u8] {
self.as_byte_array()
#[inline]
fn as_ref(&self) -> &[u8] { self.as_byte_array() }
}
impl<$($gen: $gent),*> $crate::_export::_core::borrow::Borrow<[u8; { $len }]> for $ty<$($gen),*> {
fn borrow(&self) -> &[u8; { $len }] { self.as_byte_array() }
}
impl<$($gen: $gent),*> $crate::_export::_core::borrow::Borrow<[u8]> for $ty<$($gen),*> {
fn borrow(&self) -> &[u8] { self.as_byte_array() }
}
}
}
)
);
// Generates the struct only (no impls)
//