diff --git a/src/libcollections/borrow.rs b/src/libcollections/borrow.rs index 6b45c25eb2139..22f71ca2562ad 100644 --- a/src/libcollections/borrow.rs +++ b/src/libcollections/borrow.rs @@ -69,6 +69,33 @@ impl ToOwned for T where T: Clone { } } +#[unstable(feature = "entry_into_owned", issue = "1")] +pub trait AsBorrowOf: Sized where T: Borrow { + #[unstable(feature = "entry_into_owned", issue = "1")] + fn into_owned(self) -> T; + + #[unstable(feature = "entry_into_owned", issue = "1")] + fn as_borrow_of(&self) -> &B; +} + +#[unstable(feature = "entry_into_owned", issue = "1")] +impl AsBorrowOf for T { + default fn into_owned(self) -> T { self } + default fn as_borrow_of(&self) -> &Self { self } +} + +#[unstable(feature = "entry_into_owned", issue = "1")] +impl<'a, T: Deref> AsBorrowOf<&'a T::Target, T::Target> for &'a T { + default fn into_owned(self) -> &'a T::Target { self.deref() } + default fn as_borrow_of(&self) -> &T::Target { self.deref() } +} + +#[unstable(feature = "entry_into_owned", issue = "1")] +impl<'a, B: ToOwned + ?Sized> AsBorrowOf for &'a B { + fn into_owned(self) -> B::Owned { self.to_owned() } + fn as_borrow_of(&self) -> &B { *self } +} + /// A clone-on-write smart pointer. /// /// The type `Cow` is a smart pointer providing clone-on-write functionality: it diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs index 788236c24d063..4a803f2428841 100644 --- a/src/libcollections/btree/map.rs +++ b/src/libcollections/btree/map.rs @@ -16,7 +16,7 @@ use core::marker::PhantomData; use core::ops::Index; use core::{fmt, intrinsics, mem, ptr}; -use borrow::Borrow; +use borrow::{Borrow, AsBorrowOf}; use Bound::{self, Excluded, Included, Unbounded}; use super::node::{self, Handle, NodeRef, marker}; @@ -112,6 +112,7 @@ use self::Entry::*; /// // type inference lets us omit an explicit type signature (which /// // would be `BTreeMap<&str, u8>` in this example). /// let mut player_stats = BTreeMap::new(); +/// # {let __help_inference_out: &BTreeMap<&_, _> = &player_stats;} /// /// fn random_stat_buff() -> u8 { /// // could actually return some random value here - let's just return @@ -219,7 +220,7 @@ impl Clone for BTreeMap { } impl super::Recover for BTreeMap - where K: Borrow + Ord, + where K: Borrow + Borrow + Ord, Q: Ord { type Key = K; @@ -324,11 +325,11 @@ pub struct RangeMut<'a, K: 'a, V: 'a> { /// [`BTreeMap`]: struct.BTreeMap.html /// [`entry`]: struct.BTreeMap.html#method.entry #[stable(feature = "rust1", since = "1.0.0")] -pub enum Entry<'a, K: 'a, V: 'a> { +pub enum Entry<'a, K: 'a, V: 'a, Q: 'a = K, B: 'a + ?Sized = K> { /// A vacant Entry #[stable(feature = "rust1", since = "1.0.0")] Vacant(#[stable(feature = "rust1", since = "1.0.0")] - VacantEntry<'a, K, V>), + VacantEntry<'a, K, V, Q, B>), /// An occupied Entry #[stable(feature = "rust1", since = "1.0.0")] @@ -337,7 +338,12 @@ pub enum Entry<'a, K: 'a, V: 'a> { } #[stable(feature= "debug_btree_map", since = "1.12.0")] -impl<'a, K: 'a + Debug + Ord, V: 'a + Debug> Debug for Entry<'a, K, V> { +impl<'a, K, V, Q, B: ?Sized> Debug for Entry<'a, K, V, Q, B> + where K: 'a + Debug + Ord, + V: 'a + Debug, + Q: 'a + Debug, + B: 'a +{ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { Vacant(ref v) => f.debug_tuple("Entry") @@ -354,20 +360,25 @@ impl<'a, K: 'a + Debug + Ord, V: 'a + Debug> Debug for Entry<'a, K, V> { /// /// [`Entry`]: enum.Entry.html #[stable(feature = "rust1", since = "1.0.0")] -pub struct VacantEntry<'a, K: 'a, V: 'a> { - key: K, +pub struct VacantEntry<'a, K: 'a, V: 'a, Q: 'a = K, B: 'a + ?Sized = K> { + key: Q, handle: Handle, K, V, marker::Leaf>, marker::Edge>, length: &'a mut usize, // Be invariant in `K` and `V` - _marker: PhantomData<&'a mut (K, V)>, + _marker: PhantomData<&'a mut (K, V, B)>, } #[stable(feature= "debug_btree_map", since = "1.12.0")] -impl<'a, K: 'a + Debug + Ord, V: 'a> Debug for VacantEntry<'a, K, V> { +impl<'a, K, V, Q, B: ?Sized> Debug for VacantEntry<'a, K, V, Q, B> + where K: 'a + Debug + Ord, + V: 'a, + Q: 'a + Debug, + B: 'a +{ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("VacantEntry") - .field(self.key()) + .field(&self.key) .finish() } } @@ -861,8 +872,12 @@ impl BTreeMap { /// assert_eq!(count["a"], 3); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn entry(&mut self, key: K) -> Entry { - match search::search_tree(self.root.as_mut(), &key) { + pub fn entry(&mut self, key: Q) -> Entry + where Q: AsBorrowOf, + K: Borrow, + B: Ord, + { + match search::search_tree(self.root.as_mut(), key.as_borrow_of()) { Found(handle) => { Occupied(OccupiedEntry { handle: handle, @@ -1960,7 +1975,10 @@ impl BTreeMap { } } -impl<'a, K: Ord, V> Entry<'a, K, V> { +impl<'a, K, V, Q, B: ?Sized> Entry<'a, K, V, Q, B> + where K: Ord + Borrow, + Q: AsBorrowOf +{ /// Ensures a value is in the entry by inserting the default if empty, and returns /// a mutable reference to the value in the entry. /// @@ -2004,7 +2022,9 @@ impl<'a, K: Ord, V> Entry<'a, K, V> { Vacant(entry) => entry.insert(default()), } } +} +impl<'a, K: Ord, V, B: ?Sized> Entry<'a, K, V, K, B> { /// Returns a reference to this entry's key. /// /// # Examples @@ -2024,7 +2044,7 @@ impl<'a, K: Ord, V> Entry<'a, K, V> { } } -impl<'a, K: Ord, V> VacantEntry<'a, K, V> { +impl<'a, K: Ord, V, B: ?Sized> VacantEntry<'a, K, V, K, B> { /// Gets a reference to the key that would be used when inserting a value /// through the VacantEntry. /// @@ -2059,7 +2079,12 @@ impl<'a, K: Ord, V> VacantEntry<'a, K, V> { pub fn into_key(self) -> K { self.key } +} +impl<'a, K, V, Q, B: ?Sized> VacantEntry<'a, K, V, Q, B> + where K: Ord + Borrow, + Q: AsBorrowOf +{ /// Sets the value of the entry with the `VacantEntry`'s key, /// and returns a mutable reference to it. /// @@ -2082,12 +2107,13 @@ impl<'a, K: Ord, V> VacantEntry<'a, K, V> { *self.length += 1; let out_ptr; + let key = AsBorrowOf::::into_owned(self.key); let mut ins_k; let mut ins_v; let mut ins_edge; - let mut cur_parent = match self.handle.insert(self.key, value) { + let mut cur_parent = match self.handle.insert(key, value) { (Fit(handle), _) => return handle.into_kv_mut().1, (Split(left, k, v, right), ptr) => { ins_k = k; diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index fb8a0c3c26554..89dad64a616f1 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -11,12 +11,13 @@ use self::Entry::*; use self::VacantEntryState::*; -use borrow::Borrow; +use borrow::{Borrow, AsBorrowOf}; use cmp::max; use fmt::{self, Debug}; #[allow(deprecated)] use hash::{Hash, Hasher, BuildHasher, SipHasher13}; use iter::{FromIterator, FusedIterator}; +use marker::PhantomData; use mem::{self, replace}; use ops::{Deref, Index}; use rand::{self, Rng}; @@ -274,6 +275,7 @@ impl DefaultResizePolicy { /// // type inference lets us omit an explicit type signature (which /// // would be `HashMap<&str, u8>` in this example). /// let mut player_stats = HashMap::new(); +/// # {let __help_inference_out: &HashMap<&_, _> = &player_stats;} /// /// fn random_stat_buff() -> u8 { /// // could actually return some random value here - let's just return @@ -967,10 +969,14 @@ impl HashMap /// assert_eq!(letters.get(&'y'), None); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - pub fn entry(&mut self, key: K) -> Entry { + pub fn entry(&mut self, key: Q) -> Entry + where Q: AsBorrowOf, + K: Borrow, + B: Hash + Eq + { // Gotta resize now. self.reserve(1); - self.search_mut(&key).into_entry(key).expect("unreachable") + self.search_mut(key.as_borrow_of()).into_entry(key).expect("unreachable") } /// Returns the number of elements in the map. @@ -1345,7 +1351,11 @@ impl InternalEntry { impl<'a, K, V> InternalEntry> { #[inline] - fn into_entry(self, key: K) -> Option> { + fn into_entry(self, key: Q) -> Option> + where Q: AsBorrowOf, + K: Borrow, + B: Hash + Eq + { match self { InternalEntry::Occupied { elem } => { Some(Occupied(OccupiedEntry { @@ -1358,6 +1368,7 @@ impl<'a, K, V> InternalEntry> { hash: hash, key: key, elem: elem, + _phantom: PhantomData, })) } InternalEntry::TableIsEmpty => None, @@ -1371,20 +1382,22 @@ impl<'a, K, V> InternalEntry> { /// [`HashMap`]: struct.HashMap.html /// [`entry`]: struct.HashMap.html#method.entry #[stable(feature = "rust1", since = "1.0.0")] -pub enum Entry<'a, K: 'a, V: 'a> { +pub enum Entry<'a, K: 'a, V: 'a, Q: 'a = K, B: ?Sized + 'a = K> { /// An occupied Entry. #[stable(feature = "rust1", since = "1.0.0")] Occupied(#[stable(feature = "rust1", since = "1.0.0")] - OccupiedEntry<'a, K, V>), + OccupiedEntry<'a, K, V, Q>), /// A vacant Entry. #[stable(feature = "rust1", since = "1.0.0")] Vacant(#[stable(feature = "rust1", since = "1.0.0")] - VacantEntry<'a, K, V>), + VacantEntry<'a, K, V, Q, B>), } #[stable(feature= "debug_hash_map", since = "1.12.0")] -impl<'a, K: 'a + Debug, V: 'a + Debug> Debug for Entry<'a, K, V> { +impl<'a, K, V, Q, B: ?Sized> Debug for Entry<'a, K, V, Q, B> + where K: 'a + Debug, V: 'a + Debug, Q: 'a + Debug, B: 'a +{ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { Vacant(ref v) => { @@ -1406,13 +1419,13 @@ impl<'a, K: 'a + Debug, V: 'a + Debug> Debug for Entry<'a, K, V> { /// /// [`Entry`]: enum.Entry.html #[stable(feature = "rust1", since = "1.0.0")] -pub struct OccupiedEntry<'a, K: 'a, V: 'a> { - key: Option, +pub struct OccupiedEntry<'a, K: 'a, V: 'a, Q: 'a = K> { + key: Option, elem: FullBucket>, } #[stable(feature= "debug_hash_map", since = "1.12.0")] -impl<'a, K: 'a + Debug, V: 'a + Debug> Debug for OccupiedEntry<'a, K, V> { +impl<'a, K: 'a + Debug, V: 'a + Debug, Q: 'a> Debug for OccupiedEntry<'a, K, V, Q> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("OccupiedEntry") .field("key", self.key()) @@ -1426,17 +1439,23 @@ impl<'a, K: 'a + Debug, V: 'a + Debug> Debug for OccupiedEntry<'a, K, V> { /// /// [`Entry`]: enum.Entry.html #[stable(feature = "rust1", since = "1.0.0")] -pub struct VacantEntry<'a, K: 'a, V: 'a> { +pub struct VacantEntry<'a, K: 'a, V: 'a, Q: 'a = K, B: ?Sized + 'a = K> { hash: SafeHash, - key: K, + key: Q, elem: VacantEntryState>, + _phantom: PhantomData<&'a B>, } #[stable(feature= "debug_hash_map", since = "1.12.0")] -impl<'a, K: 'a + Debug, V: 'a> Debug for VacantEntry<'a, K, V> { +impl<'a, K, V, Q, B: ?Sized> Debug for VacantEntry<'a, K, V, Q, B> + where K: 'a + Debug, + V: 'a, + Q: 'a + Debug, + B: 'a +{ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("VacantEntry") - .field(self.key()) + .field(&self.key) .finish() } } @@ -1668,7 +1687,9 @@ impl<'a, K, V> ExactSizeIterator for Drain<'a, K, V> { #[unstable(feature = "fused", issue = "35602")] impl<'a, K, V> FusedIterator for Drain<'a, K, V> {} -impl<'a, K, V> Entry<'a, K, V> { +impl<'a, K, V, Q, B: ?Sized> Entry<'a, K, V, Q, B> + where K: Borrow, Q: AsBorrowOf +{ #[stable(feature = "rust1", since = "1.0.0")] /// Ensures a value is in the entry by inserting the default if empty, and returns /// a mutable reference to the value in the entry. @@ -1715,7 +1736,9 @@ impl<'a, K, V> Entry<'a, K, V> { Vacant(entry) => entry.insert(default()), } } +} +impl<'a, K, V, B: ?Sized> Entry<'a, K, V, K, B> { /// Returns a reference to this entry's key. /// /// # Examples @@ -1735,7 +1758,7 @@ impl<'a, K, V> Entry<'a, K, V> { } } -impl<'a, K, V> OccupiedEntry<'a, K, V> { +impl<'a, K, V, Q> OccupiedEntry<'a, K, V, Q> { /// Gets a reference to the key in the entry. /// /// # Examples @@ -1898,12 +1921,12 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { /// Returns a key that was used for search. /// /// The key was retained for further use. - fn take_key(&mut self) -> Option { + fn take_key(&mut self) -> Option { self.key.take() } } -impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> { +impl<'a, K: 'a, V: 'a, B: ?Sized + 'a> VacantEntry<'a, K, V, K, B> { /// Gets a reference to the key that would be used when inserting a value /// through the `VacantEntry`. /// @@ -1938,7 +1961,13 @@ impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> { pub fn into_key(self) -> K { self.key } +} +impl<'a, K: 'a, V: 'a, Q: 'a, B: ?Sized + 'a> VacantEntry<'a, K, V, Q, B> + where K: 'a + Borrow, + V: 'a, + Q: 'a + AsBorrowOf +{ /// Sets the value of the entry with the VacantEntry's key, /// and returns a mutable reference to it. /// @@ -1957,9 +1986,10 @@ impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn insert(self, value: V) -> &'a mut V { + let key = AsBorrowOf::::into_owned(self.key); match self.elem { - NeqElem(bucket, ib) => robin_hood(bucket, ib, self.hash, self.key, value), - NoElem(bucket) => bucket.put(self.hash, self.key, value).into_mut_refs().1, + NeqElem(bucket, ib) => robin_hood(bucket, ib, self.hash, key, value), + NoElem(bucket) => bucket.put(self.hash, key, value).into_mut_refs().1, } } } @@ -2135,7 +2165,7 @@ impl Default for RandomState { } impl super::Recover for HashMap - where K: Eq + Hash + Borrow, + where K: Eq + Hash + Borrow + Borrow, S: BuildHasher, Q: Eq + Hash { diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index c2f6a6f660c48..534f9219fc0c0 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -230,6 +230,7 @@ #![feature(core_intrinsics)] #![feature(dotdot_in_tuple_patterns)] #![feature(dropck_parametricity)] +#![feature(entry_into_owned)] #![feature(float_extras)] #![feature(float_from_str_radix)] #![feature(fn_traits)]