1use crate::aliases;
2use core::{fmt, iter, ops, str};
3use derive_more::{Deref, DerefMut, From, Index, IndexMut, IntoIterator};
4use hex::FromHex;
5
6#[derive(
16 Clone,
17 Copy,
18 PartialEq,
19 Eq,
20 PartialOrd,
21 Ord,
22 Hash,
23 Deref,
24 DerefMut,
25 From,
26 Index,
27 IndexMut,
28 IntoIterator,
29)]
30#[cfg_attr(feature = "arbitrary", derive(derive_arbitrary::Arbitrary, proptest_derive::Arbitrary))]
31#[cfg_attr(feature = "allocative", derive(allocative::Allocative))]
32#[cfg_attr(feature = "diesel", derive(diesel::AsExpression, diesel::FromSqlRow))]
33#[cfg_attr(feature = "diesel", diesel(sql_type = diesel::sql_types::Binary))]
34#[repr(transparent)]
35pub struct FixedBytes<const N: usize>(#[into_iterator(owned, ref, ref_mut)] pub [u8; N]);
36
37crate::impl_fb_traits!(FixedBytes<N>, N, const);
38
39impl<const N: usize> Default for FixedBytes<N> {
40 #[inline]
41 fn default() -> Self {
42 Self::ZERO
43 }
44}
45
46impl<const N: usize> Default for &FixedBytes<N> {
47 #[inline]
48 fn default() -> Self {
49 &FixedBytes::ZERO
50 }
51}
52
53impl<const N: usize> From<&[u8; N]> for FixedBytes<N> {
54 #[inline]
55 fn from(bytes: &[u8; N]) -> Self {
56 Self(*bytes)
57 }
58}
59
60impl<const N: usize> From<&mut [u8; N]> for FixedBytes<N> {
61 #[inline]
62 fn from(bytes: &mut [u8; N]) -> Self {
63 Self(*bytes)
64 }
65}
66
67impl<const N: usize> TryFrom<&[u8]> for FixedBytes<N> {
70 type Error = core::array::TryFromSliceError;
71
72 #[inline]
73 fn try_from(slice: &[u8]) -> Result<Self, Self::Error> {
74 <&Self>::try_from(slice).copied()
75 }
76}
77
78impl<const N: usize> TryFrom<&mut [u8]> for FixedBytes<N> {
81 type Error = core::array::TryFromSliceError;
82
83 #[inline]
84 fn try_from(slice: &mut [u8]) -> Result<Self, Self::Error> {
85 Self::try_from(&*slice)
86 }
87}
88
89impl<'a, const N: usize> TryFrom<&'a [u8]> for &'a FixedBytes<N> {
92 type Error = core::array::TryFromSliceError;
93
94 #[inline]
95 fn try_from(slice: &'a [u8]) -> Result<&'a FixedBytes<N>, Self::Error> {
96 <&[u8; N]>::try_from(slice).map(|array_ref| unsafe { core::mem::transmute(array_ref) })
98 }
99}
100
101impl<'a, const N: usize> TryFrom<&'a mut [u8]> for &'a mut FixedBytes<N> {
104 type Error = core::array::TryFromSliceError;
105
106 #[inline]
107 fn try_from(slice: &'a mut [u8]) -> Result<&'a mut FixedBytes<N>, Self::Error> {
108 <&mut [u8; N]>::try_from(slice).map(|array_ref| unsafe { core::mem::transmute(array_ref) })
110 }
111}
112
113macro_rules! fixed_bytes_uint_conversions {
117 ($($int:ty => $fb:ty),* $(,)?) => {$(
118 impl From<$int> for $fb {
119 #[inline]
122 fn from(value: $int) -> Self {
123 Self(value.to_be_bytes())
124 }
125 }
126
127 impl From<$fb> for $int {
128 #[inline]
131 fn from(value: $fb) -> Self {
132 Self::from_be_bytes(value.0)
133 }
134 }
135
136 const _: () = assert!(<$int>::BITS as usize == <$fb>::len_bytes() * 8);
137 )*};
138}
139
140fixed_bytes_uint_conversions! {
141 u8 => aliases::B8,
142 aliases::U8 => aliases::B8,
143 i8 => aliases::B8,
144 aliases::I8 => aliases::B8,
145
146 u16 => aliases::B16,
147 aliases::U16 => aliases::B16,
148 i16 => aliases::B16,
149 aliases::I16 => aliases::B16,
150
151 u32 => aliases::B32,
152 aliases::U32 => aliases::B32,
153 i32 => aliases::B32,
154 aliases::I32 => aliases::B32,
155
156 u64 => aliases::B64,
157 aliases::U64 => aliases::B64,
158 i64 => aliases::B64,
159 aliases::I64 => aliases::B64,
160
161 u128 => aliases::B128,
162 aliases::U128 => aliases::B128,
163 i128 => aliases::B128,
164 aliases::I128 => aliases::B128,
165
166 aliases::U160 => aliases::B160,
167 aliases::I160 => aliases::B160,
168
169 aliases::U256 => aliases::B256,
170 aliases::I256 => aliases::B256,
171
172 aliases::U512 => aliases::B512,
173 aliases::I512 => aliases::B512,
174
175}
176
177impl<const N: usize> From<FixedBytes<N>> for [u8; N] {
178 #[inline]
179 fn from(s: FixedBytes<N>) -> Self {
180 s.0
181 }
182}
183
184impl<const N: usize> AsRef<[u8; N]> for FixedBytes<N> {
185 #[inline]
186 fn as_ref(&self) -> &[u8; N] {
187 &self.0
188 }
189}
190
191impl<const N: usize> AsMut<[u8; N]> for FixedBytes<N> {
192 #[inline]
193 fn as_mut(&mut self) -> &mut [u8; N] {
194 &mut self.0
195 }
196}
197
198impl<const N: usize> AsRef<[u8]> for FixedBytes<N> {
199 #[inline]
200 fn as_ref(&self) -> &[u8] {
201 &self.0
202 }
203}
204
205impl<const N: usize> AsMut<[u8]> for FixedBytes<N> {
206 #[inline]
207 fn as_mut(&mut self) -> &mut [u8] {
208 &mut self.0
209 }
210}
211
212impl<const N: usize> fmt::Debug for FixedBytes<N> {
213 #[inline]
214 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
215 self.fmt_hex::<false>(f, true)
216 }
217}
218
219impl<const N: usize> fmt::Display for FixedBytes<N> {
220 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
221 if N <= 4 || !f.alternate() {
223 return self.fmt_hex::<false>(f, true);
224 }
225
226 const SEP_LEN: usize = '…'.len_utf8();
228 let mut buf = [0; 2 + 4 + SEP_LEN + 4];
229 buf[0] = b'0';
230 buf[1] = b'x';
231 hex::encode_to_slice(&self.0[0..2], &mut buf[2..6]).unwrap();
232 '…'.encode_utf8(&mut buf[6..]);
233 hex::encode_to_slice(&self.0[N - 2..N], &mut buf[6 + SEP_LEN..]).unwrap();
234
235 f.write_str(unsafe { str::from_utf8_unchecked(&buf) })
237 }
238}
239
240impl<const N: usize> fmt::LowerHex for FixedBytes<N> {
241 #[inline]
242 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
243 self.fmt_hex::<false>(f, f.alternate())
244 }
245}
246
247impl<const N: usize> fmt::UpperHex for FixedBytes<N> {
248 #[inline]
249 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
250 self.fmt_hex::<true>(f, f.alternate())
251 }
252}
253
254impl<const N: usize> ops::BitAndAssign for FixedBytes<N> {
255 #[inline]
256 fn bitand_assign(&mut self, rhs: Self) {
257 *self &= &rhs;
258 }
259}
260
261impl<const N: usize> ops::BitOrAssign for FixedBytes<N> {
262 #[inline]
263 fn bitor_assign(&mut self, rhs: Self) {
264 *self |= &rhs;
265 }
266}
267
268impl<const N: usize> ops::BitXorAssign for FixedBytes<N> {
269 #[inline]
270 fn bitxor_assign(&mut self, rhs: Self) {
271 *self ^= &rhs;
272 }
273}
274
275impl<const N: usize> ops::BitAndAssign<&Self> for FixedBytes<N> {
276 #[inline]
277 fn bitand_assign(&mut self, rhs: &Self) {
278 iter::zip(self, rhs).for_each(|(a, b)| *a &= *b);
279 }
280}
281
282impl<const N: usize> ops::BitOrAssign<&Self> for FixedBytes<N> {
283 #[inline]
284 fn bitor_assign(&mut self, rhs: &Self) {
285 iter::zip(self, rhs).for_each(|(a, b)| *a |= *b);
286 }
287}
288
289impl<const N: usize> ops::BitXorAssign<&Self> for FixedBytes<N> {
290 #[inline]
291 fn bitxor_assign(&mut self, rhs: &Self) {
292 iter::zip(self, rhs).for_each(|(a, b)| *a ^= *b);
293 }
294}
295
296impl<const N: usize> ops::BitAnd for FixedBytes<N> {
297 type Output = Self;
298
299 #[inline]
300 fn bitand(mut self, rhs: Self) -> Self::Output {
301 self &= &rhs;
302 self
303 }
304}
305
306impl<const N: usize> ops::BitOr for FixedBytes<N> {
307 type Output = Self;
308
309 #[inline]
310 fn bitor(mut self, rhs: Self) -> Self::Output {
311 self |= &rhs;
312 self
313 }
314}
315
316impl<const N: usize> ops::BitXor for FixedBytes<N> {
317 type Output = Self;
318
319 #[inline]
320 fn bitxor(mut self, rhs: Self) -> Self::Output {
321 self ^= &rhs;
322 self
323 }
324}
325
326impl<const N: usize> ops::BitAnd<&Self> for FixedBytes<N> {
327 type Output = Self;
328
329 #[inline]
330 fn bitand(mut self, rhs: &Self) -> Self::Output {
331 self &= rhs;
332 self
333 }
334}
335
336impl<const N: usize> ops::BitOr<&Self> for FixedBytes<N> {
337 type Output = Self;
338
339 #[inline]
340 fn bitor(mut self, rhs: &Self) -> Self::Output {
341 self |= rhs;
342 self
343 }
344}
345
346impl<const N: usize> ops::BitXor<&Self> for FixedBytes<N> {
347 type Output = Self;
348
349 #[inline]
350 fn bitxor(mut self, rhs: &Self) -> Self::Output {
351 self ^= rhs;
352 self
353 }
354}
355
356impl<const N: usize> ops::Not for FixedBytes<N> {
357 type Output = Self;
358
359 #[inline]
360 fn not(mut self) -> Self::Output {
361 self.iter_mut().for_each(|byte| *byte = !*byte);
362 self
363 }
364}
365
366impl<const N: usize> str::FromStr for FixedBytes<N> {
367 type Err = hex::FromHexError;
368
369 #[inline]
370 fn from_str(s: &str) -> Result<Self, Self::Err> {
371 Self::from_hex(s)
372 }
373}
374
375#[cfg(feature = "rand")]
376impl<const N: usize> rand::distr::Distribution<FixedBytes<N>> for rand::distr::StandardUniform {
377 #[inline]
378 fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> FixedBytes<N> {
379 FixedBytes::random_with(rng)
380 }
381}
382
383impl<const N: usize> FixedBytes<N> {
384 pub const ZERO: Self = Self([0u8; N]);
386
387 #[inline]
389 pub const fn new(bytes: [u8; N]) -> Self {
390 Self(bytes)
391 }
392
393 #[inline]
395 pub const fn with_last_byte(x: u8) -> Self {
396 let mut bytes = [0u8; N];
397 if N > 0 {
398 bytes[N - 1] = x;
399 }
400 Self(bytes)
401 }
402
403 #[inline]
405 pub const fn repeat_byte(byte: u8) -> Self {
406 Self([byte; N])
407 }
408
409 #[inline(always)]
411 pub const fn len_bytes() -> usize {
412 N
413 }
414
415 #[cfg(feature = "getrandom")]
420 #[inline]
421 #[track_caller]
422 pub fn random() -> Self {
423 let mut bytes = Self::ZERO;
424 bytes.randomize();
425 bytes
426 }
427
428 #[cfg(feature = "getrandom")]
433 #[inline]
434 pub fn try_random() -> Result<Self, getrandom::Error> {
435 let mut bytes = Self::ZERO;
436 bytes.try_randomize()?;
437 Ok(bytes)
438 }
439
440 #[cfg(feature = "rand")]
444 #[inline]
445 #[doc(alias = "random_using")]
446 pub fn random_with<R: rand::RngCore + ?Sized>(rng: &mut R) -> Self {
447 let mut bytes = Self::ZERO;
448 bytes.randomize_with(rng);
449 bytes
450 }
451
452 #[cfg(feature = "rand")]
454 #[inline]
455 pub fn try_random_with<R: rand::TryRngCore + ?Sized>(rng: &mut R) -> Result<Self, R::Error> {
456 let mut bytes = Self::ZERO;
457 bytes.try_randomize_with(rng)?;
458 Ok(bytes)
459 }
460
461 #[cfg(feature = "getrandom")]
465 #[inline]
466 #[track_caller]
467 pub fn randomize(&mut self) {
468 self.try_randomize().unwrap_or_else(|e| panic!("failed to fill with random bytes: {e}"));
469 }
470
471 #[inline]
476 #[cfg(feature = "getrandom")]
477 pub fn try_randomize(&mut self) -> Result<(), getrandom::Error> {
478 #[cfg(all(feature = "rand", feature = "std"))]
479 {
480 self.randomize_with(&mut rand::rng());
481 Ok(())
482 }
483 #[cfg(not(all(feature = "rand", feature = "std")))]
484 {
485 getrandom::fill(&mut self.0)
486 }
487 }
488
489 #[cfg(feature = "rand")]
491 #[inline]
492 #[doc(alias = "randomize_using")]
493 pub fn randomize_with<R: rand::RngCore + ?Sized>(&mut self, rng: &mut R) {
494 rng.fill_bytes(&mut self.0);
495 }
496
497 #[inline]
499 #[cfg(feature = "rand")]
500 pub fn try_randomize_with<R: rand::TryRngCore + ?Sized>(
501 &mut self,
502 rng: &mut R,
503 ) -> Result<(), R::Error> {
504 rng.try_fill_bytes(&mut self.0)
505 }
506
507 pub const fn concat_const<const M: usize, const Z: usize>(
516 self,
517 other: FixedBytes<M>,
518 ) -> FixedBytes<Z> {
519 assert!(N + M == Z, "Output size `Z` must equal the sum of the input sizes `N` and `M`");
520
521 let mut result = [0u8; Z];
522 let mut i = 0;
523 while i < Z {
524 result[i] = if i >= N { other.0[i - N] } else { self.0[i] };
525 i += 1;
526 }
527 FixedBytes(result)
528 }
529
530 #[inline]
542 #[track_caller]
543 pub fn from_slice(src: &[u8]) -> Self {
544 match Self::try_from(src) {
545 Ok(x) => x,
546 Err(_) => panic!("cannot convert a slice of length {} to FixedBytes<{N}>", src.len()),
547 }
548 }
549
550 #[inline]
561 #[track_caller]
562 pub fn left_padding_from(value: &[u8]) -> Self {
563 let len = value.len();
564 assert!(len <= N, "slice is too large. Expected <={N} bytes, got {len}");
565 let mut bytes = Self::ZERO;
566 bytes[N - len..].copy_from_slice(value);
567 bytes
568 }
569
570 #[inline]
581 #[track_caller]
582 pub fn right_padding_from(value: &[u8]) -> Self {
583 let len = value.len();
584 assert!(len <= N, "slice is too large. Expected <={N} bytes, got {len}");
585 let mut bytes = Self::ZERO;
586 bytes[..len].copy_from_slice(value);
587 bytes
588 }
589
590 #[inline]
592 pub const fn as_slice(&self) -> &[u8] {
593 &self.0
594 }
595
596 #[inline]
599 pub fn as_mut_slice(&mut self) -> &mut [u8] {
600 &mut self.0
601 }
602
603 #[inline]
605 pub fn covers(&self, other: &Self) -> bool {
606 (*self & *other) == *other
607 }
608
609 pub const fn const_covers(self, other: Self) -> bool {
611 other.const_eq(&self.bit_and(other))
613 }
614
615 pub const fn const_eq(&self, other: &Self) -> bool {
617 let mut i = 0;
618 while i < N {
619 if self.0[i] != other.0[i] {
620 return false;
621 }
622 i += 1;
623 }
624 true
625 }
626
627 #[inline]
629 pub fn is_zero(&self) -> bool {
630 *self == Self::ZERO
631 }
632
633 #[inline]
635 pub const fn const_is_zero(&self) -> bool {
636 self.const_eq(&Self::ZERO)
637 }
638
639 pub const fn bit_and(self, rhs: Self) -> Self {
641 let mut ret = Self::ZERO;
642 let mut i = 0;
643 while i < N {
644 ret.0[i] = self.0[i] & rhs.0[i];
645 i += 1;
646 }
647 ret
648 }
649
650 pub const fn bit_or(self, rhs: Self) -> Self {
652 let mut ret = Self::ZERO;
653 let mut i = 0;
654 while i < N {
655 ret.0[i] = self.0[i] | rhs.0[i];
656 i += 1;
657 }
658 ret
659 }
660
661 pub const fn bit_xor(self, rhs: Self) -> Self {
663 let mut ret = Self::ZERO;
664 let mut i = 0;
665 while i < N {
666 ret.0[i] = self.0[i] ^ rhs.0[i];
667 i += 1;
668 }
669 ret
670 }
671
672 fn fmt_hex<const UPPER: bool>(&self, f: &mut fmt::Formatter<'_>, prefix: bool) -> fmt::Result {
673 let mut buf = hex::Buffer::<N, true>::new();
674 let s = if UPPER { buf.format_upper(self) } else { buf.format(self) };
675 f.write_str(unsafe { s.get_unchecked((!prefix as usize) * 2..) })
677 }
678}
679
680#[cfg(test)]
681mod tests {
682 use super::*;
683
684 macro_rules! test_fmt {
685 ($($fmt:literal, $hex:literal => $expected:literal;)+) => {$(
686 assert_eq!(
687 format!($fmt, fixed_bytes!($hex)),
688 $expected
689 );
690 )+};
691 }
692
693 #[test]
694 fn concat_const() {
695 const A: FixedBytes<2> = fixed_bytes!("0x0123");
696 const B: FixedBytes<2> = fixed_bytes!("0x4567");
697 const EXPECTED: FixedBytes<4> = fixed_bytes!("0x01234567");
698 const ACTUAL: FixedBytes<4> = A.concat_const(B);
699
700 assert_eq!(ACTUAL, EXPECTED);
701 }
702
703 #[test]
704 fn display() {
705 test_fmt! {
706 "{}", "0123456789abcdef" => "0x0123456789abcdef";
707 "{:#}", "0123" => "0x0123";
708 "{:#}", "01234567" => "0x01234567";
709 "{:#}", "0123456789" => "0x0123…6789";
710 }
711 }
712
713 #[test]
714 fn debug() {
715 test_fmt! {
716 "{:?}", "0123456789abcdef" => "0x0123456789abcdef";
717 "{:#?}", "0123456789abcdef" => "0x0123456789abcdef";
718 }
719 }
720
721 #[test]
722 fn lower_hex() {
723 test_fmt! {
724 "{:x}", "0123456789abcdef" => "0123456789abcdef";
725 "{:#x}", "0123456789abcdef" => "0x0123456789abcdef";
726 }
727 }
728
729 #[test]
730 fn upper_hex() {
731 test_fmt! {
732 "{:X}", "0123456789abcdef" => "0123456789ABCDEF";
733 "{:#X}", "0123456789abcdef" => "0x0123456789ABCDEF";
734 }
735 }
736
737 #[test]
738 fn left_padding_from() {
739 assert_eq!(FixedBytes::<4>::left_padding_from(&[0x01, 0x23]), fixed_bytes!("0x00000123"));
740
741 assert_eq!(
742 FixedBytes::<4>::left_padding_from(&[0x01, 0x23, 0x45, 0x67]),
743 fixed_bytes!("0x01234567")
744 );
745 }
746
747 #[test]
748 #[should_panic(expected = "slice is too large. Expected <=4 bytes, got 5")]
749 fn left_padding_from_too_large() {
750 FixedBytes::<4>::left_padding_from(&[0x01, 0x23, 0x45, 0x67, 0x89]);
751 }
752
753 #[test]
754 fn right_padding_from() {
755 assert_eq!(FixedBytes::<4>::right_padding_from(&[0x01, 0x23]), fixed_bytes!("0x01230000"));
756
757 assert_eq!(
758 FixedBytes::<4>::right_padding_from(&[0x01, 0x23, 0x45, 0x67]),
759 fixed_bytes!("0x01234567")
760 );
761 }
762
763 #[test]
764 #[should_panic(expected = "slice is too large. Expected <=4 bytes, got 5")]
765 fn right_padding_from_too_large() {
766 FixedBytes::<4>::right_padding_from(&[0x01, 0x23, 0x45, 0x67, 0x89]);
767 }
768}