diff --git a/src/map.rs b/src/map.rs index 82824c90..ab931a9a 100644 --- a/src/map.rs +++ b/src/map.rs @@ -18,6 +18,7 @@ pub use self::core::{Entry, IndexedEntry, OccupiedEntry, VacantEntry}; pub use self::iter::{ Drain, IntoIter, IntoKeys, IntoValues, Iter, IterMut, Keys, Splice, Values, ValuesMut, }; +pub use self::mutable::MutableEntryKey; pub use self::mutable::MutableKeys; pub use self::slice::Slice; diff --git a/src/map/core/entry.rs b/src/map/core/entry.rs index 6c310707..ab45ecc1 100644 --- a/src/map/core/entry.rs +++ b/src/map/core/entry.rs @@ -144,6 +144,10 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { &self.raw.bucket().key } + pub(crate) fn key_mut(&mut self) -> &mut K { + &mut self.raw.bucket_mut().key + } + /// Gets a reference to the entry's value in the map. pub fn get(&self) -> &V { &self.raw.bucket().value @@ -297,6 +301,10 @@ impl<'a, K, V> VacantEntry<'a, K, V> { &self.key } + pub(crate) fn key_mut(&mut self) -> &mut K { + &mut self.key + } + /// Takes ownership of the key, leaving the entry vacant. pub fn into_key(self) -> K { self.key @@ -373,6 +381,10 @@ impl<'a, K, V> IndexedEntry<'a, K, V> { &self.map.entries[self.index].key } + pub(crate) fn key_mut(&mut self) -> &mut K { + &mut self.map.entries[self.index].key + } + /// Gets a reference to the entry's value in the map. pub fn get(&self) -> &V { &self.map.entries[self.index].value diff --git a/src/map/mutable.rs b/src/map/mutable.rs index 7df32594..4aa22943 100644 --- a/src/map/mutable.rs +++ b/src/map/mutable.rs @@ -1,6 +1,8 @@ use core::hash::{BuildHasher, Hash}; -use super::{Bucket, Entries, Equivalent, IndexMap}; +use super::{ + Bucket, Entries, Entry, Equivalent, IndexMap, IndexedEntry, OccupiedEntry, VacantEntry, +}; /// Opt-in mutable access to [`IndexMap`] keys. /// @@ -80,8 +82,77 @@ where } } +/// Opt-in mutable access to [`Entry`] keys. +/// +/// These methods expose `&mut K`, mutable references to the key as it is stored +/// in the map. +/// You are allowed to modify the keys in the map **if the modification +/// does not change the key’s hash and equality**. +/// +/// If keys are modified erroneously, you can no longer look them up. +/// This is sound (memory safe) but a logical error hazard (just like +/// implementing `PartialEq`, `Eq`, or `Hash` incorrectly would be). +/// +/// `use` this trait to enable its methods for `Entry`. +/// +/// This trait is sealed and cannot be implemented for types outside this crate. +pub trait MutableEntryKey: private::Sealed { + type Key; + fn key_mut(&mut self) -> &mut Self::Key; +} + +/// Opt-in mutable access to [`Entry`] keys. +/// +/// See [`MutableEntryKey`] for more information. +impl MutableEntryKey for Entry<'_, K, V> { + type Key = K; + + /// Gets a mutable reference to the entry's key, either within the map if occupied, + /// or else the new key that was used to find the entry. + fn key_mut(&mut self) -> &mut Self::Key { + match self { + Entry::Occupied(e) => e.key_mut(), + Entry::Vacant(e) => e.key_mut(), + } + } +} + +/// Opt-in mutable access to [`OccupiedEntry`] keys. +/// +/// See [`MutableEntryKey`] for more information. +impl MutableEntryKey for OccupiedEntry<'_, K, V> { + type Key = K; + fn key_mut(&mut self) -> &mut Self::Key { + self.key_mut() + } +} + +/// Opt-in mutable access to [`VacantEntry`] keys. +/// +/// See [`MutableEntryKey`] for more information. +impl MutableEntryKey for VacantEntry<'_, K, V> { + type Key = K; + fn key_mut(&mut self) -> &mut Self::Key { + self.key_mut() + } +} + +/// Opt-in mutable access to [`IndexedEntry`] keys. +/// +/// See [`MutableEntryKey`] for more information. +impl MutableEntryKey for IndexedEntry<'_, K, V> { + type Key = K; + fn key_mut(&mut self) -> &mut Self::Key { + self.key_mut() + } +} + mod private { pub trait Sealed {} impl Sealed for super::IndexMap {} + impl Sealed for super::Entry<'_, K, V> {} + impl Sealed for super::OccupiedEntry<'_, K, V> {} + impl Sealed for super::VacantEntry<'_, K, V> {} + impl Sealed for super::IndexedEntry<'_, K, V> {} }