fixed_hash/
hash.rs

1// Copyright 2020 Parity Technologies
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9/// Construct a fixed-size hash type.
10///
11/// # Examples
12///
13/// Create a public unformatted hash type with 32 bytes size.
14///
15/// ```
16/// use fixed_hash::construct_fixed_hash;
17///
18/// construct_fixed_hash!{ pub struct H256(32); }
19/// assert_eq!(std::mem::size_of::<H256>(), 32);
20/// ```
21///
22/// With additional attributes and doc comments.
23///
24/// ```
25/// use fixed_hash::construct_fixed_hash;
26/// construct_fixed_hash!{
27///     /// My unformatted 160 bytes sized hash type.
28///     #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
29///     pub struct H160(20);
30/// }
31/// assert_eq!(std::mem::size_of::<H160>(), 20);
32/// ```
33///
34/// The visibility modifier is optional and you can create a private hash type.
35///
36/// ```
37/// use fixed_hash::construct_fixed_hash;
38/// construct_fixed_hash!{ struct H512(64); }
39/// assert_eq!(std::mem::size_of::<H512>(), 64);
40/// ```
41#[macro_export(local_inner_macros)]
42macro_rules! construct_fixed_hash {
43	( $(#[$attr:meta])* $visibility:vis struct $name:ident ( $n_bytes:expr ); ) => {
44		#[repr(C)]
45		$(#[$attr])*
46		$visibility struct $name (pub [u8; $n_bytes]);
47
48		impl From<[u8; $n_bytes]> for $name {
49			/// Constructs a hash type from the given bytes array of fixed length.
50			///
51			/// # Note
52			///
53			/// The given bytes are interpreted in big endian order.
54			#[inline]
55			fn from(bytes: [u8; $n_bytes]) -> Self {
56				$name(bytes)
57			}
58		}
59
60		impl<'a> From<&'a [u8; $n_bytes]> for $name {
61			/// Constructs a hash type from the given reference
62			/// to the bytes array of fixed length.
63			///
64			/// # Note
65			///
66			/// The given bytes are interpreted in big endian order.
67			#[inline]
68			fn from(bytes: &'a [u8; $n_bytes]) -> Self {
69				$name(*bytes)
70			}
71		}
72
73		impl<'a> From<&'a mut [u8; $n_bytes]> for $name {
74			/// Constructs a hash type from the given reference
75			/// to the mutable bytes array of fixed length.
76			///
77			/// # Note
78			///
79			/// The given bytes are interpreted in big endian order.
80			#[inline]
81			fn from(bytes: &'a mut [u8; $n_bytes]) -> Self {
82				$name(*bytes)
83			}
84		}
85
86		impl From<$name> for [u8; $n_bytes] {
87			#[inline]
88			fn from(s: $name) -> Self {
89				s.0
90			}
91		}
92
93		impl AsRef<[u8]> for $name {
94			#[inline]
95			fn as_ref(&self) -> &[u8] {
96				self.as_bytes()
97			}
98		}
99
100		impl AsMut<[u8]> for $name {
101			#[inline]
102			fn as_mut(&mut self) -> &mut [u8] {
103				self.as_bytes_mut()
104			}
105		}
106
107		impl $name {
108			/// Returns a new fixed hash where all bits are set to the given byte.
109			#[inline]
110			pub const fn repeat_byte(byte: u8) -> $name {
111				$name([byte; $n_bytes])
112			}
113
114			/// Returns a new zero-initialized fixed hash.
115			#[inline]
116			pub const fn zero() -> $name {
117				$name::repeat_byte(0u8)
118			}
119
120			/// Returns the size of this hash in bytes.
121			#[inline]
122			pub const fn len_bytes() -> usize {
123				$n_bytes
124			}
125
126			/// Extracts a byte slice containing the entire fixed hash.
127			#[inline]
128			pub fn as_bytes(&self) -> &[u8] {
129				&self.0
130			}
131
132			/// Extracts a mutable byte slice containing the entire fixed hash.
133			#[inline]
134			pub fn as_bytes_mut(&mut self) -> &mut [u8] {
135				&mut self.0
136			}
137
138			/// Extracts a reference to the byte array containing the entire fixed hash.
139			#[inline]
140			pub const fn as_fixed_bytes(&self) -> &[u8; $n_bytes] {
141				&self.0
142			}
143
144			/// Extracts a reference to the byte array containing the entire fixed hash.
145			#[inline]
146			pub fn as_fixed_bytes_mut(&mut self) -> &mut [u8; $n_bytes] {
147				&mut self.0
148			}
149
150			/// Returns the inner bytes array.
151			#[inline]
152			pub const fn to_fixed_bytes(self) -> [u8; $n_bytes] {
153				self.0
154			}
155
156			/// Returns a constant raw pointer to the value.
157			#[inline]
158			pub fn as_ptr(&self) -> *const u8 {
159				self.as_bytes().as_ptr()
160			}
161
162			/// Returns a mutable raw pointer to the value.
163			#[inline]
164			pub fn as_mut_ptr(&mut self) -> *mut u8 {
165				self.as_bytes_mut().as_mut_ptr()
166			}
167
168			/// Assign the bytes from the byte slice `src` to `self`.
169			///
170			/// # Note
171			///
172			/// The given bytes are interpreted in big endian order.
173			///
174			/// # Panics
175			///
176			/// If the length of `src` and the number of bytes in `self` do not match.
177			pub fn assign_from_slice(&mut self, src: &[u8]) {
178				$crate::core_::assert_eq!(src.len(), $n_bytes);
179				self.as_bytes_mut().copy_from_slice(src);
180			}
181
182			/// Create a new fixed-hash from the given slice `src`.
183			///
184			/// # Note
185			///
186			/// The given bytes are interpreted in big endian order.
187			///
188			/// # Panics
189			///
190			/// If the length of `src` and the number of bytes in `Self` do not match.
191			pub fn from_slice(src: &[u8]) -> Self {
192				$crate::core_::assert_eq!(src.len(), $n_bytes);
193				let mut ret = Self::zero();
194				ret.assign_from_slice(src);
195				ret
196			}
197
198			/// Returns `true` if all bits set in `b` are also set in `self`.
199			#[inline]
200			pub fn covers(&self, b: &Self) -> bool {
201				&(b & self) == b
202			}
203
204			/// Returns `true` if no bits are set.
205			#[inline]
206			pub fn is_zero(&self) -> bool {
207				self.as_bytes().iter().all(|&byte| byte == 0u8)
208			}
209		}
210
211		impl $crate::core_::fmt::Debug for $name {
212			fn fmt(&self, f: &mut $crate::core_::fmt::Formatter) -> $crate::core_::fmt::Result {
213				$crate::core_::write!(f, "{:#x}", self)
214			}
215		}
216
217		impl $crate::core_::fmt::Display for $name {
218			fn fmt(&self, f: &mut $crate::core_::fmt::Formatter) -> $crate::core_::fmt::Result {
219				$crate::core_::write!(f, "0x")?;
220				for i in &self.0[0..2] {
221					$crate::core_::write!(f, "{:02x}", i)?;
222				}
223				$crate::core_::write!(f, "…")?;
224				for i in &self.0[$n_bytes - 2..$n_bytes] {
225					$crate::core_::write!(f, "{:02x}", i)?;
226				}
227				Ok(())
228			}
229		}
230
231		impl $crate::core_::fmt::LowerHex for $name {
232			fn fmt(&self, f: &mut $crate::core_::fmt::Formatter) -> $crate::core_::fmt::Result {
233				if f.alternate() {
234					$crate::core_::write!(f, "0x")?;
235				}
236				for i in &self.0[..] {
237					$crate::core_::write!(f, "{:02x}", i)?;
238				}
239				Ok(())
240			}
241		}
242
243		impl $crate::core_::fmt::UpperHex for $name {
244			fn fmt(&self, f: &mut $crate::core_::fmt::Formatter) -> $crate::core_::fmt::Result {
245				if f.alternate() {
246					$crate::core_::write!(f, "0X")?;
247				}
248				for i in &self.0[..] {
249					$crate::core_::write!(f, "{:02X}", i)?;
250				}
251				Ok(())
252			}
253		}
254
255		impl $crate::core_::marker::Copy for $name {}
256
257		#[cfg_attr(feature = "dev", allow(expl_impl_clone_on_copy))]
258		impl $crate::core_::clone::Clone for $name {
259			fn clone(&self) -> $name {
260				let mut ret = $name::zero();
261				ret.0.copy_from_slice(&self.0);
262				ret
263			}
264		}
265
266		impl $crate::core_::cmp::Eq for $name {}
267
268		impl $crate::core_::cmp::PartialOrd for $name {
269			fn partial_cmp(&self, other: &Self) -> Option<$crate::core_::cmp::Ordering> {
270				Some(self.cmp(other))
271			}
272		}
273
274		impl $crate::core_::hash::Hash for $name {
275			fn hash<H>(&self, state: &mut H) where H: $crate::core_::hash::Hasher {
276				state.write(&self.0);
277			}
278		}
279
280		impl<I> $crate::core_::ops::Index<I> for $name
281		where
282			I: $crate::core_::slice::SliceIndex<[u8]>
283		{
284			type Output = I::Output;
285
286			#[inline]
287			fn index(&self, index: I) -> &I::Output {
288				&self.as_bytes()[index]
289			}
290		}
291
292		impl<I> $crate::core_::ops::IndexMut<I> for $name
293		where
294			I: $crate::core_::slice::SliceIndex<[u8], Output = [u8]>
295		{
296			#[inline]
297			fn index_mut(&mut self, index: I) -> &mut I::Output {
298				&mut self.as_bytes_mut()[index]
299			}
300		}
301
302		impl $crate::core_::default::Default for $name {
303			#[inline]
304			fn default() -> Self {
305				Self::zero()
306			}
307		}
308
309		impl_ops_for_hash!($name, BitOr, bitor, BitOrAssign, bitor_assign, |, |=);
310		impl_ops_for_hash!($name, BitAnd, bitand, BitAndAssign, bitand_assign, &, &=);
311		impl_ops_for_hash!($name, BitXor, bitxor, BitXorAssign, bitxor_assign, ^, ^=);
312
313		impl_byteorder_for_fixed_hash!($name);
314		impl_rand_for_fixed_hash!($name);
315		impl_cmp_for_fixed_hash!($name);
316		impl_rustc_hex_for_fixed_hash!($name);
317		impl_quickcheck_for_fixed_hash!($name);
318		impl_arbitrary_for_fixed_hash!($name);
319	}
320}
321
322// Implementation for disabled byteorder crate support.
323//
324// # Note
325//
326// Feature guarded macro definitions instead of feature guarded impl blocks
327// to work around the problems of introducing `byteorder` crate feature in
328// a user crate.
329#[cfg(not(feature = "byteorder"))]
330#[macro_export]
331#[doc(hidden)]
332macro_rules! impl_byteorder_for_fixed_hash {
333	( $name:ident ) => {};
334}
335
336// Implementation for enabled byteorder crate support.
337//
338// # Note
339//
340// Feature guarded macro definitions instead of feature guarded impl blocks
341// to work around the problems of introducing `byteorder` crate feature in
342// a user crate.
343#[cfg(feature = "byteorder")]
344#[macro_export]
345#[doc(hidden)]
346macro_rules! impl_byteorder_for_fixed_hash {
347	( $name:ident ) => {
348		/// Utilities using the `byteorder` crate.
349		impl $name {
350			/// Returns the least significant `n` bytes as slice.
351			///
352			/// # Panics
353			///
354			/// If `n` is greater than the number of bytes in `self`.
355			#[inline]
356			fn least_significant_bytes(&self, n: usize) -> &[u8] {
357				$crate::core_::assert_eq!(true, n <= Self::len_bytes());
358				&self[(Self::len_bytes() - n)..]
359			}
360
361			fn to_low_u64_with_byteorder<B>(&self) -> u64
362			where
363				B: $crate::byteorder::ByteOrder,
364			{
365				let mut buf = [0x0; 8];
366				let capped = $crate::core_::cmp::min(Self::len_bytes(), 8);
367				buf[(8 - capped)..].copy_from_slice(self.least_significant_bytes(capped));
368				B::read_u64(&buf)
369			}
370
371			/// Returns the lowest 8 bytes interpreted as big-endian.
372			///
373			/// # Note
374			///
375			/// For hash type with less than 8 bytes the missing bytes
376			/// are interpreted as being zero.
377			#[inline]
378			pub fn to_low_u64_be(&self) -> u64 {
379				self.to_low_u64_with_byteorder::<$crate::byteorder::BigEndian>()
380			}
381
382			/// Returns the lowest 8 bytes interpreted as little-endian.
383			///
384			/// # Note
385			///
386			/// For hash type with less than 8 bytes the missing bytes
387			/// are interpreted as being zero.
388			#[inline]
389			pub fn to_low_u64_le(&self) -> u64 {
390				self.to_low_u64_with_byteorder::<$crate::byteorder::LittleEndian>()
391			}
392
393			/// Returns the lowest 8 bytes interpreted as native-endian.
394			///
395			/// # Note
396			///
397			/// For hash type with less than 8 bytes the missing bytes
398			/// are interpreted as being zero.
399			#[inline]
400			pub fn to_low_u64_ne(&self) -> u64 {
401				self.to_low_u64_with_byteorder::<$crate::byteorder::NativeEndian>()
402			}
403
404			fn from_low_u64_with_byteorder<B>(val: u64) -> Self
405			where
406				B: $crate::byteorder::ByteOrder,
407			{
408				let mut buf = [0x0; 8];
409				B::write_u64(&mut buf, val);
410				let capped = $crate::core_::cmp::min(Self::len_bytes(), 8);
411				let mut bytes = [0x0; $crate::core_::mem::size_of::<Self>()];
412				bytes[(Self::len_bytes() - capped)..].copy_from_slice(&buf[..capped]);
413				Self::from_slice(&bytes)
414			}
415
416			/// Creates a new hash type from the given `u64` value.
417			///
418			/// # Note
419			///
420			/// - The given `u64` value is interpreted as big endian.
421			/// - Ignores the most significant bits of the given value
422			///   if the hash type has less than 8 bytes.
423			#[inline]
424			pub fn from_low_u64_be(val: u64) -> Self {
425				Self::from_low_u64_with_byteorder::<$crate::byteorder::BigEndian>(val)
426			}
427
428			/// Creates a new hash type from the given `u64` value.
429			///
430			/// # Note
431			///
432			/// - The given `u64` value is interpreted as little endian.
433			/// - Ignores the most significant bits of the given value
434			///   if the hash type has less than 8 bytes.
435			#[inline]
436			pub fn from_low_u64_le(val: u64) -> Self {
437				Self::from_low_u64_with_byteorder::<$crate::byteorder::LittleEndian>(val)
438			}
439
440			/// Creates a new hash type from the given `u64` value.
441			///
442			/// # Note
443			///
444			/// - The given `u64` value is interpreted as native endian.
445			/// - Ignores the most significant bits of the given value
446			///   if the hash type has less than 8 bytes.
447			#[inline]
448			pub fn from_low_u64_ne(val: u64) -> Self {
449				Self::from_low_u64_with_byteorder::<$crate::byteorder::NativeEndian>(val)
450			}
451		}
452	};
453}
454
455// Implementation for disabled rand crate support.
456//
457// # Note
458//
459// Feature guarded macro definitions instead of feature guarded impl blocks
460// to work around the problems of introducing `rand` crate feature in
461// a user crate.
462#[cfg(not(feature = "rand"))]
463#[macro_export]
464#[doc(hidden)]
465macro_rules! impl_rand_for_fixed_hash {
466	( $name:ident ) => {};
467}
468
469// Implementation for enabled rand crate support.
470//
471// # Note
472//
473// Feature guarded macro definitions instead of feature guarded impl blocks
474// to work around the problems of introducing `rand` crate feature in
475// a user crate.
476#[cfg(feature = "rand")]
477#[macro_export]
478#[doc(hidden)]
479macro_rules! impl_rand_for_fixed_hash {
480	( $name:ident ) => {
481		impl $crate::rand::distributions::Distribution<$name> for $crate::rand::distributions::Standard {
482			fn sample<R: $crate::rand::Rng + ?Sized>(&self, rng: &mut R) -> $name {
483				let mut ret = $name::zero();
484				for byte in ret.as_bytes_mut().iter_mut() {
485					*byte = rng.gen();
486				}
487				ret
488			}
489		}
490
491		/// Utilities using the `rand` crate.
492		impl $name {
493			/// Assign `self` to a cryptographically random value using the
494			/// given random number generator.
495			pub fn randomize_using<R>(&mut self, rng: &mut R)
496			where
497				R: $crate::rand::Rng + ?Sized,
498			{
499				use $crate::rand::distributions::Distribution;
500				*self = $crate::rand::distributions::Standard.sample(rng);
501			}
502
503			/// Assign `self` to a cryptographically random value.
504			pub fn randomize(&mut self) {
505				let mut rng = $crate::rand::rngs::OsRng;
506				self.randomize_using(&mut rng);
507			}
508
509			/// Create a new hash with cryptographically random content using the
510			/// given random number generator.
511			pub fn random_using<R>(rng: &mut R) -> Self
512			where
513				R: $crate::rand::Rng + ?Sized,
514			{
515				let mut ret = Self::zero();
516				ret.randomize_using(rng);
517				ret
518			}
519
520			/// Create a new hash with cryptographically random content.
521			pub fn random() -> Self {
522				let mut hash = Self::zero();
523				hash.randomize();
524				hash
525			}
526		}
527	};
528}
529
530#[macro_export]
531#[doc(hidden)]
532macro_rules! impl_cmp_for_fixed_hash {
533	( $name:ident ) => {
534		impl $crate::core_::cmp::PartialEq for $name {
535			#[inline]
536			fn eq(&self, other: &Self) -> bool {
537				self.as_bytes() == other.as_bytes()
538			}
539		}
540
541		impl $crate::core_::cmp::Ord for $name {
542			#[inline]
543			fn cmp(&self, other: &Self) -> $crate::core_::cmp::Ordering {
544				self.as_bytes().cmp(other.as_bytes())
545			}
546		}
547	};
548}
549
550// Implementation for disabled rustc-hex crate support.
551//
552// # Note
553//
554// Feature guarded macro definitions instead of feature guarded impl blocks
555// to work around the problems of introducing `rustc-hex` crate feature in
556// a user crate.
557#[cfg(not(feature = "rustc-hex"))]
558#[macro_export]
559#[doc(hidden)]
560macro_rules! impl_rustc_hex_for_fixed_hash {
561	( $name:ident ) => {};
562}
563
564// Implementation for enabled rustc-hex crate support.
565//
566// # Note
567//
568// Feature guarded macro definitions instead of feature guarded impl blocks
569// to work around the problems of introducing `rustc-hex` crate feature in
570// a user crate.
571#[cfg(feature = "rustc-hex")]
572#[macro_export]
573#[doc(hidden)]
574macro_rules! impl_rustc_hex_for_fixed_hash {
575	( $name:ident ) => {
576		impl $crate::core_::str::FromStr for $name {
577			type Err = $crate::rustc_hex::FromHexError;
578
579			/// Creates a hash type instance from the given string.
580			///
581			/// # Note
582			///
583			/// The given input string is interpreted in big endian.
584			///
585			/// # Errors
586			///
587			/// - When encountering invalid non hex-digits
588			/// - Upon empty string input or invalid input length in general
589			fn from_str(input: &str) -> $crate::core_::result::Result<$name, $crate::rustc_hex::FromHexError> {
590				let input = input.strip_prefix("0x").unwrap_or(input);
591				let mut iter = $crate::rustc_hex::FromHexIter::new(input);
592				let mut result = Self::zero();
593				for byte in result.as_mut() {
594					*byte = iter.next().ok_or(Self::Err::InvalidHexLength)??;
595				}
596				if iter.next().is_some() {
597					return Err(Self::Err::InvalidHexLength)
598				}
599				Ok(result)
600			}
601		}
602	};
603}
604
605// Implementation for disabled quickcheck crate support.
606//
607// # Note
608//
609// Feature guarded macro definitions instead of feature guarded impl blocks
610// to work around the problems of introducing `quickcheck` crate feature in
611// a user crate.
612#[cfg(not(feature = "quickcheck"))]
613#[macro_export]
614#[doc(hidden)]
615macro_rules! impl_quickcheck_for_fixed_hash {
616	( $name:ident ) => {};
617}
618
619// Implementation for enabled quickcheck crate support.
620//
621// # Note
622//
623// Feature guarded macro definitions instead of feature guarded impl blocks
624// to work around the problems of introducing `quickcheck` crate feature in
625// a user crate.
626#[cfg(feature = "quickcheck")]
627#[macro_export]
628#[doc(hidden)]
629macro_rules! impl_quickcheck_for_fixed_hash {
630	( $name:ident ) => {
631		impl $crate::quickcheck::Arbitrary for $name {
632			fn arbitrary(g: &mut $crate::quickcheck::Gen) -> Self {
633				let res: [u8; Self::len_bytes()] = $crate::core_::array::from_fn(|_| u8::arbitrary(g));
634				Self::from(res)
635			}
636		}
637	};
638}
639
640// When the `arbitrary` feature is disabled.
641//
642// # Note
643//
644// Feature guarded macro definitions instead of feature guarded impl blocks
645// to work around the problems of introducing `arbitrary` crate feature in
646// a user crate.
647#[cfg(not(feature = "arbitrary"))]
648#[macro_export]
649#[doc(hidden)]
650macro_rules! impl_arbitrary_for_fixed_hash {
651	( $name:ident ) => {};
652}
653
654// When the `arbitrary` feature is enabled.
655//
656// # Note
657//
658// Feature guarded macro definitions instead of feature guarded impl blocks
659// to work around the problems of introducing `arbitrary` crate feature in
660// a user crate.
661#[cfg(feature = "arbitrary")]
662#[macro_export]
663#[doc(hidden)]
664macro_rules! impl_arbitrary_for_fixed_hash {
665	( $name:ident ) => {
666		impl $crate::arbitrary::Arbitrary<'_> for $name {
667			fn arbitrary(u: &mut $crate::arbitrary::Unstructured<'_>) -> $crate::arbitrary::Result<Self> {
668				let mut res = Self::zero();
669				u.fill_buffer(&mut res.0)?;
670				Ok(Self::from(res))
671			}
672		}
673	};
674}
675
676#[macro_export]
677#[doc(hidden)]
678macro_rules! impl_ops_for_hash {
679	(
680		$impl_for:ident,
681		$ops_trait_name:ident,
682		$ops_fn_name:ident,
683		$ops_assign_trait_name:ident,
684		$ops_assign_fn_name:ident,
685		$ops_tok:tt,
686		$ops_assign_tok:tt
687	) => {
688		impl<'r> $crate::core_::ops::$ops_assign_trait_name<&'r $impl_for> for $impl_for {
689			fn $ops_assign_fn_name(&mut self, rhs: &'r $impl_for) {
690				for (lhs, rhs) in self.as_bytes_mut().iter_mut().zip(rhs.as_bytes()) {
691					*lhs $ops_assign_tok rhs;
692				}
693			}
694		}
695
696		impl $crate::core_::ops::$ops_assign_trait_name<$impl_for> for $impl_for {
697			#[inline]
698			fn $ops_assign_fn_name(&mut self, rhs: $impl_for) {
699				*self $ops_assign_tok &rhs;
700			}
701		}
702
703		impl<'l, 'r> $crate::core_::ops::$ops_trait_name<&'r $impl_for> for &'l $impl_for {
704			type Output = $impl_for;
705
706			fn $ops_fn_name(self, rhs: &'r $impl_for) -> Self::Output {
707				let mut ret = self.clone();
708				ret $ops_assign_tok rhs;
709				ret
710			}
711		}
712
713		impl $crate::core_::ops::$ops_trait_name<$impl_for> for $impl_for {
714			type Output = $impl_for;
715
716			#[inline]
717			fn $ops_fn_name(self, rhs: Self) -> Self::Output {
718				&self $ops_tok &rhs
719			}
720		}
721	};
722}
723
724/// Implements lossy conversions between the given types.
725///
726/// # Note
727///
728/// - Both types must be of different sizes.
729/// - Type `large_ty` must have a larger memory footprint compared to `small_ty`.
730///
731/// # Panics
732///
733/// Both `From` implementations will panic if sizes of the given types
734/// do not meet the requirements stated above.
735///
736/// # Example
737///
738/// ```
739/// use fixed_hash::{construct_fixed_hash, impl_fixed_hash_conversions};
740/// construct_fixed_hash!{ struct H160(20); }
741/// construct_fixed_hash!{ struct H256(32); }
742/// impl_fixed_hash_conversions!(H256, H160);
743/// // now use it!
744/// assert_eq!(H256::from(H160::zero()), H256::zero());
745/// assert_eq!(H160::from(H256::zero()), H160::zero());
746/// ```
747#[macro_export(local_inner_macros)]
748macro_rules! impl_fixed_hash_conversions {
749	($large_ty:ident, $small_ty:ident) => {
750		$crate::static_assertions::const_assert!(
751			$crate::core_::mem::size_of::<$small_ty>() < $crate::core_::mem::size_of::<$large_ty>()
752		);
753
754		impl From<$small_ty> for $large_ty {
755			fn from(value: $small_ty) -> $large_ty {
756				let large_ty_size = $large_ty::len_bytes();
757				let small_ty_size = $small_ty::len_bytes();
758
759				$crate::core_::debug_assert!(
760					large_ty_size > small_ty_size && large_ty_size % 2 == 0 && small_ty_size % 2 == 0
761				);
762
763				let mut ret = $large_ty::zero();
764				ret.as_bytes_mut()[(large_ty_size - small_ty_size)..large_ty_size].copy_from_slice(value.as_bytes());
765				ret
766			}
767		}
768
769		impl From<$large_ty> for $small_ty {
770			fn from(value: $large_ty) -> $small_ty {
771				let large_ty_size = $large_ty::len_bytes();
772				let small_ty_size = $small_ty::len_bytes();
773
774				$crate::core_::debug_assert!(
775					large_ty_size > small_ty_size && large_ty_size % 2 == 0 && small_ty_size % 2 == 0
776				);
777
778				let mut ret = $small_ty::zero();
779				ret.as_bytes_mut()
780					.copy_from_slice(&value[(large_ty_size - small_ty_size)..large_ty_size]);
781				ret
782			}
783		}
784	};
785}