bitcoin_hashes/
internal_macros.rs

1// SPDX-License-Identifier: CC0-1.0
2
3//! Non-public macros
4
5macro_rules! arr_newtype_fmt_impl {
6    ($ty:ident, $bytes:expr $(, $gen:ident: $gent:ident)*) => {
7        impl<$($gen: $gent),*> $crate::_export::_core::fmt::LowerHex for $ty<$($gen),*> {
8            #[inline]
9            fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result {
10                #[allow(unused)]
11                use crate::Hash as _;
12                let case = $crate::hex::Case::Lower;
13                if <$ty<$($gen),*>>::DISPLAY_BACKWARD {
14                    $crate::hex::fmt_hex_exact!(f, $bytes, self.0.iter().rev(), case)
15                } else {
16                    $crate::hex::fmt_hex_exact!(f, $bytes, self.0.iter(), case)
17                }
18            }
19        }
20
21        impl<$($gen: $gent),*> $crate::_export::_core::fmt::UpperHex for $ty<$($gen),*> {
22            #[inline]
23            fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result {
24                #[allow(unused)]
25                use crate::Hash as _;
26                let case = $crate::hex::Case::Upper;
27                if <$ty<$($gen),*>>::DISPLAY_BACKWARD {
28                    $crate::hex::fmt_hex_exact!(f, $bytes, self.0.iter().rev(), case)
29                } else {
30                    $crate::hex::fmt_hex_exact!(f, $bytes, self.0.iter(), case)
31                }
32            }
33        }
34
35        impl<$($gen: $gent),*> $crate::_export::_core::fmt::Display for $ty<$($gen),*> {
36            #[inline]
37            fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result {
38                $crate::_export::_core::fmt::LowerHex::fmt(self, f)
39            }
40        }
41
42        impl<$($gen: $gent),*> $crate::_export::_core::fmt::Debug for $ty<$($gen),*> {
43            #[inline]
44            fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result {
45                write!(f, "{:#}", self)
46            }
47        }
48    }
49}
50pub(crate) use arr_newtype_fmt_impl;
51
52/// Adds trait impls to the type called `Hash` in the current scope.
53///
54/// Implpements various conversion traits as well as the [`crate::Hash`] trait.
55/// Arguments:
56///
57/// * `$bits` - number of bits this hash type has
58/// * `$reverse` - `bool`  - `true` if the hash type should be displayed backwards, `false`
59///    otherwise.
60/// * `$gen: $gent` - generic type(s) and trait bound(s)
61///
62/// Restrictions on usage:
63///
64/// * There must be a free-standing `fn from_engine(HashEngine) -> Hash` in the scope
65/// * `fn internal_new([u8; $bits / 8]) -> Self` must exist on `Hash`
66/// * `fn internal_engine() -> HashEngine` must exist on `Hash`
67///
68/// `from_engine` obviously implements the finalization algorithm.
69/// `internal_new` is required so that types with more than one field are constructible.
70/// `internal_engine` is required to initialize the engine for given hash type.
71macro_rules! hash_trait_impls {
72    ($bits:expr, $reverse:expr $(, $gen:ident: $gent:ident)*) => {
73        impl<$($gen: $gent),*> Hash<$($gen),*> {
74            /// Displays hex forwards, regardless of how this type would display it naturally.
75            ///
76            /// This is mainly intended as an internal method and you shouldn't need it unless
77            /// you're doing something special.
78            pub fn forward_hex(&self) -> impl '_ + core::fmt::LowerHex + core::fmt::UpperHex {
79                $crate::hex::DisplayHex::as_hex(&self.0)
80            }
81
82            /// Displays hex backwards, regardless of how this type would display it naturally.
83            ///
84            /// This is mainly intended as an internal method and you shouldn't need it unless
85            /// you're doing something special.
86            pub fn backward_hex(&self) -> impl '_ + core::fmt::LowerHex + core::fmt::UpperHex {
87                $crate::hex::display::DisplayArray::<_, [u8; $bits / 8 * 2]>::new(self.0.iter().rev())
88            }
89
90            /// Zero cost conversion between a fixed length byte array shared reference and
91            /// a shared reference to this Hash type.
92            pub fn from_bytes_ref(bytes: &[u8; $bits / 8]) -> &Self {
93                // Safety: Sound because Self is #[repr(transparent)] containing [u8; $bits / 8]
94                unsafe { &*(bytes as *const _ as *const Self) }
95            }
96
97            /// Zero cost conversion between a fixed length byte array exclusive reference and
98            /// an exclusive reference to this Hash type.
99            pub fn from_bytes_mut(bytes: &mut [u8; $bits / 8]) -> &mut Self {
100                // Safety: Sound because Self is #[repr(transparent)] containing [u8; $bits / 8]
101                unsafe { &mut *(bytes as *mut _ as *mut Self) }
102            }
103        }
104
105        impl<$($gen: $gent),*> str::FromStr for Hash<$($gen),*> {
106            type Err = $crate::hex::HexToArrayError;
107            fn from_str(s: &str) -> Result<Self, Self::Err> {
108                use $crate::hex::{FromHex, HexToBytesIter};
109                use $crate::Hash;
110
111                let inner: [u8; $bits / 8] = if $reverse {
112                    FromHex::from_byte_iter(HexToBytesIter::new(s)?.rev())?
113                } else {
114                    FromHex::from_byte_iter(HexToBytesIter::new(s)?)?
115                };
116                Ok(Self::from_byte_array(inner))
117            }
118        }
119
120        $crate::internal_macros::arr_newtype_fmt_impl!(Hash, $bits / 8 $(, $gen: $gent)*);
121        serde_impl!(Hash, $bits / 8 $(, $gen: $gent)*);
122        borrow_slice_impl!(Hash $(, $gen: $gent)*);
123
124        impl<$($gen: $gent),*> $crate::_export::_core::convert::AsRef<[u8; $bits / 8]> for Hash<$($gen),*> {
125            fn as_ref(&self) -> &[u8; $bits / 8] {
126                &self.0
127            }
128        }
129
130        impl<I: SliceIndex<[u8]> $(, $gen: $gent)*> Index<I> for Hash<$($gen),*> {
131            type Output = I::Output;
132
133            #[inline]
134            fn index(&self, index: I) -> &Self::Output {
135                &self.0[index]
136            }
137        }
138
139        impl<$($gen: $gent),*> crate::Hash for Hash<$($gen),*> {
140            type Engine = HashEngine;
141            type Bytes = [u8; $bits / 8];
142
143            const LEN: usize = $bits / 8;
144            const DISPLAY_BACKWARD: bool = $reverse;
145
146            fn engine() -> Self::Engine {
147                Self::internal_engine()
148            }
149
150            fn from_engine(e: HashEngine) -> Hash<$($gen),*> {
151                from_engine(e)
152            }
153
154            fn from_slice(sl: &[u8]) -> Result<Hash<$($gen),*>, FromSliceError> {
155                if sl.len() != $bits / 8 {
156                    Err(FromSliceError{expected: Self::LEN, got: sl.len()})
157                } else {
158                    let mut ret = [0; $bits / 8];
159                    ret.copy_from_slice(sl);
160                    Ok(Self::internal_new(ret))
161                }
162            }
163
164            fn to_byte_array(self) -> Self::Bytes {
165                self.0
166            }
167
168            fn as_byte_array(&self) -> &Self::Bytes {
169                &self.0
170            }
171
172            fn from_byte_array(bytes: Self::Bytes) -> Self {
173                Self::internal_new(bytes)
174            }
175
176            fn all_zeros() -> Self {
177                Hash::internal_new([0x00; $bits / 8])
178            }
179        }
180    }
181}
182pub(crate) use hash_trait_impls;
183
184/// Creates a type called `Hash` and implements standard interface for it.
185///
186/// The created type will have all standard derives, `Hash` impl and implementation of
187/// `internal_engine` returning default. The created type has a single field.
188///
189/// Arguments:
190///
191/// * `$bits` - the number of bits of the hash type
192/// * `$reverse` - `true` if the hash should be displayed backwards, `false` otherwise
193/// * `$doc` - doc string to put on the type
194/// * `$schemars` - a literal that goes into `schema_with`.
195///
196/// The `from_engine` free-standing function is still required with this macro. See the doc of
197/// [`hash_trait_impls`].
198macro_rules! hash_type {
199    ($bits:expr, $reverse:expr, $doc:literal, $schemars:literal) => {
200        #[doc = $doc]
201        #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
202        #[cfg_attr(feature = "schemars", derive(crate::schemars::JsonSchema))]
203        #[repr(transparent)]
204        pub struct Hash(
205            #[cfg_attr(feature = "schemars", schemars(schema_with = $schemars))] [u8; $bits / 8],
206        );
207
208        impl Hash {
209            fn internal_new(arr: [u8; $bits / 8]) -> Self { Hash(arr) }
210
211            fn internal_engine() -> HashEngine { Default::default() }
212        }
213
214        crate::internal_macros::hash_trait_impls!($bits, $reverse);
215    };
216}
217pub(crate) use hash_type;