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