#[macro_export]
macro_rules! sha256t_tag {
($(#[$($tag_attr:tt)*])* $tag_vis:vis struct $tag:ident = $constructor:tt($($tag_value:tt)+);) => {
$crate::sha256t_tag_struct!($tag_vis, $tag, stringify!($hash_name), $(#[$($tag_attr)*])*);
impl $crate::sha256t::Tag for $tag {
const MIDSTATE: $crate::sha256::Midstate = $crate::sha256t_tag_constructor!($constructor, $($tag_value)+);
}
}
}
#[macro_export]
macro_rules! hash_newtype {
($($(#[$($type_attrs:tt)*])* $type_vis:vis struct $newtype:ident($(#[$field_attrs:tt])* $field_vis:vis $hash:path);)+) => {
$(
$($crate::hash_newtype_known_attrs!(#[ $($type_attrs)* ]);)*
$crate::hash_newtype_struct! {
$type_vis struct $newtype($(#[$field_attrs])* $field_vis $hash);
$({ $($type_attrs)* })*
}
$crate::impl_bytelike_traits!($newtype, { <$newtype as $crate::Hash>::LEN });
#[allow(unused)] impl $newtype {
pub const fn from_byte_array(bytes: <$hash as $crate::Hash>::Bytes) -> Self {
$newtype(<$hash>::from_byte_array(bytes))
}
pub const fn to_byte_array(self) -> <$hash as $crate::Hash>::Bytes {
self.0.to_byte_array()
}
pub const fn as_byte_array(&self) -> &<$hash as $crate::Hash>::Bytes {
self.0.as_byte_array()
}
}
impl $crate::Hash for $newtype {
type Bytes = <$hash as $crate::Hash>::Bytes;
const DISPLAY_BACKWARD: bool = $crate::hash_newtype_get_direction!($hash, $(#[$($type_attrs)*])*);
fn from_byte_array(bytes: Self::Bytes) -> Self { Self::from_byte_array(bytes) }
fn to_byte_array(self) -> Self::Bytes { self.to_byte_array() }
fn as_byte_array(&self) -> &Self::Bytes { self.as_byte_array() }
}
)+
};
}
#[macro_export]
#[cfg(feature = "hex")]
macro_rules! impl_hex_for_newtype {
($($newtype:ident),*) => {
$(
$crate::impl_hex_string_traits!($newtype, { <$newtype as $crate::Hash>::LEN }, { <$newtype as $crate::Hash>::DISPLAY_BACKWARD });
)*
}
}
#[macro_export]
macro_rules! impl_debug_only_for_newtype {
($($newtype:ident),*) => {
$(
$crate::impl_debug_only!($newtype, { <$newtype as $crate::Hash>::LEN }, { <$newtype as $crate::Hash>::DISPLAY_BACKWARD });
)*
}
}
#[doc(hidden)]
#[macro_export]
macro_rules! impl_bytelike_traits {
($ty:ident, $len:expr $(, $gen:ident: $gent:ident)*) => {
impl<$($gen: $gent),*> $crate::_export::_core::convert::AsRef<[u8; { $len }]> for $ty<$($gen),*> {
#[inline]
fn as_ref(&self) -> &[u8; { $len }] { self.as_byte_array() }
}
impl<$($gen: $gent),*> $crate::_export::_core::convert::AsRef<[u8]> for $ty<$($gen),*> {
#[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() }
}
}
}
#[doc(hidden)]
#[macro_export]
#[cfg(feature = "hex")]
macro_rules! impl_hex_string_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 {
bytes.reverse();
}
Ok(Self::from_byte_array(bytes))
}
}
macro_rules! impl_case_hex {
($case:expr) => {
#[inline]
fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result {
if $reverse {
let bytes = $crate::_export::_core::borrow::Borrow::<[u8]>::borrow(self).iter().rev();
$crate::hex::fmt_hex_exact!(f, ($len), bytes, $case)
} else {
let bytes = $crate::_export::_core::borrow::Borrow::<[u8]>::borrow(self).iter();
$crate::hex::fmt_hex_exact!(f, ($len), bytes, $case)
}
}
}
}
impl<$($gen: $gent),*> $crate::_export::_core::fmt::LowerHex for $ty<$($gen),*> {
impl_case_hex!($crate::hex::Case::Lower);
}
impl<$($gen: $gent),*> $crate::_export::_core::fmt::UpperHex for $ty<$($gen),*> {
impl_case_hex!($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 {
struct HexWrap<'a, T: $crate::_export::_core::fmt::LowerHex>(&'a T);
impl<T: $crate::_export::_core::fmt::LowerHex> $crate::_export::_core::fmt::Debug for HexWrap<'_, T> {
fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result {
$crate::_export::_core::fmt::LowerHex::fmt(&self.0, f)
}
}
f.debug_tuple(core::any::type_name::<$ty<$($gen),*>>())
.field(&HexWrap(self))
.finish()
}
}
}
}
#[doc(hidden)]
#[macro_export]
macro_rules! impl_debug_only {
($ty:ident, $len:expr, $reverse:expr $(, $gen:ident: $gent:ident)*) => {
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 {
struct HexWrap<'a, T: $crate::Hash>(&'a T);
impl<T: $crate::Hash> $crate::_export::_core::fmt::Debug for HexWrap<'_, T> {
fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result {
if $reverse {
$crate::debug_hex(self.0.as_ref().iter().rev(), f)
} else {
$crate::debug_hex(self.0.as_ref(), f)
}
}
}
f.debug_tuple(core::any::type_name::<$ty<$($gen),*>>())
.field(&HexWrap(self))
.finish()
}
}
}
}
#[doc(hidden)]
#[macro_export]
macro_rules! hash_newtype_struct {
($(#[$other_attrs:meta])* $type_vis:vis struct $newtype:ident($(#[$field_attrs:meta])* $field_vis:vis $hash:path);) => {
$(#[$other_attrs])*
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
$type_vis struct $newtype($(#[$field_attrs])* $field_vis $hash);
};
($(#[$other_attrs:meta])* $type_vis:vis struct $newtype:ident($(#[$field_attrs:meta])* $field_vis:vis $hash:path); { hash_newtype($($ignore:tt)*) } $($type_attrs:tt)*) => {
$crate::hash_newtype_struct! {
$(#[$other_attrs])*
$type_vis struct $newtype($(#[$field_attrs])* $field_vis $hash);
$($type_attrs)*
}
};
($(#[$other_attrs:meta])* $type_vis:vis struct $newtype:ident($(#[$field_attrs:meta])* $field_vis:vis $hash:path); { $other_attr:meta } $($type_attrs:tt)*) => {
$crate::hash_newtype_struct! {
$(#[$other_attrs])*
#[$other_attr]
$type_vis struct $newtype($(#[$field_attrs])* $field_vis $hash);
$($type_attrs)*
}
};
}
// Extracts `hash_newtype(forward)` and `hash_newtype(backward)` attributes if any and turns them
#[doc(hidden)]
#[macro_export]
macro_rules! hash_newtype_get_direction {
($hash:ty, ) => { <$hash as $crate::Hash>::DISPLAY_BACKWARD };
($hash:ty, #[hash_newtype(forward)] $($others:tt)*) => { { $crate::hash_newtype_forbid_direction!(forward, $($others)*); false } };
($hash:ty, #[hash_newtype(backward)] $($others:tt)*) => { { $crate::hash_newtype_forbid_direction!(backward, $($others)*); true } };
($hash:ty, #[$($ignore:tt)*] $($others:tt)*) => { $crate::hash_newtype_get_direction!($hash, $($others)*) };
}
#[doc(hidden)]
#[macro_export]
macro_rules! hash_newtype_forbid_direction {
($direction:ident, ) => {};
($direction:ident, #[hash_newtype(forward)] $(others:tt)*) => {
compile_error!(concat!("cannot set display direction to forward: ", stringify!($direction), " was already specified"));
};
($direction:ident, #[hash_newtype(backward)] $(others:tt)*) => {
compile_error!(concat!("cannot set display direction to backward: ", stringify!($direction), " was already specified"));
};
($direction:ident, #[$($ignore:tt)*] $(#[$others:tt])*) => {
$crate::hash_newtype_forbid_direction!($direction, $(#[$others])*)
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! hash_newtype_known_attrs {
(#[hash_newtype(forward)]) => {};
(#[hash_newtype(backward)]) => {};
(#[hash_newtype($($unknown:tt)*)]) => { compile_error!(concat!("unrecognized attribute ", stringify!($($unknown)*))); };
($($ignore:tt)*) => {};
}
#[cfg(feature = "serde")]
pub mod serde_details {
use core::marker::PhantomData;
use core::str::FromStr;
use core::{fmt, str};
use serde::de;
pub struct HexVisitor<ValueT>(PhantomData<ValueT>);
impl<ValueT> Default for HexVisitor<ValueT> {
fn default() -> Self { Self(PhantomData) }
}
impl<ValueT> de::Visitor<'_> for HexVisitor<ValueT>
where
ValueT: FromStr,
<ValueT as FromStr>::Err: fmt::Display,
{
type Value = ValueT;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("an ASCII hex string")
}
fn visit_bytes<E>(self, v: &[u8]) -> core::result::Result<Self::Value, E>
where
E: de::Error,
{
if let Ok(hex) = str::from_utf8(v) {
hex.parse::<Self::Value>().map_err(E::custom)
} else {
Err(E::invalid_value(de::Unexpected::Bytes(v), &self))
}
}
fn visit_str<E>(self, v: &str) -> core::result::Result<Self::Value, E>
where
E: de::Error,
{
v.parse::<Self::Value>().map_err(E::custom)
}
}
pub struct BytesVisitor<ValueT, const N: usize>(PhantomData<ValueT>);
impl<ValueT, const N: usize> Default for BytesVisitor<ValueT, N> {
fn default() -> Self { Self(PhantomData) }
}
impl<ValueT, const N: usize> de::Visitor<'_> for BytesVisitor<ValueT, N>
where
ValueT: crate::Hash,
ValueT: crate::Hash<Bytes = [u8; N]>,
{
type Value = ValueT;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a bytestring")
}
fn visit_bytes<E>(self, v: &[u8]) -> core::result::Result<Self::Value, E>
where
E: de::Error,
{
let bytes = <[u8; N]>::try_from(v).map_err(|_| {
E::invalid_length(v.len(), &stringify!(N))
})?;
Ok(<Self::Value as crate::Hash>::from_byte_array(bytes))
}
}
}
#[macro_export]
#[cfg(feature = "serde")]
macro_rules! impl_serde_for_newtype {
($($newtype:ident),*) => {
$(
$crate::serde_impl!($newtype, { <$newtype as $crate::Hash>::LEN });
)*
}
}
#[doc(hidden)]
#[macro_export]
#[cfg(feature = "serde")]
macro_rules! serde_impl(
($t:ident, $len:expr $(, $gen:ident: $gent:ident)*) => (
impl<$($gen: $gent),*> $crate::serde::Serialize for $t<$($gen),*> {
fn serialize<S: $crate::serde::Serializer>(&self, s: S) -> core::result::Result<S::Ok, S::Error> {
if s.is_human_readable() {
s.collect_str(self)
} else {
s.serialize_bytes(<Self as $crate::Hash>::as_byte_array(self))
}
}
}
impl<'de $(, $gen: $gent)*> $crate::serde::Deserialize<'de> for $t<$($gen),*> {
fn deserialize<D: $crate::serde::Deserializer<'de>>(d: D) -> core::result::Result<$t<$($gen),*>, D::Error> {
use $crate::macros::serde_details::{BytesVisitor, HexVisitor};
if d.is_human_readable() {
d.deserialize_str(HexVisitor::<Self>::default())
} else {
d.deserialize_bytes(BytesVisitor::<Self, $len>::default())
}
}
}
));
#[doc(hidden)]
#[macro_export]
#[cfg(not(feature = "serde"))]
macro_rules! serde_impl(
($t:ident, $len:expr $(, $gen:ident: $gent:ident)*) => ()
);
#[cfg(test)]
mod test {
use crate::sha256;
#[test]
fn hash_as_ref_array() {
let hash = sha256::Hash::hash(&[3, 50]);
let r = AsRef::<[u8; 32]>::as_ref(&hash);
assert_eq!(r, hash.as_byte_array());
}
#[test]
fn hash_as_ref_slice() {
let hash = sha256::Hash::hash(&[3, 50]);
let r = AsRef::<[u8]>::as_ref(&hash);
assert_eq!(r, hash.as_byte_array());
}
#[test]
fn hash_borrow() {
use core::borrow::Borrow;
let hash = sha256::Hash::hash(&[3, 50]);
let borrowed: &[u8] = hash.borrow();
assert_eq!(borrowed, hash.as_byte_array());
}
hash_newtype! {
struct TestHash(crate::sha256d::Hash);
}
#[cfg(feature = "hex")]
crate::impl_hex_for_newtype!(TestHash);
#[cfg(not(feature = "hex"))]
crate::impl_debug_only_for_newtype!(TestHash);
impl TestHash {
fn all_zeros() -> Self { Self::from_byte_array([0; 32]) }
}
#[test]
fn macros_work_in_function_scope() {
use crate::sha256t;
sha256t_tag! {
#[repr(align(2))] pub struct FunctionScopeTag = hash_str("It works");
}
hash_newtype! {
#[repr(align(4))] pub struct FunctionScopeHash(pub(crate) sha256t::Hash<FunctionScopeTag>);
}
assert_eq!(2, core::mem::align_of::<FunctionScopeTag>());
assert_eq!(4, core::mem::align_of::<FunctionScopeHash>());
}
#[test]
#[cfg(feature = "alloc")]
fn debug() {
use alloc::format;
let want = "bitcoin_hashes::macros::test::TestHash(0000000000000000000000000000000000000000000000000000000000000000)";
let got = format!("{:?}", TestHash::all_zeros());
assert_eq!(got, want);
let mut bytes = [0u8; 32];
bytes[31] = 0xff;
let hash = TestHash::from_byte_array(bytes);
let want = "bitcoin_hashes::macros::test::TestHash(ff00000000000000000000000000000000000000000000000000000000000000)";
let got = format!("{:?}", hash);
assert_eq!(got, want);
}
#[test]
#[cfg(feature = "alloc")]
#[cfg(feature = "hex")]
fn display() {
use alloc::format;
let want = "0000000000000000000000000000000000000000000000000000000000000000";
let got = format!("{}", TestHash::all_zeros());
assert_eq!(got, want)
}
#[test]
#[cfg(feature = "alloc")]
#[cfg(feature = "hex")]
fn display_alternate() {
use alloc::format;
let want = "0x0000000000000000000000000000000000000000000000000000000000000000";
let got = format!("{:#}", TestHash::all_zeros());
assert_eq!(got, want)
}
#[test]
#[cfg(feature = "alloc")]
#[cfg(feature = "hex")]
fn lower_hex() {
use alloc::format;
let want = "0000000000000000000000000000000000000000000000000000000000000000";
let got = format!("{:x}", TestHash::all_zeros());
assert_eq!(got, want)
}
#[test]
#[cfg(feature = "alloc")]
#[cfg(feature = "hex")]
fn lower_hex_alternate() {
use alloc::format;
let want = "0x0000000000000000000000000000000000000000000000000000000000000000";
let got = format!("{:#x}", TestHash::all_zeros());
assert_eq!(got, want)
}
#[test]
fn inner_hash_as_ref_array() {
let hash = TestHash::all_zeros();
let r = AsRef::<[u8; 32]>::as_ref(&hash);
assert_eq!(r, hash.as_byte_array());
}
#[test]
fn inner_hash_as_ref_slice() {
let hash = TestHash::all_zeros();
let r = AsRef::<[u8]>::as_ref(&hash);
assert_eq!(r, hash.as_byte_array());
}
}