Skip to content

Commit cb92ff5

Browse files
committedMar 10, 2025
Make slice PartialEq more generic
(cherry picked from commit 3c1aa9577a543d9fd075307372345801a39d5fd3)
1 parent 34c5807 commit cb92ff5

File tree

3 files changed

+89
-40
lines changed

3 files changed

+89
-40
lines changed
 

‎src/map/slice.rs

+38-24
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use super::{Bucket, IntoIter, IntoKeys, IntoValues, Iter, IterMut, Keys, Values, ValuesMut};
2-
use crate::util::try_simplify_range;
2+
use crate::util::{slice_eq, try_simplify_range};
33

44
use alloc::boxed::Box;
55
use alloc::collections::VecDeque;
@@ -329,41 +329,55 @@ impl<K: fmt::Debug, V: fmt::Debug> fmt::Debug for Slice<K, V> {
329329
}
330330
}
331331

332-
impl<K: PartialEq, V: PartialEq> PartialEq for Slice<K, V> {
333-
fn eq(&self, other: &Self) -> bool {
334-
self.len() == other.len() && self.iter().eq(other)
332+
impl<K, V, K2, V2> PartialEq<Slice<K2, V2>> for Slice<K, V>
333+
where
334+
K: PartialEq<K2>,
335+
V: PartialEq<V2>,
336+
{
337+
fn eq(&self, other: &Slice<K2, V2>) -> bool {
338+
slice_eq(&self.entries, &other.entries, |b1, b2| {
339+
b1.key == b2.key && b1.value == b2.value
340+
})
335341
}
336342
}
337343

338-
impl<K: PartialEq, V: PartialEq> PartialEq<[(K, V)]> for Slice<K, V> {
339-
fn eq(&self, other: &[(K, V)]) -> bool {
340-
self.len() == other.len() &&
341-
// mapping from `&(K, V)` to `(&K, &V)`
342-
self.iter().eq(other.iter().map(|(k, v)| (k, v)))
344+
impl<K, V, K2, V2> PartialEq<[(K2, V2)]> for Slice<K, V>
345+
where
346+
K: PartialEq<K2>,
347+
V: PartialEq<V2>,
348+
{
349+
fn eq(&self, other: &[(K2, V2)]) -> bool {
350+
slice_eq(&self.entries, other, |b, t| b.key == t.0 && b.value == t.1)
343351
}
344352
}
345353

346-
impl<K: PartialEq, V: PartialEq> PartialEq<Slice<K, V>> for [(K, V)] {
347-
fn eq(&self, other: &Slice<K, V>) -> bool {
348-
self.len() == other.len() &&
349-
// mapping from `&(K, V)` to `(&K, &V)`
350-
self.iter().map(|(k, v)| (k, v)).eq(other)
354+
impl<K, V, K2, V2> PartialEq<Slice<K2, V2>> for [(K, V)]
355+
where
356+
K: PartialEq<K2>,
357+
V: PartialEq<V2>,
358+
{
359+
fn eq(&self, other: &Slice<K2, V2>) -> bool {
360+
slice_eq(self, &other.entries, |t, b| t.0 == b.key && t.1 == b.value)
351361
}
352362
}
353363

354-
impl<K: PartialEq, V: PartialEq, const N: usize> PartialEq<[(K, V); N]> for Slice<K, V> {
355-
fn eq(&self, other: &[(K, V); N]) -> bool {
356-
self.len() == N &&
357-
// mapping from `&(K, V)` to `(&K, &V)`
358-
self.iter().eq(other.iter().map(|(k, v)| (k, v)))
364+
impl<K, V, K2, V2, const N: usize> PartialEq<[(K2, V2); N]> for Slice<K, V>
365+
where
366+
K: PartialEq<K2>,
367+
V: PartialEq<V2>,
368+
{
369+
fn eq(&self, other: &[(K2, V2); N]) -> bool {
370+
<Self as PartialEq<[_]>>::eq(self, other)
359371
}
360372
}
361373

362-
impl<K: PartialEq, V: PartialEq, const N: usize> PartialEq<Slice<K, V>> for [(K, V); N] {
363-
fn eq(&self, other: &Slice<K, V>) -> bool {
364-
N == other.len() &&
365-
// mapping from `&(K, V)` to `(&K, &V)`
366-
self.iter().map(|(k, v)| (k, v)).eq(other)
374+
impl<K, V, const N: usize, K2, V2> PartialEq<Slice<K2, V2>> for [(K, V); N]
375+
where
376+
K: PartialEq<K2>,
377+
V: PartialEq<V2>,
378+
{
379+
fn eq(&self, other: &Slice<K2, V2>) -> bool {
380+
<[_] as PartialEq<_>>::eq(self, other)
367381
}
368382
}
369383

‎src/set/slice.rs

+31-16
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use super::{Bucket, IntoIter, Iter};
2-
use crate::util::try_simplify_range;
2+
use crate::util::{slice_eq, try_simplify_range};
33

44
use alloc::boxed::Box;
55
use alloc::collections::VecDeque;
@@ -219,33 +219,48 @@ impl<T: fmt::Debug> fmt::Debug for Slice<T> {
219219
}
220220
}
221221

222-
impl<T: PartialEq> PartialEq for Slice<T> {
223-
fn eq(&self, other: &Self) -> bool {
224-
self.len() == other.len() && self.iter().eq(other)
222+
impl<T, U> PartialEq<Slice<U>> for Slice<T>
223+
where
224+
T: PartialEq<U>,
225+
{
226+
fn eq(&self, other: &Slice<U>) -> bool {
227+
slice_eq(&self.entries, &other.entries, |b1, b2| b1.key == b2.key)
225228
}
226229
}
227230

228-
impl<T: PartialEq> PartialEq<[T]> for Slice<T> {
229-
fn eq(&self, other: &[T]) -> bool {
230-
self.len() == other.len() && self.iter().eq(other)
231+
impl<T, U> PartialEq<[U]> for Slice<T>
232+
where
233+
T: PartialEq<U>,
234+
{
235+
fn eq(&self, other: &[U]) -> bool {
236+
slice_eq(&self.entries, other, |b, o| b.key == *o)
231237
}
232238
}
233239

234-
impl<T: PartialEq> PartialEq<Slice<T>> for [T] {
235-
fn eq(&self, other: &Slice<T>) -> bool {
236-
self.len() == other.len() && self.iter().eq(other)
240+
impl<T, U> PartialEq<Slice<U>> for [T]
241+
where
242+
T: PartialEq<U>,
243+
{
244+
fn eq(&self, other: &Slice<U>) -> bool {
245+
slice_eq(self, &other.entries, |o, b| *o == b.key)
237246
}
238247
}
239248

240-
impl<T: PartialEq, const N: usize> PartialEq<[T; N]> for Slice<T> {
241-
fn eq(&self, other: &[T; N]) -> bool {
242-
self.len() == N && self.iter().eq(other)
249+
impl<T, U, const N: usize> PartialEq<[U; N]> for Slice<T>
250+
where
251+
T: PartialEq<U>,
252+
{
253+
fn eq(&self, other: &[U; N]) -> bool {
254+
<Self as PartialEq<[U]>>::eq(self, other)
243255
}
244256
}
245257

246-
impl<T: PartialEq, const N: usize> PartialEq<Slice<T>> for [T; N] {
247-
fn eq(&self, other: &Slice<T>) -> bool {
248-
N == other.len() && self.iter().eq(other)
258+
impl<T, const N: usize, U> PartialEq<Slice<U>> for [T; N]
259+
where
260+
T: PartialEq<U>,
261+
{
262+
fn eq(&self, other: &Slice<U>) -> bool {
263+
<[T] as PartialEq<Slice<U>>>::eq(self, other)
249264
}
250265
}
251266

‎src/util.rs

+20
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,23 @@ where
5656
}
5757
Some(start..end)
5858
}
59+
60+
// Generic slice equality -- copied from the standard library but adding a custom comparator,
61+
// allowing for our `Bucket` wrapper on either or both sides.
62+
pub(crate) fn slice_eq<T, U>(left: &[T], right: &[U], eq: impl Fn(&T, &U) -> bool) -> bool {
63+
if left.len() != right.len() {
64+
return false;
65+
}
66+
67+
// Implemented as explicit indexing rather
68+
// than zipped iterators for performance reasons.
69+
// See PR https://github.com/rust-lang/rust/pull/116846
70+
for i in 0..left.len() {
71+
// bound checks are optimized away
72+
if !eq(&left[i], &right[i]) {
73+
return false;
74+
}
75+
}
76+
77+
true
78+
}

0 commit comments

Comments
 (0)
Please sign in to comment.