diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 8b6d86a288866..dafb0316ff281 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -1,5 +1,4 @@ -use core::borrow::Borrow; -use core::cmp::Ordering; +use core::cmp::{Comparable, Ordering}; use core::error::Error; use core::fmt::{self, Debug}; use core::hash::{Hash, Hasher}; @@ -332,8 +331,7 @@ impl BTreeMap { pub(super) fn get_or_insert_with(&mut self, q: &Q, f: F) -> &K where - K: Borrow + Ord, - Q: Ord, + K: Comparable + Ord, F: FnOnce(&Q) -> K, { let (map, dormant_map) = DormantMutRef::new(self); @@ -343,7 +341,7 @@ impl BTreeMap { Found(handle) => handle.into_kv_mut().0, GoDown(handle) => { let key = f(q); - assert!(*key.borrow() == *q, "new value is not equal"); + assert!(key.equivalent(q), "new value is not equal"); VacantEntry { key, handle: Some(handle), @@ -710,8 +708,7 @@ impl BTreeMap { #[stable(feature = "rust1", since = "1.0.0")] pub fn get(&self, key: &Q) -> Option<&V> where - K: Borrow + Ord, - Q: Ord, + K: Comparable + Ord, { let root_node = self.root.as_ref()?.reborrow(); match root_node.search_tree(key) { @@ -776,8 +773,7 @@ impl BTreeMap { #[stable(feature = "map_get_key_value", since = "1.40.0")] pub fn get_key_value(&self, k: &Q) -> Option<(&K, &V)> where - K: Borrow + Ord, - Q: Ord, + K: Comparable + Ord, { let root_node = self.root.as_ref()?.reborrow(); match root_node.search_tree(k) { @@ -972,8 +968,7 @@ impl BTreeMap { #[cfg_attr(not(test), rustc_diagnostic_item = "btreemap_contains_key")] pub fn contains_key(&self, key: &Q) -> bool where - K: Borrow + Ord, - Q: Ord, + K: Comparable + Ord, { self.get(key).is_some() } @@ -999,8 +994,7 @@ impl BTreeMap { #[stable(feature = "rust1", since = "1.0.0")] pub fn get_mut(&mut self, key: &Q) -> Option<&mut V> where - K: Borrow + Ord, - Q: Ord, + K: Comparable + Ord, { let root_node = self.root.as_mut()?.borrow_mut(); match root_node.search_tree(key) { @@ -1101,8 +1095,7 @@ impl BTreeMap { #[rustc_confusables("delete", "take")] pub fn remove(&mut self, key: &Q) -> Option where - K: Borrow + Ord, - Q: Ord, + K: Comparable + Ord, { self.remove_entry(key).map(|(_, v)| v) } @@ -1126,8 +1119,7 @@ impl BTreeMap { #[stable(feature = "btreemap_remove_entry", since = "1.45.0")] pub fn remove_entry(&mut self, key: &Q) -> Option<(K, V)> where - K: Borrow + Ord, - Q: Ord, + K: Comparable + Ord, { let (map, dormant_map) = DormantMutRef::new(self); let root_node = map.root.as_mut()?.borrow_mut(); @@ -1260,7 +1252,7 @@ impl BTreeMap { pub fn range(&self, range: R) -> Range<'_, K, V> where T: Ord, - K: Borrow + Ord, + K: Comparable, R: RangeBounds, { if let Some(root) = &self.root { @@ -1300,7 +1292,7 @@ impl BTreeMap { pub fn range_mut(&mut self, range: R) -> RangeMut<'_, K, V> where T: Ord, - K: Borrow + Ord, + K: Comparable, R: RangeBounds, { if let Some(root) = &mut self.root { @@ -1388,9 +1380,9 @@ impl BTreeMap { /// assert_eq!(b[&41], "e"); /// ``` #[stable(feature = "btree_split_off", since = "1.11.0")] - pub fn split_off(&mut self, key: &Q) -> Self + pub fn split_off(&mut self, key: &Q) -> Self where - K: Borrow + Ord, + K: Comparable + Ord, A: Clone, { if self.is_empty() { @@ -2440,8 +2432,7 @@ impl Debug for BTreeMap { #[stable(feature = "rust1", since = "1.0.0")] impl Index<&Q> for BTreeMap where - K: Borrow + Ord, - Q: Ord, + K: Comparable + Ord, { type Output = V; @@ -2694,8 +2685,7 @@ impl BTreeMap { #[unstable(feature = "btree_cursors", issue = "107540")] pub fn lower_bound(&self, bound: Bound<&Q>) -> Cursor<'_, K, V> where - K: Borrow + Ord, - Q: Ord, + K: Comparable + Ord, { let root_node = match self.root.as_ref() { None => return Cursor { current: None, root: None }, @@ -2747,8 +2737,7 @@ impl BTreeMap { #[unstable(feature = "btree_cursors", issue = "107540")] pub fn lower_bound_mut(&mut self, bound: Bound<&Q>) -> CursorMut<'_, K, V, A> where - K: Borrow + Ord, - Q: Ord, + K: Comparable + Ord, { let (root, dormant_root) = DormantMutRef::new(&mut self.root); let root_node = match root.as_mut() { @@ -2817,8 +2806,7 @@ impl BTreeMap { #[unstable(feature = "btree_cursors", issue = "107540")] pub fn upper_bound(&self, bound: Bound<&Q>) -> Cursor<'_, K, V> where - K: Borrow + Ord, - Q: Ord, + K: Comparable + Ord, { let root_node = match self.root.as_ref() { None => return Cursor { current: None, root: None }, @@ -2870,8 +2858,7 @@ impl BTreeMap { #[unstable(feature = "btree_cursors", issue = "107540")] pub fn upper_bound_mut(&mut self, bound: Bound<&Q>) -> CursorMut<'_, K, V, A> where - K: Borrow + Ord, - Q: Ord, + K: Comparable + Ord, { let (root, dormant_root) = DormantMutRef::new(&mut self.root); let root_node = match root.as_mut() { diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs index 79879d31d3dfd..cca9851d3e351 100644 --- a/library/alloc/src/collections/btree/map/tests.rs +++ b/library/alloc/src/collections/btree/map/tests.rs @@ -1,4 +1,5 @@ use core::assert_matches::assert_matches; +use std::borrow::Borrow; use std::iter; use std::ops::Bound::{Excluded, Included, Unbounded}; use std::panic::{AssertUnwindSafe, catch_unwind}; diff --git a/library/alloc/src/collections/btree/navigate.rs b/library/alloc/src/collections/btree/navigate.rs index b2a7de74875d9..c8241287894e6 100644 --- a/library/alloc/src/collections/btree/navigate.rs +++ b/library/alloc/src/collections/btree/navigate.rs @@ -1,4 +1,4 @@ -use core::borrow::Borrow; +use core::cmp::Comparable; use core::ops::RangeBounds; use core::{hint, ptr}; @@ -267,7 +267,7 @@ impl NodeRef LeafRange where Q: Ord, - K: Borrow, + K: Comparable, R: RangeBounds, { match self.search_tree_for_bifurcation(&range) { @@ -316,7 +316,7 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> pub(super) fn range_search(self, range: R) -> LeafRange, K, V> where Q: ?Sized + Ord, - K: Borrow, + K: Comparable, R: RangeBounds, { // SAFETY: our borrow type is immutable. @@ -342,7 +342,7 @@ impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> pub(super) fn range_search(self, range: R) -> LeafRange, K, V> where Q: ?Sized + Ord, - K: Borrow, + K: Comparable, R: RangeBounds, { unsafe { self.find_leaf_edges_spanning_range(range) } @@ -746,8 +746,7 @@ impl NodeRef, ) -> Handle, marker::Edge> where - Q: Ord, - K: Borrow, + K: Comparable, { let mut node = self; loop { @@ -769,8 +768,7 @@ impl NodeRef, ) -> Handle, marker::Edge> where - Q: Ord, - K: Borrow, + K: Comparable, { let mut node = self; loop { diff --git a/library/alloc/src/collections/btree/search.rs b/library/alloc/src/collections/btree/search.rs index 96e5bf108024b..4f9953241bb0e 100644 --- a/library/alloc/src/collections/btree/search.rs +++ b/library/alloc/src/collections/btree/search.rs @@ -1,5 +1,4 @@ -use core::borrow::Borrow; -use core::cmp::Ordering; +use core::cmp::{Comparable, Ordering}; use core::ops::{Bound, RangeBounds}; use SearchBound::*; @@ -51,8 +50,7 @@ impl NodeRef SearchResult where - Q: Ord, - K: Borrow, + K: Comparable, { loop { self = match self.search_node(key) { @@ -95,7 +93,7 @@ impl NodeRef where Q: Ord, - K: Borrow, + K: Comparable, R: RangeBounds, { // Determine if map or set is being searched @@ -161,8 +159,8 @@ impl NodeRef, ) -> (Handle, SearchBound<&'r Q>) where - Q: ?Sized + Ord, - K: Borrow, + Q: ?Sized, + K: Comparable, { let (edge_idx, bound) = self.find_lower_bound_index(bound); let edge = unsafe { Handle::new_edge(self, edge_idx) }; @@ -175,8 +173,8 @@ impl NodeRef, ) -> (Handle, SearchBound<&'r Q>) where - Q: ?Sized + Ord, - K: Borrow, + Q: ?Sized, + K: Comparable, { let (edge_idx, bound) = unsafe { self.find_upper_bound_index(bound, 0) }; let edge = unsafe { Handle::new_edge(self, edge_idx) }; @@ -197,8 +195,7 @@ impl NodeRef { key: &Q, ) -> SearchResult where - Q: Ord, - K: Borrow, + K: Comparable, { match unsafe { self.find_key_index(key, 0) } { IndexResult::KV(idx) => Found(unsafe { Handle::new_kv(self, idx) }), @@ -216,17 +213,16 @@ impl NodeRef { /// `start_index` must be a valid edge index for the node. unsafe fn find_key_index(&self, key: &Q, start_index: usize) -> IndexResult where - Q: Ord, - K: Borrow, + K: Comparable, { let node = self.reborrow(); let keys = node.keys(); debug_assert!(start_index <= keys.len()); for (offset, k) in unsafe { keys.get_unchecked(start_index..) }.iter().enumerate() { - match key.cmp(k.borrow()) { - Ordering::Greater => {} + match k.compare(key) { + Ordering::Less => {} Ordering::Equal => return IndexResult::KV(start_index + offset), - Ordering::Less => return IndexResult::Edge(start_index + offset), + Ordering::Greater => return IndexResult::Edge(start_index + offset), } } IndexResult::Edge(keys.len()) @@ -242,8 +238,8 @@ impl NodeRef { bound: SearchBound<&'r Q>, ) -> (usize, SearchBound<&'r Q>) where - Q: ?Sized + Ord, - K: Borrow, + Q: ?Sized, + K: Comparable, { match bound { Included(key) => match unsafe { self.find_key_index(key, 0) } { @@ -270,8 +266,8 @@ impl NodeRef { start_index: usize, ) -> (usize, SearchBound<&'r Q>) where - Q: ?Sized + Ord, - K: Borrow, + Q: ?Sized, + K: Comparable, { match bound { Included(key) => match unsafe { self.find_key_index(key, start_index) } { diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index d50ce02bda743..542c0ed8a1109 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -1,6 +1,5 @@ -use core::borrow::Borrow; use core::cmp::Ordering::{self, Equal, Greater, Less}; -use core::cmp::{max, min}; +use core::cmp::{Comparable, max, min}; use core::fmt::{self, Debug}; use core::hash::{Hash, Hasher}; use core::iter::{FusedIterator, Peekable}; @@ -396,7 +395,7 @@ impl BTreeSet { pub fn range(&self, range: R) -> Range<'_, T> where K: Ord, - T: Borrow + Ord, + T: Comparable + Ord, R: RangeBounds, { Range { iter: self.map.range(range) } @@ -611,8 +610,7 @@ impl BTreeSet { #[stable(feature = "rust1", since = "1.0.0")] pub fn contains(&self, value: &Q) -> bool where - T: Borrow + Ord, - Q: Ord, + T: Comparable + Ord, { self.map.contains_key(value) } @@ -636,8 +634,7 @@ impl BTreeSet { #[stable(feature = "set_recovery", since = "1.9.0")] pub fn get(&self, value: &Q) -> Option<&T> where - T: Borrow + Ord, - Q: Ord, + T: Comparable + Ord, { self.map.get_key_value(value).map(|(k, _)| k) } @@ -982,8 +979,7 @@ impl BTreeSet { #[unstable(feature = "btree_set_entry", issue = "133549")] pub fn get_or_insert_with(&mut self, value: &Q, f: F) -> &T where - T: Borrow + Ord, - Q: Ord, + T: Comparable + Ord, F: FnOnce(&Q) -> T, { self.map.get_or_insert_with(value, f) @@ -1057,8 +1053,7 @@ impl BTreeSet { #[stable(feature = "rust1", since = "1.0.0")] pub fn remove(&mut self, value: &Q) -> bool where - T: Borrow + Ord, - Q: Ord, + T: Comparable + Ord, { self.map.remove(value).is_some() } @@ -1082,8 +1077,7 @@ impl BTreeSet { #[stable(feature = "set_recovery", since = "1.9.0")] pub fn take(&mut self, value: &Q) -> Option where - T: Borrow + Ord, - Q: Ord, + T: Comparable + Ord, { self.map.remove_entry(value).map(|(k, _)| k) } @@ -1179,9 +1173,9 @@ impl BTreeSet { /// assert!(b.contains(&41)); /// ``` #[stable(feature = "btree_split_off", since = "1.11.0")] - pub fn split_off(&mut self, value: &Q) -> Self + pub fn split_off(&mut self, value: &Q) -> Self where - T: Borrow + Ord, + T: Comparable + Ord, A: Clone, { BTreeSet { map: self.map.split_off(value) } @@ -1335,8 +1329,7 @@ impl BTreeSet { #[unstable(feature = "btree_cursors", issue = "107540")] pub fn lower_bound(&self, bound: Bound<&Q>) -> Cursor<'_, T> where - T: Borrow + Ord, - Q: Ord, + T: Comparable + Ord, { Cursor { inner: self.map.lower_bound(bound) } } @@ -1378,8 +1371,7 @@ impl BTreeSet { #[unstable(feature = "btree_cursors", issue = "107540")] pub fn lower_bound_mut(&mut self, bound: Bound<&Q>) -> CursorMut<'_, T, A> where - T: Borrow + Ord, - Q: Ord, + T: Comparable + Ord, { CursorMut { inner: self.map.lower_bound_mut(bound) } } @@ -1421,8 +1413,7 @@ impl BTreeSet { #[unstable(feature = "btree_cursors", issue = "107540")] pub fn upper_bound(&self, bound: Bound<&Q>) -> Cursor<'_, T> where - T: Borrow + Ord, - Q: Ord, + T: Comparable + Ord, { Cursor { inner: self.map.upper_bound(bound) } } @@ -1464,8 +1455,7 @@ impl BTreeSet { #[unstable(feature = "btree_cursors", issue = "107540")] pub fn upper_bound_mut(&mut self, bound: Bound<&Q>) -> CursorMut<'_, T, A> where - T: Borrow + Ord, - Q: Ord, + T: Comparable + Ord, { CursorMut { inner: self.map.upper_bound_mut(bound) } } diff --git a/library/alloc/src/collections/btree/split.rs b/library/alloc/src/collections/btree/split.rs index 87a79e6cf3f93..fda14113d072c 100644 --- a/library/alloc/src/collections/btree/split.rs +++ b/library/alloc/src/collections/btree/split.rs @@ -1,5 +1,5 @@ use core::alloc::Allocator; -use core::borrow::Borrow; +use core::cmp::Comparable; use super::node::ForceResult::*; use super::node::Root; @@ -31,13 +31,9 @@ impl Root { /// and if the ordering of `Q` corresponds to that of `K`. /// If `self` respects all `BTreeMap` tree invariants, then both /// `self` and the returned tree will respect those invariants. - pub(super) fn split_off( - &mut self, - key: &Q, - alloc: A, - ) -> Self + pub(super) fn split_off(&mut self, key: &Q, alloc: A) -> Self where - K: Borrow, + K: Comparable, { let left_root = self; let mut right_root = Root::new_pillar(left_root.height(), alloc.clone()); diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 711092ae8eb25..63f552e5728ee 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -107,6 +107,7 @@ #![feature(char_max_len)] #![feature(clone_to_uninit)] #![feature(coerce_unsized)] +#![feature(comparable_trait)] #![feature(const_default)] #![feature(const_eval_select)] #![feature(const_heap)] diff --git a/library/alloctests/lib.rs b/library/alloctests/lib.rs index 97de7d6a701ca..b2a23592320c7 100644 --- a/library/alloctests/lib.rs +++ b/library/alloctests/lib.rs @@ -20,6 +20,7 @@ #![feature(assert_matches)] #![feature(char_internals)] #![feature(char_max_len)] +#![feature(comparable_trait)] #![feature(core_intrinsics)] #![feature(exact_size_is_empty)] #![feature(extend_one)] diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index ab018fa267502..fda8abb43686f 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -1510,6 +1510,54 @@ pub macro PartialOrd($item:item) { /* compiler built-in */ } +/// Key equivalence trait. +/// +/// This trait allows hash table lookup to be customized. +/// +/// # Contract +/// +/// The implementor **must** hash like `Q`, if it is hashable. +#[unstable(feature = "comparable_trait", issue = "145986")] +pub trait Equivalent { + /// Compare self to `key` and return `true` if they are equal. + #[unstable(feature = "comparable_trait", issue = "145986")] + fn equivalent(&self, key: &Q) -> bool; +} + +#[unstable(feature = "comparable_trait", issue = "145986")] +impl Equivalent for K +where + K: crate::borrow::Borrow, + Q: Eq, +{ + #[inline] + fn equivalent(&self, key: &Q) -> bool { + PartialEq::eq(self.borrow(), key) + } +} + +/// Key ordering trait. +/// +/// This trait allows ordered map lookup to be customized. +#[unstable(feature = "comparable_trait", issue = "145986")] +pub trait Comparable: Equivalent { + /// Compare self to `key` and return their ordering. + #[unstable(feature = "comparable_trait", issue = "145986")] + fn compare(&self, key: &Q) -> Ordering; +} + +#[unstable(feature = "comparable_trait", issue = "145986")] +impl Comparable for K +where + K: crate::borrow::Borrow, + Q: Ord, +{ + #[inline] + fn compare(&self, key: &Q) -> Ordering { + Ord::cmp(self.borrow(), key) + } +} + /// Compares and returns the minimum of two values. /// /// Returns the first argument if the comparison determines them to be equal. diff --git a/tests/ui/privacy/sysroot-private.default.stderr b/tests/ui/privacy/sysroot-private.default.stderr index 692b1bbd4db35..3f2a562b50de6 100644 --- a/tests/ui/privacy/sysroot-private.default.stderr +++ b/tests/ui/privacy/sysroot-private.default.stderr @@ -1,25 +1,25 @@ -error[E0405]: cannot find trait `Equivalent` in this scope +error[E0405]: cannot find trait `Relocate` in this scope --> $DIR/sysroot-private.rs:27:18 | -LL | trait Trait2: Equivalent {} - | ^^^^^^^^^^ not found in this scope +LL | trait Trait2: Relocate {} + | ^^^^^^^^ not found in this scope error[E0412]: cannot find type `K` in this scope - --> $DIR/sysroot-private.rs:32:35 + --> $DIR/sysroot-private.rs:32:34 | -LL | fn trait_member(val: &T, key: &K) -> bool { - | - ^ +LL | fn trait_member(val: &T, key: K) -> bool { + | - ^ | | | similarly named type parameter `T` defined here | help: a type parameter with a similar name exists | -LL - fn trait_member(val: &T, key: &K) -> bool { -LL + fn trait_member(val: &T, key: &T) -> bool { +LL - fn trait_member(val: &T, key: K) -> bool { +LL + fn trait_member(val: &T, key: T) -> bool { | help: you might be missing a type parameter | -LL | fn trait_member(val: &T, key: &K) -> bool { +LL | fn trait_member(val: &T, key: K) -> bool { | +++ error[E0220]: associated type `ExpressionStack` not found for `Trait` diff --git a/tests/ui/privacy/sysroot-private.rs b/tests/ui/privacy/sysroot-private.rs index 8681857459273..f983c1e232ba7 100644 --- a/tests/ui/privacy/sysroot-private.rs +++ b/tests/ui/privacy/sysroot-private.rs @@ -23,16 +23,16 @@ type AssociatedTy = dyn Trait; //~^ ERROR associated type `ExpressionStack` not found //[rustc_private_enabled]~| NOTE there is an associated type `ExpressionStack` in the trait `gimli::read::op::EvaluationStorage` -// Attempt to get a suggestion for `hashbrown::Equivalent` -trait Trait2: Equivalent {} +// Attempt to get a suggestion for `gimli::read::Relocate` +trait Trait2: Relocate {} //~^ ERROR cannot find trait //~| NOTE not found -// Attempt to get a suggestion for `hashbrown::Equivalent::equivalent` -fn trait_member(val: &T, key: &K) -> bool { +// Attempt to get a suggestion for `gimli::read::Relocate::relocate_address` +fn trait_member(val: &T, key: K) -> bool { //~^ ERROR cannot find type `K` //~| NOTE similarly named - val.equivalent(key) + val.relocate_address(key, 0).is_ok() } // Attempt to get a suggestion for `memchr::memchr2` diff --git a/tests/ui/privacy/sysroot-private.rustc_private_enabled.stderr b/tests/ui/privacy/sysroot-private.rustc_private_enabled.stderr index dc2d890a082cf..3f0d438d28ed2 100644 --- a/tests/ui/privacy/sysroot-private.rustc_private_enabled.stderr +++ b/tests/ui/privacy/sysroot-private.rustc_private_enabled.stderr @@ -1,25 +1,25 @@ -error[E0405]: cannot find trait `Equivalent` in this scope +error[E0405]: cannot find trait `Relocate` in this scope --> $DIR/sysroot-private.rs:27:18 | -LL | trait Trait2: Equivalent {} - | ^^^^^^^^^^ not found in this scope +LL | trait Trait2: Relocate {} + | ^^^^^^^^ not found in this scope error[E0412]: cannot find type `K` in this scope - --> $DIR/sysroot-private.rs:32:35 + --> $DIR/sysroot-private.rs:32:34 | -LL | fn trait_member(val: &T, key: &K) -> bool { - | - ^ +LL | fn trait_member(val: &T, key: K) -> bool { + | - ^ | | | similarly named type parameter `T` defined here | help: a type parameter with a similar name exists | -LL - fn trait_member(val: &T, key: &K) -> bool { -LL + fn trait_member(val: &T, key: &T) -> bool { +LL - fn trait_member(val: &T, key: K) -> bool { +LL + fn trait_member(val: &T, key: T) -> bool { | help: you might be missing a type parameter | -LL | fn trait_member(val: &T, key: &K) -> bool { +LL | fn trait_member(val: &T, key: K) -> bool { | +++ error[E0220]: associated type `ExpressionStack` not found for `Trait`