diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index e3a6e90566f5e..94c46c78074fe 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}; @@ -317,7 +316,7 @@ impl BTreeMap { let (map, dormant_map) = DormantMutRef::new(self); let root_node = map.root.get_or_insert_with(|| Root::new((*map.alloc).clone())).borrow_mut(); - match root_node.search_tree::(&key) { + match root_node.search_tree(&key) { Found(mut kv) => Some(mem::replace(kv.key_mut(), key)), GoDown(handle) => { VacantEntry { @@ -333,20 +332,19 @@ impl BTreeMap { } } - pub(super) fn get_or_insert_with(&mut self, q: &Q, f: F) -> &K + pub(super) fn get_or_insert_with(&mut self, q: Q, f: F) -> &K where - K: Borrow + Ord, - Q: Ord, - F: FnOnce(&Q) -> K, + K: Comparable + Ord, + F: FnOnce(Q) -> K, { let (map, dormant_map) = DormantMutRef::new(self); let root_node = map.root.get_or_insert_with(|| Root::new((*map.alloc).clone())).borrow_mut(); - match root_node.search_tree(q) { + match root_node.search_tree(q.clone()) { Found(handle) => handle.into_kv_mut().0, GoDown(handle) => { - let key = f(q); - assert!(*key.borrow() == *q, "new value is not equal"); + let key = f(q.clone()); + assert!(key.compare(q) == Ordering::Equal, "new value is not equal"); VacantEntry { key, handle: Some(handle), @@ -716,10 +714,9 @@ impl BTreeMap { /// assert_eq!(map.get(&2), None); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn get(&self, key: &Q) -> Option<&V> + 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) { @@ -782,10 +779,9 @@ impl BTreeMap { /// assert_eq!(map.get_key_value(&p), None); /// ``` #[stable(feature = "map_get_key_value", since = "1.40.0")] - pub fn get_key_value(&self, k: &Q) -> Option<(&K, &V)> + 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) { @@ -978,10 +974,9 @@ impl BTreeMap { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "btreemap_contains_key")] - pub fn contains_key(&self, key: &Q) -> bool + pub fn contains_key(&self, key: Q) -> bool where - K: Borrow + Ord, - Q: Ord, + K: Comparable + Ord, { self.get(key).is_some() } @@ -1005,10 +1000,9 @@ impl BTreeMap { /// ``` // See `get` for implementation notes, this is basically a copy-paste with mut's added #[stable(feature = "rust1", since = "1.0.0")] - pub fn get_mut(&mut self, key: &Q) -> Option<&mut V> + 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) { @@ -1107,10 +1101,9 @@ impl BTreeMap { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[rustc_confusables("delete", "take")] - pub fn remove(&mut self, key: &Q) -> Option + pub fn remove(&mut self, key: Q) -> Option where - K: Borrow + Ord, - Q: Ord, + K: Comparable + Ord, { self.remove_entry(key).map(|(_, v)| v) } @@ -1132,10 +1125,9 @@ impl BTreeMap { /// assert_eq!(map.remove_entry(&1), None); /// ``` #[stable(feature = "btreemap_remove_entry", since = "1.45.0")] - pub fn remove_entry(&mut self, key: &Q) -> Option<(K, V)> + 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(); @@ -1410,7 +1402,7 @@ impl BTreeMap { pub fn range(&self, range: R) -> Range<'_, K, V> where T: Ord, - K: Borrow + Ord, + K: for<'a> Comparable<&'a T>, R: RangeBounds, { if let Some(root) = &self.root { @@ -1450,7 +1442,7 @@ impl BTreeMap { pub fn range_mut(&mut self, range: R) -> RangeMut<'_, K, V> where T: Ord, - K: Borrow + Ord, + K: for<'a> Comparable<&'a T>, R: RangeBounds, { if let Some(root) = &mut self.root { @@ -1539,9 +1531,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() { @@ -2616,10 +2608,9 @@ impl Debug for BTreeMap { } #[stable(feature = "rust1", since = "1.0.0")] -impl Index<&Q> for BTreeMap +impl Index for BTreeMap where - K: Borrow + Ord, - Q: Ord, + K: Comparable + Ord, { type Output = V; @@ -2629,7 +2620,7 @@ where /// /// Panics if the key is not present in the `BTreeMap`. #[inline] - fn index(&self, key: &Q) -> &V { + fn index(&self, key: Q) -> &V { self.get(key).expect("no entry found for key") } } @@ -2870,10 +2861,9 @@ impl BTreeMap { /// assert_eq!(cursor.peek_next(), Some((&1, &"a"))); /// ``` #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn lower_bound(&self, bound: Bound<&Q>) -> Cursor<'_, K, V> + pub fn lower_bound(&self, bound: Bound) -> 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 }, @@ -2923,10 +2913,9 @@ impl BTreeMap { /// assert_eq!(cursor.peek_next(), Some((&1, &mut "a"))); /// ``` #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn lower_bound_mut(&mut self, bound: Bound<&Q>) -> CursorMut<'_, K, V, A> + pub fn lower_bound_mut(&mut self, bound: Bound) -> 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() { @@ -2993,10 +2982,9 @@ impl BTreeMap { /// assert_eq!(cursor.peek_next(), None); /// ``` #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn upper_bound(&self, bound: Bound<&Q>) -> Cursor<'_, K, V> + pub fn upper_bound(&self, bound: Bound) -> 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 }, @@ -3046,10 +3034,9 @@ impl BTreeMap { /// assert_eq!(cursor.peek_next(), None); /// ``` #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn upper_bound_mut(&mut self, bound: Bound<&Q>) -> CursorMut<'_, K, V, A> + pub fn upper_bound_mut(&mut self, bound: Bound) -> 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 64348745aa07d..e0d0c4c109e41 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; +use std::borrow::Borrow; use std::ops::Bound::{Excluded, Included, Unbounded}; use std::panic::{AssertUnwindSafe, catch_unwind}; use std::sync::atomic::AtomicUsize; @@ -2795,3 +2796,19 @@ fn test_id_based_merge() { assert_eq!(merged_kv_pair.0.id, 0); assert_eq!(merged_kv_pair.0.name, "lhs_k".to_string()); } + +#[test] +fn test_comparable_tuple_lookup() { + let mut map = BTreeMap::new(); + map.insert(("hello".to_string(), "world".to_string()), 1); + map.insert(("foo".to_string(), "bar".to_string()), 2); + + assert_eq!(map.get(("hello", "world")), Some(&1)); + assert_eq!(map.get(("foo", "bar")), Some(&2)); + assert_eq!(map.get(("missing", "key")), None); + + assert!(map.contains_key(("hello", "world"))); + assert!(!map.contains_key(("missing", "key"))); + + assert_eq!(map[("foo", "bar")], 2); +} diff --git a/library/alloc/src/collections/btree/navigate.rs b/library/alloc/src/collections/btree/navigate.rs index b2a7de74875d9..34cb2911c2a2c 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: for<'a> Comparable<&'a Q>, 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: for<'b> Comparable<&'b Q>, 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: for<'b> Comparable<&'b Q>, R: RangeBounds, { unsafe { self.find_leaf_edges_spanning_range(range) } @@ -741,13 +741,12 @@ impl impl NodeRef { /// Returns the leaf edge corresponding to the first point at which the /// given bound is true. - pub(super) fn lower_bound( + pub(super) fn lower_bound( self, - mut bound: SearchBound<&Q>, + mut bound: SearchBound, ) -> Handle, marker::Edge> where - Q: Ord, - K: Borrow, + K: Comparable, { let mut node = self; loop { @@ -764,13 +763,12 @@ impl NodeRef( + pub(super) fn upper_bound( self, - mut bound: SearchBound<&Q>, + mut bound: SearchBound, ) -> 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..63962356b54a5 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::*; @@ -46,16 +45,15 @@ impl NodeRef( + pub(super) fn search_tree( mut self, - key: &Q, + key: Q, ) -> SearchResult where - Q: Ord, - K: Borrow, + K: Comparable, { loop { - self = match self.search_node(key) { + self = match self.search_node(key.clone()) { Found(handle) => return Found(handle), GoDown(handle) => match handle.force() { Leaf(leaf) => return GoDown(leaf), @@ -95,7 +93,7 @@ impl NodeRef where Q: Ord, - K: Borrow, + K: for<'a> Comparable<&'a Q>, R: RangeBounds, { // Determine if map or set is being searched @@ -156,13 +154,12 @@ impl NodeRef( + pub(super) fn find_lower_bound_edge( self, - bound: SearchBound<&'r Q>, - ) -> (Handle, SearchBound<&'r Q>) + bound: SearchBound, + ) -> (Handle, SearchBound) where - Q: ?Sized + Ord, - K: Borrow, + K: Comparable, { let (edge_idx, bound) = self.find_lower_bound_index(bound); let edge = unsafe { Handle::new_edge(self, edge_idx) }; @@ -170,13 +167,12 @@ impl NodeRef( + pub(super) fn find_upper_bound_edge( self, - bound: SearchBound<&'r Q>, - ) -> (Handle, SearchBound<&'r Q>) + bound: SearchBound, + ) -> (Handle, SearchBound) where - Q: ?Sized + Ord, - K: Borrow, + K: Comparable, { let (edge_idx, bound) = unsafe { self.find_upper_bound_index(bound, 0) }; let edge = unsafe { Handle::new_edge(self, edge_idx) }; @@ -192,13 +188,9 @@ impl NodeRef { /// /// The result is meaningful only if the tree is ordered by key, like the tree /// in a `BTreeMap` is. - pub(super) fn search_node( - self, - key: &Q, - ) -> SearchResult + pub(super) fn search_node(self, 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) }), @@ -214,19 +206,18 @@ impl NodeRef { /// /// # Safety /// `start_index` must be a valid edge index for the node. - unsafe fn find_key_index(&self, key: &Q, start_index: usize) -> IndexResult + 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.clone()) { + 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()) @@ -237,22 +228,18 @@ impl NodeRef { /// the matching child node, if `self` is an internal node. /// /// The result is meaningful only if the tree is ordered by key. - fn find_lower_bound_index<'r, Q>( - &self, - bound: SearchBound<&'r Q>, - ) -> (usize, SearchBound<&'r Q>) + fn find_lower_bound_index(&self, bound: SearchBound) -> (usize, SearchBound) where - Q: ?Sized + Ord, - K: Borrow, + K: Comparable, { match bound { - Included(key) => match unsafe { self.find_key_index(key, 0) } { + Included(key) => match unsafe { self.find_key_index(key.clone(), 0) } { IndexResult::KV(idx) => (idx, AllExcluded), - IndexResult::Edge(idx) => (idx, bound), + IndexResult::Edge(idx) => (idx, Included(key)), }, - Excluded(key) => match unsafe { self.find_key_index(key, 0) } { + Excluded(key) => match unsafe { self.find_key_index(key.clone(), 0) } { IndexResult::KV(idx) => (idx + 1, AllIncluded), - IndexResult::Edge(idx) => (idx, bound), + IndexResult::Edge(idx) => (idx, Excluded(key)), }, AllIncluded => (0, AllIncluded), AllExcluded => (self.len(), AllExcluded), @@ -264,23 +251,22 @@ impl NodeRef { /// /// # Safety /// `start_index` must be a valid edge index for the node. - unsafe fn find_upper_bound_index<'r, Q>( + unsafe fn find_upper_bound_index( &self, - bound: SearchBound<&'r Q>, + bound: SearchBound, start_index: usize, - ) -> (usize, SearchBound<&'r Q>) + ) -> (usize, SearchBound) where - Q: ?Sized + Ord, - K: Borrow, + K: Comparable, { match bound { - Included(key) => match unsafe { self.find_key_index(key, start_index) } { + Included(key) => match unsafe { self.find_key_index(key.clone(), start_index) } { IndexResult::KV(idx) => (idx + 1, AllExcluded), - IndexResult::Edge(idx) => (idx, bound), + IndexResult::Edge(idx) => (idx, Included(key)), }, - Excluded(key) => match unsafe { self.find_key_index(key, start_index) } { + Excluded(key) => match unsafe { self.find_key_index(key.clone(), start_index) } { IndexResult::KV(idx) => (idx, AllIncluded), - IndexResult::Edge(idx) => (idx, bound), + IndexResult::Edge(idx) => (idx, Excluded(key)), }, AllIncluded => (self.len(), AllIncluded), AllExcluded => (start_index, AllExcluded), diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index db8007834432c..53c88ae67dd90 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, TrustedLen}; @@ -397,7 +396,7 @@ impl BTreeSet { pub fn range(&self, range: R) -> Range<'_, T> where K: Ord, - T: Borrow + Ord, + T: for<'a> Comparable<&'a K> + Ord, R: RangeBounds, { Range { iter: self.map.range(range) } @@ -602,10 +601,9 @@ impl BTreeSet { /// assert_eq!(set.contains(&4), false); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn contains(&self, value: &Q) -> bool + pub fn contains(&self, value: Q) -> bool where - T: Borrow + Ord, - Q: Ord, + T: Comparable + Ord, { self.map.contains_key(value) } @@ -627,10 +625,9 @@ impl BTreeSet { /// assert_eq!(set.get(&4), None); /// ``` #[stable(feature = "set_recovery", since = "1.9.0")] - pub fn get(&self, value: &Q) -> Option<&T> + 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) } @@ -974,11 +971,10 @@ impl BTreeSet { /// ``` #[inline] #[unstable(feature = "btree_set_entry", issue = "133549")] - pub fn get_or_insert_with(&mut self, value: &Q, f: F) -> &T + pub fn get_or_insert_with(&mut self, value: Q, f: F) -> &T where - T: Borrow + Ord, - Q: Ord, - F: FnOnce(&Q) -> T, + T: Comparable + Ord, + F: FnOnce(Q) -> T, { self.map.get_or_insert_with(value, f) } @@ -1049,10 +1045,9 @@ impl BTreeSet { /// assert_eq!(set.remove(&2), false); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn remove(&mut self, value: &Q) -> bool + pub fn remove(&mut self, value: Q) -> bool where - T: Borrow + Ord, - Q: Ord, + T: Comparable + Ord, { self.map.remove(value).is_some() } @@ -1074,10 +1069,9 @@ impl BTreeSet { /// assert_eq!(set.take(&2), None); /// ``` #[stable(feature = "set_recovery", since = "1.9.0")] - pub fn take(&mut self, value: &Q) -> Option + 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) } @@ -1173,9 +1167,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) } @@ -1327,10 +1321,9 @@ impl BTreeSet { /// assert_eq!(cursor.peek_next(), Some(&1)); /// ``` #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn lower_bound(&self, bound: Bound<&Q>) -> Cursor<'_, T> + pub fn lower_bound(&self, bound: Bound) -> Cursor<'_, T> where - T: Borrow + Ord, - Q: Ord, + T: Comparable + Ord, { Cursor { inner: self.map.lower_bound(bound) } } @@ -1370,10 +1363,9 @@ impl BTreeSet { /// assert_eq!(cursor.peek_next(), Some(&1)); /// ``` #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn lower_bound_mut(&mut self, bound: Bound<&Q>) -> CursorMut<'_, T, A> + pub fn lower_bound_mut(&mut self, bound: Bound) -> CursorMut<'_, T, A> where - T: Borrow + Ord, - Q: Ord, + T: Comparable + Ord, { CursorMut { inner: self.map.lower_bound_mut(bound) } } @@ -1413,10 +1405,9 @@ impl BTreeSet { /// assert_eq!(cursor.peek_next(), None); /// ``` #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn upper_bound(&self, bound: Bound<&Q>) -> Cursor<'_, T> + pub fn upper_bound(&self, bound: Bound) -> Cursor<'_, T> where - T: Borrow + Ord, - Q: Ord, + T: Comparable + Ord, { Cursor { inner: self.map.upper_bound(bound) } } @@ -1456,10 +1447,9 @@ impl BTreeSet { /// assert_eq!(cursor.peek_next(), None); /// ``` #[unstable(feature = "btree_cursors", issue = "107540")] - pub fn upper_bound_mut(&mut self, bound: Bound<&Q>) -> CursorMut<'_, T, A> + pub fn upper_bound_mut(&mut self, bound: Bound) -> 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..9713ff1338c71 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()); @@ -45,7 +41,7 @@ impl Root { let mut right_node = right_root.borrow_mut(); loop { - let mut split_edge = match left_node.search_node(key) { + let mut split_edge = match left_node.search_node(key.clone()) { // key is going to the right tree Found(kv) => kv.left_edge(), GoDown(edge) => edge, diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index aff10c4320fe1..46c236a3300a2 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -98,6 +98,7 @@ #![feature(char_internals)] #![feature(clone_to_uninit)] #![feature(coerce_unsized)] +#![feature(comparable_trait)] #![feature(const_clone)] #![feature(const_cmp)] #![feature(const_convert)] diff --git a/library/alloctests/lib.rs b/library/alloctests/lib.rs index e09d8495fdeac..f20f85155f1c7 100644 --- a/library/alloctests/lib.rs +++ b/library/alloctests/lib.rs @@ -17,6 +17,7 @@ #![feature(allocator_api)] #![feature(array_into_iter_constructors)] #![feature(char_internals)] +#![feature(comparable_trait)] #![feature(const_alloc_error)] #![feature(const_cmp)] #![feature(const_convert)] diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 49d7487c2803b..7e17cf2689a91 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -1535,6 +1535,82 @@ 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<'a, Q: ?Sized, K: ?Sized> Equivalent<&'a Q> for K +where + K: crate::borrow::Borrow, + Q: Eq, +{ + #[inline] + fn equivalent(&self, key: &'a Q) -> bool { + PartialEq::eq(self.borrow(), key) + } +} + +#[unstable(feature = "comparable_trait", issue = "145986")] +impl<'a, Q1: ?Sized, K1, Q2: ?Sized, K2> Equivalent<(&'a Q1, &'a Q2)> for (K1, K2) +where + Q1: Eq, + K1: crate::borrow::Borrow, + Q2: Eq, + K2: crate::borrow::Borrow, +{ + #[inline] + fn equivalent(&self, key: (&'a Q1, &'a Q2)) -> bool { + PartialEq::eq(self.0.borrow(), key.0) && PartialEq::eq(self.1.borrow(), key.1) + } +} + +/// Key ordering trait. +/// +/// This trait allows ordered map lookup to be customized. +#[unstable(feature = "comparable_trait", issue = "145986")] +pub trait Comparable { + /// 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<'a, Q: ?Sized, K: ?Sized> Comparable<&'a Q> for K +where + K: crate::borrow::Borrow, + Q: Ord, +{ + #[inline] + fn compare(&self, key: &'a Q) -> Ordering { + Ord::cmp(self.borrow(), key) + } +} + +#[unstable(feature = "comparable_trait", issue = "145986")] +impl<'a, Q1: ?Sized, K1, Q2: ?Sized, K2> Comparable<(&'a Q1, &'a Q2)> for (K1, K2) +where + Q1: Ord, + K1: crate::borrow::Borrow, + Q2: Ord, + K2: crate::borrow::Borrow, +{ + #[inline] + fn compare(&self, key: (&'a Q1, &'a Q2)) -> Ordering { + Ord::cmp(self.0.borrow(), key.0).then_with(|| Ord::cmp(self.1.borrow(), key.1)) + } +} + /// 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 66712a59e7b27..ec6389375eebb 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[E0425]: 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 94b85b995c479..e6b83b2a82931 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[E0425]: 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`