diff --git a/library/core/src/array/equality.rs b/library/core/src/array/equality.rs index dcd78e7a245d4..a882d18b1514c 100644 --- a/library/core/src/array/equality.rs +++ b/library/core/src/array/equality.rs @@ -5,11 +5,11 @@ where { #[inline] fn eq(&self, other: &[B; N]) -> bool { - self[..] == other[..] + SpecArrayEq::spec_eq(self, other) } #[inline] fn ne(&self, other: &[B; N]) -> bool { - self[..] != other[..] + SpecArrayEq::spec_ne(self, other) } } @@ -109,3 +109,47 @@ where #[stable(feature = "rust1", since = "1.0.0")] impl Eq for [T; N] {} + +trait SpecArrayEq: Sized { + fn spec_eq(a: &[Self; N], b: &[Other; N]) -> bool; + fn spec_ne(a: &[Self; N], b: &[Other; N]) -> bool; +} + +impl, Other, const N: usize> SpecArrayEq for T { + default fn spec_eq(a: &[Self; N], b: &[Other; N]) -> bool { + a[..] == b[..] + } + default fn spec_ne(a: &[Self; N], b: &[Other; N]) -> bool { + a[..] != b[..] + } +} + +impl + IsRawEqComparable, U, const N: usize> SpecArrayEq for T { + fn spec_eq(a: &[T; N], b: &[U; N]) -> bool { + // SAFETY: This is why `IsRawEqComparable` is an `unsafe trait`. + unsafe { + let b = &*b.as_ptr().cast::<[T; N]>(); + crate::intrinsics::raw_eq(a, b) + } + } + fn spec_ne(a: &[T; N], b: &[U; N]) -> bool { + !Self::spec_eq(a, b) + } +} + +/// `U` exists on here mostly because `min_specialization` didn't let me +/// repeat the `T` type parameter in the above specialization, so instead +/// the `T == U` constraint comes from the impls on this. +/// # Safety +/// - Neither `Self` nor `U` has any padding. +/// - `Self` and `U` have the same layout. +/// - `Self: PartialEq` is byte-wise (this means no floats, among other things) +#[rustc_specialization_trait] +unsafe trait IsRawEqComparable {} + +macro_rules! is_raw_comparable { + ($($t:ty),+) => {$( + unsafe impl IsRawEqComparable<$t> for $t {} + )+}; +} +is_raw_comparable!(bool, char, u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize);