num_primitive/bytes.rs
1use core::array::TryFromSliceError;
2
3trait Sealed {}
4
5/// Trait for arrays of bytes that may be used in numeric conversions.
6///
7/// In particular, this is used as a bound for the associated type
8/// [`PrimitiveNumber::Bytes`][crate::PrimitiveNumber::Bytes] for converting numbers to and from an
9/// array of bytes in various endian orders. It is simply `[u8; size_of::<Self>()]` for every
10/// primitive number type, but there's no way yet to write that directly in the trait.
11///
12/// This trait is not exhaustive of everything byte arrays can do, but it's enough to be useful for
13/// generically constructing bytes and dealing with them as slices.
14///
15/// This trait is sealed with a private trait to prevent downstream implementations, so we may
16/// continue to expand along with the standard library without worrying about breaking changes for
17/// implementors.
18///
19/// # Examples
20///
21/// The supertraits of `PrimitiveBytes` can be used without importing this trait directly:
22///
23/// ```
24/// use num_primitive::PrimitiveNumber;
25///
26/// // Return a value with the most significant bit set
27/// fn msb<T: PrimitiveNumber>() -> T {
28/// let mut bytes = T::Bytes::default(); // prelude `Default`
29/// bytes[0] = 0x80; // operator `IndexMut`
30/// T::from_be_bytes(bytes)
31/// }
32///
33/// assert_eq!(msb::<i64>(), i64::MIN);
34/// assert_eq!(msb::<u16>(), 1u16 << 15);
35/// assert!(msb::<f64>().total_cmp(&-0.0).is_eq());
36/// ```
37///
38/// However, this trait must be imported to use its own methods like [`repeat`][Self::repeat]:
39///
40/// ```
41/// use num_primitive::{PrimitiveBytes, PrimitiveNumber};
42///
43/// // Return a value with all bits set
44/// fn all_ones<T: PrimitiveNumber>() -> T {
45/// T::from_ne_bytes(T::Bytes::repeat(0xff))
46/// }
47///
48/// assert_eq!(all_ones::<i32>(), -1);
49/// assert_eq!(all_ones::<usize>(), usize::MAX);
50/// assert!(all_ones::<f64>().is_nan());
51/// ```
52///
53/// In cases where the size is known, you can use that as a constraint and then work with byte
54/// arrays directly, regardless of this trait.
55///
56/// ```
57/// use num_primitive::PrimitiveNumber;
58///
59/// fn rust<T: PrimitiveNumber<Bytes = [u8; 4]>>() -> T {
60/// T::from_be_bytes(*b"Rust")
61/// }
62///
63/// assert_eq!(rust::<i32>(), 0x52_75_73_74_i32);
64/// assert_eq!(rust::<u32>(), 0x52_75_73_74_u32);
65/// assert_eq!(rust::<f32>(), 2.63551e11);
66/// ```
67#[expect(private_bounds)]
68pub trait PrimitiveBytes:
69 'static
70 + Sealed
71 + core::borrow::Borrow<[u8]>
72 + core::borrow::BorrowMut<[u8]>
73 + core::cmp::Eq
74 + core::cmp::Ord
75 + core::cmp::PartialEq<[u8]>
76 + core::convert::AsRef<[u8]>
77 + core::convert::AsMut<[u8]>
78 + core::default::Default
79 + core::fmt::Debug
80 + core::hash::Hash
81 + core::marker::Copy
82 + core::marker::Send
83 + core::marker::Sync
84 + core::marker::Unpin
85 + core::ops::Index<usize, Output = u8>
86 + core::ops::IndexMut<usize>
87 + core::panic::RefUnwindSafe
88 + core::panic::UnwindSafe
89 + for<'a> core::cmp::PartialEq<&'a [u8]>
90 + for<'a> core::cmp::PartialEq<&'a mut [u8]>
91 + for<'a> core::convert::TryFrom<&'a [u8], Error = TryFromSliceError>
92 + for<'a> core::convert::TryFrom<&'a mut [u8], Error = TryFromSliceError>
93{
94 /// Creates an array of bytes where each byte is produced by calling `f`
95 /// with that element's index while walking forward through the array.
96 ///
97 /// See the [`core::array::from_fn`] function.
98 fn from_fn<F>(f: F) -> Self
99 where
100 F: FnMut(usize) -> u8;
101
102 /// Creates an array of bytes with a repeat expression, `[value; N]`.
103 fn repeat(value: u8) -> Self;
104}
105
106macro_rules! impl_bytes {
107 ($($N:literal),+) => {$(
108 impl Sealed for [u8; $N] {}
109
110 impl PrimitiveBytes for [u8; $N] {
111 #[inline]
112 fn from_fn<F>(f: F) -> Self
113 where
114 F: FnMut(usize) -> u8
115 {
116 core::array::from_fn(f)
117 }
118
119 #[inline]
120 fn repeat(value: u8) -> Self {
121 // We don't need to forward to `array::repeat` for cloning,
122 // since we can construct it directly with `u8` copies.
123 [value; $N]
124 }
125 }
126 )+}
127}
128
129impl_bytes!(1, 2, 4, 8, 16);