Skip to content

Commit

Permalink
feat(map): Add MutableEntryKey
Browse files Browse the repository at this point in the history
I added `pub(crate) fn key_mut` to the different `Entry` types to limit
how much of their internals get exposed (as otherwise I'd have had to
make their fields `pub(crate)`.
  • Loading branch information
epage committed Jul 28, 2024
1 parent 7f7d39f commit 65c3c46
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 1 deletion.
1 change: 1 addition & 0 deletions src/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
12 changes: 12 additions & 0 deletions src/map/core/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
73 changes: 72 additions & 1 deletion src/map/mutable.rs
Original file line number Diff line number Diff line change
@@ -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.
///
Expand Down Expand Up @@ -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<K, V> 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<K, V> 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<K, V> 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<K, V> 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<K, V, S> Sealed for super::IndexMap<K, V, S> {}
impl<K, V> Sealed for super::Entry<'_, K, V> {}
impl<K, V> Sealed for super::OccupiedEntry<'_, K, V> {}
impl<K, V> Sealed for super::VacantEntry<'_, K, V> {}
impl<K, V> Sealed for super::IndexedEntry<'_, K, V> {}
}

0 comments on commit 65c3c46

Please sign in to comment.