Skip to content

Commit 3c1aa95

Browse files
committed
Make slice PartialEq more generic
1 parent 6a83883 commit 3c1aa95

File tree

3 files changed

+89
-40
lines changed

3 files changed

+89
-40
lines changed

src/map/slice.rs

Lines changed: 38 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use super::{
22
Bucket, Entries, IndexMap, IntoIter, IntoKeys, IntoValues, Iter, IterMut, Keys, Values,
33
ValuesMut,
44
};
5-
use crate::util::try_simplify_range;
5+
use crate::util::{slice_eq, try_simplify_range};
66

77
use alloc::boxed::Box;
88
use alloc::vec::Vec;
@@ -335,41 +335,55 @@ impl<K: fmt::Debug, V: fmt::Debug> fmt::Debug for Slice<K, V> {
335335
}
336336
}
337337

338-
impl<K: PartialEq, V: PartialEq> PartialEq for Slice<K, V> {
339-
fn eq(&self, other: &Self) -> bool {
340-
self.len() == other.len() && self.iter().eq(other)
338+
impl<K, V, K2, V2> PartialEq<Slice<K2, V2>> for Slice<K, V>
339+
where
340+
K: PartialEq<K2>,
341+
V: PartialEq<V2>,
342+
{
343+
fn eq(&self, other: &Slice<K2, V2>) -> bool {
344+
slice_eq(&self.entries, &other.entries, |b1, b2| {
345+
b1.key == b2.key && b1.value == b2.value
346+
})
341347
}
342348
}
343349

344-
impl<K: PartialEq, V: PartialEq> PartialEq<[(K, V)]> for Slice<K, V> {
345-
fn eq(&self, other: &[(K, V)]) -> bool {
346-
self.len() == other.len() &&
347-
// mapping from `&(K, V)` to `(&K, &V)`
348-
self.iter().eq(other.iter().map(|(k, v)| (k, v)))
350+
impl<K, V, K2, V2> PartialEq<[(K2, V2)]> for Slice<K, V>
351+
where
352+
K: PartialEq<K2>,
353+
V: PartialEq<V2>,
354+
{
355+
fn eq(&self, other: &[(K2, V2)]) -> bool {
356+
slice_eq(&self.entries, other, |b, t| b.key == t.0 && b.value == t.1)
349357
}
350358
}
351359

352-
impl<K: PartialEq, V: PartialEq> PartialEq<Slice<K, V>> for [(K, V)] {
353-
fn eq(&self, other: &Slice<K, V>) -> bool {
354-
self.len() == other.len() &&
355-
// mapping from `&(K, V)` to `(&K, &V)`
356-
self.iter().map(|(k, v)| (k, v)).eq(other)
360+
impl<K, V, K2, V2> PartialEq<Slice<K2, V2>> for [(K, V)]
361+
where
362+
K: PartialEq<K2>,
363+
V: PartialEq<V2>,
364+
{
365+
fn eq(&self, other: &Slice<K2, V2>) -> bool {
366+
slice_eq(self, &other.entries, |t, b| t.0 == b.key && t.1 == b.value)
357367
}
358368
}
359369

360-
impl<K: PartialEq, V: PartialEq, const N: usize> PartialEq<[(K, V); N]> for Slice<K, V> {
361-
fn eq(&self, other: &[(K, V); N]) -> bool {
362-
self.len() == N &&
363-
// mapping from `&(K, V)` to `(&K, &V)`
364-
self.iter().eq(other.iter().map(|(k, v)| (k, v)))
370+
impl<K, V, K2, V2, const N: usize> PartialEq<[(K2, V2); N]> for Slice<K, V>
371+
where
372+
K: PartialEq<K2>,
373+
V: PartialEq<V2>,
374+
{
375+
fn eq(&self, other: &[(K2, V2); N]) -> bool {
376+
<Self as PartialEq<[_]>>::eq(self, other)
365377
}
366378
}
367379

368-
impl<K: PartialEq, V: PartialEq, const N: usize> PartialEq<Slice<K, V>> for [(K, V); N] {
369-
fn eq(&self, other: &Slice<K, V>) -> bool {
370-
N == other.len() &&
371-
// mapping from `&(K, V)` to `(&K, &V)`
372-
self.iter().map(|(k, v)| (k, v)).eq(other)
380+
impl<K, V, const N: usize, K2, V2> PartialEq<Slice<K2, V2>> for [(K, V); N]
381+
where
382+
K: PartialEq<K2>,
383+
V: PartialEq<V2>,
384+
{
385+
fn eq(&self, other: &Slice<K2, V2>) -> bool {
386+
<[_] as PartialEq<_>>::eq(self, other)
373387
}
374388
}
375389

src/set/slice.rs

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use super::{Bucket, Entries, IndexSet, 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::vec::Vec;
@@ -222,33 +222,48 @@ impl<T: fmt::Debug> fmt::Debug for Slice<T> {
222222
}
223223
}
224224

225-
impl<T: PartialEq> PartialEq for Slice<T> {
226-
fn eq(&self, other: &Self) -> bool {
227-
self.len() == other.len() && self.iter().eq(other)
225+
impl<T, U> PartialEq<Slice<U>> for Slice<T>
226+
where
227+
T: PartialEq<U>,
228+
{
229+
fn eq(&self, other: &Slice<U>) -> bool {
230+
slice_eq(&self.entries, &other.entries, |b1, b2| b1.key == b2.key)
228231
}
229232
}
230233

231-
impl<T: PartialEq> PartialEq<[T]> for Slice<T> {
232-
fn eq(&self, other: &[T]) -> bool {
233-
self.len() == other.len() && self.iter().eq(other)
234+
impl<T, U> PartialEq<[U]> for Slice<T>
235+
where
236+
T: PartialEq<U>,
237+
{
238+
fn eq(&self, other: &[U]) -> bool {
239+
slice_eq(&self.entries, other, |b, o| b.key == *o)
234240
}
235241
}
236242

237-
impl<T: PartialEq> PartialEq<Slice<T>> for [T] {
238-
fn eq(&self, other: &Slice<T>) -> bool {
239-
self.len() == other.len() && self.iter().eq(other)
243+
impl<T, U> PartialEq<Slice<U>> for [T]
244+
where
245+
T: PartialEq<U>,
246+
{
247+
fn eq(&self, other: &Slice<U>) -> bool {
248+
slice_eq(self, &other.entries, |o, b| *o == b.key)
240249
}
241250
}
242251

243-
impl<T: PartialEq, const N: usize> PartialEq<[T; N]> for Slice<T> {
244-
fn eq(&self, other: &[T; N]) -> bool {
245-
self.len() == N && self.iter().eq(other)
252+
impl<T, U, const N: usize> PartialEq<[U; N]> for Slice<T>
253+
where
254+
T: PartialEq<U>,
255+
{
256+
fn eq(&self, other: &[U; N]) -> bool {
257+
<Self as PartialEq<[U]>>::eq(self, other)
246258
}
247259
}
248260

249-
impl<T: PartialEq, const N: usize> PartialEq<Slice<T>> for [T; N] {
250-
fn eq(&self, other: &Slice<T>) -> bool {
251-
N == other.len() && self.iter().eq(other)
261+
impl<T, const N: usize, U> PartialEq<Slice<U>> for [T; N]
262+
where
263+
T: PartialEq<U>,
264+
{
265+
fn eq(&self, other: &Slice<U>) -> bool {
266+
<[T] as PartialEq<Slice<U>>>::eq(self, other)
252267
}
253268
}
254269

src/util.rs

Lines changed: 20 additions & 0 deletions
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)