Skip to content

Commit

Permalink
Merge pull request #335 from epage/mut
Browse files Browse the repository at this point in the history
Alow Mutating Entry keys and iterator keys
  • Loading branch information
cuviper authored Jul 31, 2024
2 parents 7f7d39f + 39f7cc0 commit 22c0b4e
Show file tree
Hide file tree
Showing 7 changed files with 163 additions and 3 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "indexmap"
edition = "2021"
version = "2.2.6"
version = "2.3.0"
documentation = "https://docs.rs/indexmap/"
repository = "https://github.com/indexmap-rs/indexmap"
license = "Apache-2.0 OR MIT"
Expand Down
6 changes: 6 additions & 0 deletions RELEASES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Releases

## 2.3.0

- Added trait `MutableEntryKey` for opt-in mutable access to map entry keys.
- Added method `MutableKeys::iter_mut2` for opt-in mutable iteration of map
keys and values.

## 2.2.6

- Added trait `MutableValues` for opt-in mutable access to set values.
Expand Down
3 changes: 2 additions & 1 deletion src/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ mod tests;
pub use self::core::raw_entry_v1::{self, RawEntryApiV1};
pub use self::core::{Entry, IndexedEntry, OccupiedEntry, VacantEntry};
pub use self::iter::{
Drain, IntoIter, IntoKeys, IntoValues, Iter, IterMut, Keys, Splice, Values, ValuesMut,
Drain, IntoIter, IntoKeys, IntoValues, Iter, IterMut, IterMut2, 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
61 changes: 61 additions & 0 deletions src/map/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,67 @@ impl<K, V> Default for IterMut<'_, K, V> {
}
}

/// A mutable iterator over the entries of an [`IndexMap`].
///
/// This `struct` is created by the [`MutableKeys::iter_mut2`][super::MutableKeys::iter_mut2] method.
/// See its documentation for more.
pub struct IterMut2<'a, K, V> {
iter: slice::IterMut<'a, Bucket<K, V>>,
}

impl<'a, K, V> IterMut2<'a, K, V> {
pub(super) fn new(entries: &'a mut [Bucket<K, V>]) -> Self {
Self {
iter: entries.iter_mut(),
}
}

/// Returns a slice of the remaining entries in the iterator.
pub fn as_slice(&self) -> &Slice<K, V> {
Slice::from_slice(self.iter.as_slice())
}

/// Returns a mutable slice of the remaining entries in the iterator.
///
/// To avoid creating `&mut` references that alias, this is forced to consume the iterator.
pub fn into_slice(self) -> &'a mut Slice<K, V> {
Slice::from_mut_slice(self.iter.into_slice())
}
}

impl<'a, K, V> Iterator for IterMut2<'a, K, V> {
type Item = (&'a mut K, &'a mut V);

iterator_methods!(Bucket::muts);
}

impl<K, V> DoubleEndedIterator for IterMut2<'_, K, V> {
double_ended_iterator_methods!(Bucket::muts);
}

impl<K, V> ExactSizeIterator for IterMut2<'_, K, V> {
fn len(&self) -> usize {
self.iter.len()
}
}

impl<K, V> FusedIterator for IterMut2<'_, K, V> {}

impl<K: fmt::Debug, V: fmt::Debug> fmt::Debug for IterMut2<'_, K, V> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let iter = self.iter.as_slice().iter().map(Bucket::refs);
f.debug_list().entries(iter).finish()
}
}

impl<K, V> Default for IterMut2<'_, K, V> {
fn default() -> Self {
Self {
iter: [].iter_mut(),
}
}
}

/// An owning iterator over the entries of an [`IndexMap`].
///
/// This `struct` is created by the [`IndexMap::into_iter`] method
Expand Down
81 changes: 80 additions & 1 deletion src/map/mutable.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use core::hash::{BuildHasher, Hash};

use super::{Bucket, Entries, Equivalent, IndexMap};
use super::{
Bucket, Entries, Entry, Equivalent, IndexMap, IndexedEntry, IterMut2, OccupiedEntry,
VacantEntry,
};

/// Opt-in mutable access to [`IndexMap`] keys.
///
Expand Down Expand Up @@ -34,6 +37,9 @@ pub trait MutableKeys: private::Sealed {
/// Computes in **O(1)** time.
fn get_index_mut2(&mut self, index: usize) -> Option<(&mut Self::Key, &mut Self::Value)>;

/// Return an iterator over the key-value pairs of the map, in their order
fn iter_mut2(&mut self) -> IterMut2<'_, Self::Key, Self::Value>;

/// Scan through each key-value pair in the map and keep those where the
/// closure `keep` returns `true`.
///
Expand Down Expand Up @@ -72,6 +78,10 @@ where
self.as_entries_mut().get_mut(index).map(Bucket::muts)
}

fn iter_mut2(&mut self) -> IterMut2<'_, Self::Key, Self::Value> {
IterMut2::new(self.as_entries_mut())
}

fn retain2<F>(&mut self, keep: F)
where
F: FnMut(&mut K, &mut V) -> bool,
Expand All @@ -80,8 +90,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> {}
}
1 change: 1 addition & 0 deletions src/map/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,7 @@ fn iter_default() {
}
assert_default::<Iter<'static, K, V>>();
assert_default::<IterMut<'static, K, V>>();
assert_default::<IterMut2<'static, K, V>>();
assert_default::<IntoIter<K, V>>();
assert_default::<Keys<'static, K, V>>();
assert_default::<IntoKeys<K, V>>();
Expand Down

0 comments on commit 22c0b4e

Please sign in to comment.