Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 26 additions & 5 deletions library/alloc/src/collections/btree/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1059,7 +1059,7 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
/// a mutable reference to the value in the entry.
///
/// If the map already had this key present, nothing is updated, and
/// an error containing the occupied entry and the value is returned.
/// an error containing the occupied entry, key, and the value is returned.
///
/// # Examples
///
Expand All @@ -1074,17 +1074,38 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
/// let err = map.try_insert(37, "b").unwrap_err();
/// assert_eq!(err.entry.key(), &37);
/// assert_eq!(err.entry.get(), &"a");
/// assert_eq!(err.key, 37);
/// assert_eq!(err.value, "b");
/// ```
#[unstable(feature = "map_try_insert", issue = "82766")]
pub fn try_insert(&mut self, key: K, value: V) -> Result<&mut V, OccupiedError<'_, K, V, A>>
where
K: Ord,
{
match self.entry(key) {
Occupied(entry) => Err(OccupiedError { entry, value }),
Vacant(entry) => Ok(entry.insert(value)),
}
let (map, dormant_map) = DormantMutRef::new(self);
let handle = match map.root {
Some(ref mut root) => match root.borrow_mut().search_tree(&key) {
Found(handle) => {
let entry = OccupiedEntry {
handle,
dormant_map,
alloc: (*map.alloc).clone(),
_marker: PhantomData,
};
return Err(OccupiedError { entry, key, value });
}
GoDown(handle) => Some(handle),
},
None => None,
};
let entry = VacantEntry {
key,
handle,
dormant_map,
alloc: (*map.alloc).clone(),
_marker: PhantomData,
};
Ok(entry.insert(value))
}

/// Removes a key from the map, returning the value at the key if the key
Expand Down
27 changes: 5 additions & 22 deletions library/alloc/src/collections/btree/map/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,9 @@ impl<K: Debug + Ord, V: Debug, A: Allocator + Clone> Debug for OccupiedEntry<'_,

/// The error returned by [`try_insert`](BTreeMap::try_insert) when the key already exists.
///
/// Contains the occupied entry, and the value that was not inserted.
/// Contains the occupied entry, key, and the value that was not inserted.
#[unstable(feature = "map_try_insert", issue = "82766")]
#[non_exhaustive]
pub struct OccupiedError<
'a,
K: 'a,
Expand All @@ -109,40 +110,22 @@ pub struct OccupiedError<
pub entry: OccupiedEntry<'a, K, V, A>,
/// The value which was not inserted, because the entry was already occupied.
pub value: V,
/// The key which was not inserted, because the entry was already occupied.
pub key: K,
}

#[unstable(feature = "map_try_insert", issue = "82766")]
impl<K: Debug + Ord, V: Debug, A: Allocator + Clone> Debug for OccupiedError<'_, K, V, A> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("OccupiedError")
.field("key", self.entry.key())
.field("uninserted_key", &self.key)
.field("old_value", self.entry.get())
.field("new_value", &self.value)
.finish()
}
}

#[unstable(feature = "map_try_insert", issue = "82766")]
impl<'a, K: Debug + Ord, V: Debug, A: Allocator + Clone> fmt::Display
for OccupiedError<'a, K, V, A>
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"failed to insert {:?}, key {:?} already exists with value {:?}",
self.value,
self.entry.key(),
self.entry.get(),
)
}
}

#[unstable(feature = "map_try_insert", issue = "82766")]
impl<'a, K: core::fmt::Debug + Ord, V: core::fmt::Debug> core::error::Error
for crate::collections::btree_map::OccupiedError<'a, K, V>
{
}

impl<'a, K: Ord, V, A: Allocator + Clone> Entry<'a, K, V, A> {
/// Ensures a value is in the entry by inserting the default if empty, and returns
/// a mutable reference to the value in the entry.
Expand Down
1 change: 1 addition & 0 deletions library/alloc/src/collections/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ pub mod vec_deque;
pub mod btree_map {
//! An ordered map based on a B-Tree.
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg(not(test))]
pub use super::btree::map::*;
}

Expand Down
38 changes: 14 additions & 24 deletions library/std/src/collections/hash/map.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
#[cfg(test)]
mod tests;

use hashbrown::hash_map as base;
use hashbrown::hash_map::{self as base, RustcEntry};

use self::Entry::*;
use crate::alloc::{Allocator, Global};
use crate::borrow::Borrow;
use crate::collections::{TryReserveError, TryReserveErrorKind};
use crate::error::Error;
use crate::fmt::{self, Debug};
use crate::hash::{BuildHasher, Hash, RandomState};
use crate::iter::FusedIterator;
Expand Down Expand Up @@ -1333,7 +1332,7 @@ where
/// a mutable reference to the value in the entry.
///
/// If the map already had this key present, nothing is updated, and
/// an error containing the occupied entry and the value is returned.
/// an error containing the occupied entry, key, and the value is returned.
///
/// # Examples
///
Expand All @@ -1350,13 +1349,16 @@ where
/// let err = map.try_insert(37, "b").unwrap_err();
/// assert_eq!(err.entry.key(), &37);
/// assert_eq!(err.entry.get(), &"a");
/// assert_eq!(err.key, 37);
/// assert_eq!(err.value, "b");
/// ```
#[unstable(feature = "map_try_insert", issue = "82766")]
pub fn try_insert(&mut self, key: K, value: V) -> Result<&mut V, OccupiedError<'_, K, V, A>> {
match self.entry(key) {
Occupied(entry) => Err(OccupiedError { entry, value }),
Vacant(entry) => Ok(entry.insert(value)),
match self.base.rustc_entry(key) {
RustcEntry::Occupied(entry, key) => {
Err(OccupiedError { entry: OccupiedEntry { base: entry }, key, value })
}
RustcEntry::Vacant(entry) => Ok(entry.insert(value)),
}
}

Expand Down Expand Up @@ -2007,8 +2009,9 @@ impl<K: Debug, V, A: Allocator> Debug for VacantEntry<'_, K, V, A> {

/// The error returned by [`try_insert`](HashMap::try_insert) when the key already exists.
///
/// Contains the occupied entry, and the value that was not inserted.
/// Contains the occupied entry, key, and the value that was not inserted.
#[unstable(feature = "map_try_insert", issue = "82766")]
#[non_exhaustive]
pub struct OccupiedError<
'a,
K: 'a,
Expand All @@ -2019,35 +2022,22 @@ pub struct OccupiedError<
pub entry: OccupiedEntry<'a, K, V, A>,
/// The value which was not inserted, because the entry was already occupied.
pub value: V,
/// The key which was not inserted, because the entry was already occupied.
pub key: K,
}

#[unstable(feature = "map_try_insert", issue = "82766")]
impl<K: Debug, V: Debug, A: Allocator> Debug for OccupiedError<'_, K, V, A> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("OccupiedError")
.field("key", self.entry.key())
.field("uninserted_key", &self.key)
.field("old_value", self.entry.get())
.field("new_value", &self.value)
.finish_non_exhaustive()
}
}

#[unstable(feature = "map_try_insert", issue = "82766")]
impl<'a, K: Debug, V: Debug, A: Allocator> fmt::Display for OccupiedError<'a, K, V, A> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"failed to insert {:?}, key {:?} already exists with value {:?}",
self.value,
self.entry.key(),
self.entry.get(),
)
}
}

#[unstable(feature = "map_try_insert", issue = "82766")]
impl<'a, K: Debug, V: Debug, A: Allocator> Error for OccupiedError<'a, K, V, A> {}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, K, V, S, A: Allocator> IntoIterator for &'a HashMap<K, V, S, A> {
type Item = (&'a K, &'a V);
Expand Down Expand Up @@ -3010,7 +3000,7 @@ fn map_entry<'a, K: 'a, V: 'a, A: Allocator>(
raw: base::RustcEntry<'a, K, V, A>,
) -> Entry<'a, K, V, A> {
match raw {
base::RustcEntry::Occupied(base) => Entry::Occupied(OccupiedEntry { base }),
base::RustcEntry::Occupied(base, _) => Entry::Occupied(OccupiedEntry { base }),
base::RustcEntry::Vacant(base) => Entry::Vacant(VacantEntry { base }),
}
}
Expand Down
Loading