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