about summary refs log tree commit diff
path: root/library/core/src/array/equality.rs
diff options
context:
space:
mode:
authorScott McMurray <scottmcm@users.noreply.github.com>2021-12-10 17:30:39 -0800
committerScott McMurray <scottmcm@users.noreply.github.com>2021-12-10 17:30:39 -0800
commit24affba02e1db9fdfe446e68a74a0ba98acbdd71 (patch)
treee76ba7acd611743b5d901c2dc63f645a326f9e8c /library/core/src/array/equality.rs
parentf0448f44bcda55fd9eb71da82495ef648eedb4e4 (diff)
downloadrust-24affba02e1db9fdfe446e68a74a0ba98acbdd71.tar.gz
rust-24affba02e1db9fdfe446e68a74a0ba98acbdd71.zip
Allow `memcmp` for more array comparisons
This way comparing `[NonZeroU8; 8]` is just as fast as comparing `[u8; 8]`.
Diffstat (limited to 'library/core/src/array/equality.rs')
-rw-r--r--library/core/src/array/equality.rs54
1 files changed, 49 insertions, 5 deletions
diff --git a/library/core/src/array/equality.rs b/library/core/src/array/equality.rs
index a882d18b151..25e056501be 100644
--- a/library/core/src/array/equality.rs
+++ b/library/core/src/array/equality.rs
@@ -1,3 +1,6 @@
+use crate::num::{NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize};
+use crate::num::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize};
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<A, B, const N: usize> PartialEq<[B; N]> for [A; N]
 where
@@ -124,7 +127,7 @@ impl<T: PartialEq<Other>, Other, const N: usize> SpecArrayEq<Other, N> for T {
     }
 }
 
-impl<T: PartialEq<U> + IsRawEqComparable<U>, U, const N: usize> SpecArrayEq<U, N> for T {
+impl<T: IsRawEqComparable<U>, U, const N: usize> SpecArrayEq<U, N> for T {
     fn spec_eq(a: &[T; N], b: &[U; N]) -> bool {
         // SAFETY: This is why `IsRawEqComparable` is an `unsafe trait`.
         unsafe {
@@ -145,11 +148,52 @@ impl<T: PartialEq<U> + IsRawEqComparable<U>, U, const N: usize> SpecArrayEq<U, N
 /// - `Self` and `U` have the same layout.
 /// - `Self: PartialEq<U>` is byte-wise (this means no floats, among other things)
 #[rustc_specialization_trait]
-unsafe trait IsRawEqComparable<U> {}
+unsafe trait IsRawEqComparable<U>: PartialEq<U> {}
 
-macro_rules! is_raw_comparable {
-    ($($t:ty),+) => {$(
+macro_rules! is_raw_eq_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);
+
+// SAFETY: All the ordinary integer types allow all bit patterns as distinct values
+is_raw_eq_comparable!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize);
+
+// SAFETY: bool and char have *niches*, but no *padding*, so this is sound
+is_raw_eq_comparable!(bool, char);
+
+// SAFETY: Similarly, the non-zero types have a niche, but no undef,
+// and they compare like their underlying numeric type.
+is_raw_eq_comparable!(
+    NonZeroU8,
+    NonZeroU16,
+    NonZeroU32,
+    NonZeroU64,
+    NonZeroU128,
+    NonZeroUsize,
+    NonZeroI8,
+    NonZeroI16,
+    NonZeroI32,
+    NonZeroI64,
+    NonZeroI128,
+    NonZeroIsize,
+);
+
+// SAFETY: The NonZero types have the "null" optimization guaranteed, and thus
+// are also safe to equality-compare bitwise inside an `Option`.
+// The way `PartialOrd` is defined for `Option` means that this wouldn't work
+// for `<` or `>` on the signed types, but since we only do `==` it's fine.
+is_raw_eq_comparable!(
+    Option<NonZeroU8>,
+    Option<NonZeroU16>,
+    Option<NonZeroU32>,
+    Option<NonZeroU64>,
+    Option<NonZeroU128>,
+    Option<NonZeroUsize>,
+    Option<NonZeroI8>,
+    Option<NonZeroI16>,
+    Option<NonZeroI32>,
+    Option<NonZeroI64>,
+    Option<NonZeroI128>,
+    Option<NonZeroIsize>,
+);