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
4 changes: 2 additions & 2 deletions library/Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -125,9 +125,9 @@ dependencies = [

[[package]]
name = "hashbrown"
version = "0.17.0"
version = "0.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51"
checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
dependencies = [
"foldhash",
"rustc-std-workspace-alloc",
Expand Down
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 @@ -107,6 +108,8 @@ pub struct OccupiedError<
> {
/// The entry in the map that was already occupied.
pub entry: OccupiedEntry<'a, K, V, A>,
/// The key which was not inserted, because the entry was already occupied.
pub key: K,
/// The value which was not inserted, because the entry was already occupied.
pub value: V,
}
Expand All @@ -116,33 +119,13 @@ impl<K: Debug + Ord, V: Debug, A: Allocator + Clone> Debug for OccupiedError<'_,
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>
Copy link
Copy Markdown
Member

@cuviper cuviper May 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, I suspect it was this path keeping that pub use alive when compiled in test mode.
(not sure why that wasn't just using the type directly like the Display above it...)

View changes since the review

{
}

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
2 changes: 1 addition & 1 deletion library/std/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ panic_unwind = { path = "../panic_unwind", optional = true }
panic_abort = { path = "../panic_abort" }
core = { path = "../core", public = true }
unwind = { path = "../unwind" }
hashbrown = { version = "0.17.0", default-features = false, features = [
hashbrown = { version = "0.17.1", default-features = false, features = [
'rustc-dep-of-std',
] }
std_detect = { path = "../std_detect", public = true }
Expand Down
36 changes: 13 additions & 23 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, RustcOccupiedError};

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_try_insert(key, value) {
Result::Ok(value) => Ok(value),
Result::Err(RustcOccupiedError { entry, key, value, .. }) => {
Err(OccupiedError { entry: OccupiedEntry { base: entry }, key, 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 @@ -2017,6 +2020,8 @@ pub struct OccupiedError<
> {
/// The entry in the map that was already occupied.
pub entry: OccupiedEntry<'a, K, V, A>,
/// The key which was not inserted, because the entry was already occupied.
pub key: K,
/// The value which was not inserted, because the entry was already occupied.
pub value: V,
}
Expand All @@ -2026,28 +2031,13 @@ 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
Loading