Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Alow Mutating Entry keys and iterator keys #335

Merged
merged 3 commits into from
Jul 31, 2024
Merged
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
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