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);