1use crate::num::{NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize};
2use crate::num::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize};
3
4/// Types where `==` & `!=` are equivalent to comparing their underlying bytes.
5///
6/// Importantly, this means no floating-point types, as those have different
7/// byte representations (like `-0` and `+0`) which compare as the same.
8/// Since byte arrays are `Eq`, that implies that these types are probably also
9/// `Eq`, but that's not technically required to use this trait.
10///
11/// `Rhs` is *de facto* always `Self`, but the separate parameter is important
12/// to avoid the `specializing impl repeats parameter` error when consuming this.
13///
14/// # Safety
15///
16/// - `Self` and `Rhs` have no padding.
17/// - `Self` and `Rhs` have the same layout (size and alignment).
18/// - Neither `Self` nor `Rhs` have provenance, so integer comparisons are correct.
19/// - `<Self as PartialEq<Rhs>>::{eq,ne}` are equivalent to comparing the bytes.
20#[rustc_specialization_trait]
21pub(crate) unsafe trait BytewiseEq<Rhs = Self>: PartialEq<Rhs> + Sized {}
22
23macro_rules! is_bytewise_comparable {
24 ($($t:ty),+ $(,)?) => {$(
25 unsafe impl BytewiseEq for $t {}
26 )+};
27}
28
29// SAFETY: All the ordinary integer types have no padding, and are not pointers.
30is_bytewise_comparable!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize);
31
32// SAFETY: These have *niches*, but no *padding* and no *provenance*,
33// so we can compare them directly.
34is_bytewise_comparable!(bool, char, super::Ordering);
35
36// SAFETY: Similarly, the non-zero types have a niche, but no undef and no pointers,
37// and they compare like their underlying numeric type.
38is_bytewise_comparable!(
39 NonZeroU8,
40 NonZeroU16,
41 NonZeroU32,
42 NonZeroU64,
43 NonZeroU128,
44 NonZeroUsize,
45 NonZeroI8,
46 NonZeroI16,
47 NonZeroI32,
48 NonZeroI64,
49 NonZeroI128,
50 NonZeroIsize,
51);
52
53// SAFETY: The NonZero types have the "null" optimization guaranteed, and thus
54// are also safe to equality-compare bitwise inside an `Option`.
55// The way `PartialOrd` is defined for `Option` means that this wouldn't work
56// for `<` or `>` on the signed types, but since we only do `==` it's fine.
57is_bytewise_comparable!(
58 Option<NonZeroU8>,
59 Option<NonZeroU16>,
60 Option<NonZeroU32>,
61 Option<NonZeroU64>,
62 Option<NonZeroU128>,
63 Option<NonZeroUsize>,
64 Option<NonZeroI8>,
65 Option<NonZeroI16>,
66 Option<NonZeroI32>,
67 Option<NonZeroI64>,
68 Option<NonZeroI128>,
69 Option<NonZeroIsize>,
70);
71
72macro_rules! is_bytewise_comparable_array_length {
73 ($($n:literal),+ $(,)?) => {$(
74 // SAFETY: Arrays have no padding between elements, so if the elements are
75 // `BytewiseEq`, then the whole array can be too.
76 unsafe impl<T: BytewiseEq<U>, U> BytewiseEq<[U; $n]> for [T; $n] {}
77 )+};
78}
79
80// Frustratingly, this can't be made const-generic as it gets
81// error: specializing impl repeats parameter `N`
82// so just do it for a couple of plausibly-common ones.
83is_bytewise_comparable_array_length!(0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64);
84