Skip to content

Commit

Permalink
Merge pull request #323 from cuviper/mutable
Browse files Browse the repository at this point in the history
Opt-in mutable access on IndexSet, release 2.2.6
  • Loading branch information
cuviper authored Mar 23, 2024
2 parents 184fe4b + 33c1a7c commit 3f0fffb
Show file tree
Hide file tree
Showing 11 changed files with 165 additions and 86 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.5"
version = "2.2.6"
documentation = "https://docs.rs/indexmap/"
repository = "https://github.com/indexmap-rs/indexmap"
license = "Apache-2.0 OR MIT"
Expand Down
4 changes: 4 additions & 0 deletions RELEASES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Releases

## 2.2.6

- Added trait `MutableValues` for opt-in mutable access to set values.

## 2.2.5

- Added optional `borsh` serialization support.
Expand Down
1 change: 0 additions & 1 deletion src/borsh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
use alloc::vec::Vec;
use core::hash::BuildHasher;
use core::hash::Hash;
use core::iter::ExactSizeIterator;
use core::mem::size_of;

use borsh::error::ERROR_ZST_FORBIDDEN;
Expand Down
3 changes: 1 addition & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
//! - The [`Equivalent`] trait, which offers more flexible equality definitions
//! between borrowed and owned versions of keys.
//! - The [`MutableKeys`][map::MutableKeys] trait, which gives opt-in mutable
//! access to hash map keys.
//! access to map keys, and [`MutableValues`][set::MutableValues] for sets.
//!
//! ### Feature Flags
//!
Expand Down Expand Up @@ -116,7 +116,6 @@ mod arbitrary;
mod macros;
#[cfg(feature = "borsh")]
mod borsh;
mod mutable_keys;
#[cfg(feature = "serde")]
mod serde;
mod util;
Expand Down
70 changes: 32 additions & 38 deletions src/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
mod core;
mod iter;
mod mutable;
mod slice;

#[cfg(feature = "serde")]
Expand All @@ -17,8 +18,8 @@ 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::MutableKeys;
pub use self::slice::Slice;
pub use crate::mutable_keys::MutableKeys;

#[cfg(feature = "rayon")]
pub use crate::rayon::map as rayon;
Expand Down Expand Up @@ -533,9 +534,9 @@ where
/// Return `true` if an equivalent to `key` exists in the map.
///
/// Computes in **O(1)** time (average).
pub fn contains_key<Q: ?Sized>(&self, key: &Q) -> bool
pub fn contains_key<Q>(&self, key: &Q) -> bool
where
Q: Hash + Equivalent<K>,
Q: ?Sized + Hash + Equivalent<K>,
{
self.get_index_of(key).is_some()
}
Expand All @@ -544,9 +545,9 @@ where
/// else `None`.
///
/// Computes in **O(1)** time (average).
pub fn get<Q: ?Sized>(&self, key: &Q) -> Option<&V>
pub fn get<Q>(&self, key: &Q) -> Option<&V>
where
Q: Hash + Equivalent<K>,
Q: ?Sized + Hash + Equivalent<K>,
{
if let Some(i) = self.get_index_of(key) {
let entry = &self.as_entries()[i];
Expand All @@ -560,9 +561,9 @@ where
/// if it is present, else `None`.
///
/// Computes in **O(1)** time (average).
pub fn get_key_value<Q: ?Sized>(&self, key: &Q) -> Option<(&K, &V)>
pub fn get_key_value<Q>(&self, key: &Q) -> Option<(&K, &V)>
where
Q: Hash + Equivalent<K>,
Q: ?Sized + Hash + Equivalent<K>,
{
if let Some(i) = self.get_index_of(key) {
let entry = &self.as_entries()[i];
Expand All @@ -573,9 +574,9 @@ where
}

/// Return item index, key and value
pub fn get_full<Q: ?Sized>(&self, key: &Q) -> Option<(usize, &K, &V)>
pub fn get_full<Q>(&self, key: &Q) -> Option<(usize, &K, &V)>
where
Q: Hash + Equivalent<K>,
Q: ?Sized + Hash + Equivalent<K>,
{
if let Some(i) = self.get_index_of(key) {
let entry = &self.as_entries()[i];
Expand All @@ -588,9 +589,9 @@ where
/// Return item index, if it exists in the map
///
/// Computes in **O(1)** time (average).
pub fn get_index_of<Q: ?Sized>(&self, key: &Q) -> Option<usize>
pub fn get_index_of<Q>(&self, key: &Q) -> Option<usize>
where
Q: Hash + Equivalent<K>,
Q: ?Sized + Hash + Equivalent<K>,
{
match self.as_entries() {
[] => None,
Expand All @@ -602,9 +603,9 @@ where
}
}

pub fn get_mut<Q: ?Sized>(&mut self, key: &Q) -> Option<&mut V>
pub fn get_mut<Q>(&mut self, key: &Q) -> Option<&mut V>
where
Q: Hash + Equivalent<K>,
Q: ?Sized + Hash + Equivalent<K>,
{
if let Some(i) = self.get_index_of(key) {
let entry = &mut self.as_entries_mut()[i];
Expand All @@ -614,9 +615,9 @@ where
}
}

pub fn get_full_mut<Q: ?Sized>(&mut self, key: &Q) -> Option<(usize, &K, &mut V)>
pub fn get_full_mut<Q>(&mut self, key: &Q) -> Option<(usize, &K, &mut V)>
where
Q: Hash + Equivalent<K>,
Q: ?Sized + Hash + Equivalent<K>,
{
if let Some(i) = self.get_index_of(key) {
let entry = &mut self.as_entries_mut()[i];
Expand All @@ -635,9 +636,9 @@ where
/// [`.shift_remove(key)`][Self::shift_remove] instead.
#[deprecated(note = "`remove` disrupts the map order -- \
use `swap_remove` or `shift_remove` for explicit behavior.")]
pub fn remove<Q: ?Sized>(&mut self, key: &Q) -> Option<V>
pub fn remove<Q>(&mut self, key: &Q) -> Option<V>
where
Q: Hash + Equivalent<K>,
Q: ?Sized + Hash + Equivalent<K>,
{
self.swap_remove(key)
}
Expand All @@ -650,9 +651,9 @@ where
/// use [`.shift_remove_entry(key)`][Self::shift_remove_entry] instead.
#[deprecated(note = "`remove_entry` disrupts the map order -- \
use `swap_remove_entry` or `shift_remove_entry` for explicit behavior.")]
pub fn remove_entry<Q: ?Sized>(&mut self, key: &Q) -> Option<(K, V)>
pub fn remove_entry<Q>(&mut self, key: &Q) -> Option<(K, V)>
where
Q: Hash + Equivalent<K>,
Q: ?Sized + Hash + Equivalent<K>,
{
self.swap_remove_entry(key)
}
Expand All @@ -667,9 +668,9 @@ where
/// Return `None` if `key` is not in map.
///
/// Computes in **O(1)** time (average).
pub fn swap_remove<Q: ?Sized>(&mut self, key: &Q) -> Option<V>
pub fn swap_remove<Q>(&mut self, key: &Q) -> Option<V>
where
Q: Hash + Equivalent<K>,
Q: ?Sized + Hash + Equivalent<K>,
{
self.swap_remove_full(key).map(third)
}
Expand All @@ -683,9 +684,9 @@ where
/// Return `None` if `key` is not in map.
///
/// Computes in **O(1)** time (average).
pub fn swap_remove_entry<Q: ?Sized>(&mut self, key: &Q) -> Option<(K, V)>
pub fn swap_remove_entry<Q>(&mut self, key: &Q) -> Option<(K, V)>
where
Q: Hash + Equivalent<K>,
Q: ?Sized + Hash + Equivalent<K>,
{
match self.swap_remove_full(key) {
Some((_, key, value)) => Some((key, value)),
Expand All @@ -703,9 +704,9 @@ where
/// Return `None` if `key` is not in map.
///
/// Computes in **O(1)** time (average).
pub fn swap_remove_full<Q: ?Sized>(&mut self, key: &Q) -> Option<(usize, K, V)>
pub fn swap_remove_full<Q>(&mut self, key: &Q) -> Option<(usize, K, V)>
where
Q: Hash + Equivalent<K>,
Q: ?Sized + Hash + Equivalent<K>,
{
match self.as_entries() {
[x] if key.equivalent(&x.key) => {
Expand All @@ -730,9 +731,9 @@ where
/// Return `None` if `key` is not in map.
///
/// Computes in **O(n)** time (average).
pub fn shift_remove<Q: ?Sized>(&mut self, key: &Q) -> Option<V>
pub fn shift_remove<Q>(&mut self, key: &Q) -> Option<V>
where
Q: Hash + Equivalent<K>,
Q: ?Sized + Hash + Equivalent<K>,
{
self.shift_remove_full(key).map(third)
}
Expand All @@ -746,9 +747,9 @@ where
/// Return `None` if `key` is not in map.
///
/// Computes in **O(n)** time (average).
pub fn shift_remove_entry<Q: ?Sized>(&mut self, key: &Q) -> Option<(K, V)>
pub fn shift_remove_entry<Q>(&mut self, key: &Q) -> Option<(K, V)>
where
Q: Hash + Equivalent<K>,
Q: ?Sized + Hash + Equivalent<K>,
{
match self.shift_remove_full(key) {
Some((_, key, value)) => Some((key, value)),
Expand All @@ -766,9 +767,9 @@ where
/// Return `None` if `key` is not in map.
///
/// Computes in **O(n)** time (average).
pub fn shift_remove_full<Q: ?Sized>(&mut self, key: &Q) -> Option<(usize, K, V)>
pub fn shift_remove_full<Q>(&mut self, key: &Q) -> Option<(usize, K, V)>
where
Q: Hash + Equivalent<K>,
Q: ?Sized + Hash + Equivalent<K>,
{
match self.as_entries() {
[x] if key.equivalent(&x.key) => {
Expand Down Expand Up @@ -808,13 +809,6 @@ impl<K, V, S> IndexMap<K, V, S> {
self.core.retain_in_order(move |k, v| keep(k, v));
}

pub(crate) fn retain_mut<F>(&mut self, keep: F)
where
F: FnMut(&mut K, &mut V) -> bool,
{
self.core.retain_in_order(keep);
}

/// Sort the map’s key-value pairs by the default ordering of the keys.
///
/// This is a stable sort -- but equivalent keys should not normally coexist in
Expand Down
16 changes: 8 additions & 8 deletions src/map/core/raw_entry_v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,18 +198,18 @@ impl<K, V, S> fmt::Debug for RawEntryBuilder<'_, K, V, S> {

impl<'a, K, V, S> RawEntryBuilder<'a, K, V, S> {
/// Access an entry by key.
pub fn from_key<Q: ?Sized>(self, key: &Q) -> Option<(&'a K, &'a V)>
pub fn from_key<Q>(self, key: &Q) -> Option<(&'a K, &'a V)>
where
S: BuildHasher,
Q: Hash + Equivalent<K>,
Q: ?Sized + Hash + Equivalent<K>,
{
self.map.get_key_value(key)
}

/// Access an entry by a key and its hash.
pub fn from_key_hashed_nocheck<Q: ?Sized>(self, hash: u64, key: &Q) -> Option<(&'a K, &'a V)>
pub fn from_key_hashed_nocheck<Q>(self, hash: u64, key: &Q) -> Option<(&'a K, &'a V)>
where
Q: Equivalent<K>,
Q: ?Sized + Equivalent<K>,
{
let hash = HashValue(hash as usize);
let i = self.map.core.get_index_of(hash, key)?;
Expand Down Expand Up @@ -265,19 +265,19 @@ impl<K, V, S> fmt::Debug for RawEntryBuilderMut<'_, K, V, S> {

impl<'a, K, V, S> RawEntryBuilderMut<'a, K, V, S> {
/// Access an entry by key.
pub fn from_key<Q: ?Sized>(self, key: &Q) -> RawEntryMut<'a, K, V, S>
pub fn from_key<Q>(self, key: &Q) -> RawEntryMut<'a, K, V, S>
where
S: BuildHasher,
Q: Hash + Equivalent<K>,
Q: ?Sized + Hash + Equivalent<K>,
{
let hash = self.map.hash(key);
self.from_key_hashed_nocheck(hash.get(), key)
}

/// Access an entry by a key and its hash.
pub fn from_key_hashed_nocheck<Q: ?Sized>(self, hash: u64, key: &Q) -> RawEntryMut<'a, K, V, S>
pub fn from_key_hashed_nocheck<Q>(self, hash: u64, key: &Q) -> RawEntryMut<'a, K, V, S>
where
Q: Equivalent<K>,
Q: ?Sized + Equivalent<K>,
{
self.from_hash(hash, |k| Q::equivalent(key, k))
}
Expand Down
17 changes: 7 additions & 10 deletions src/mutable_keys.rs → src/map/mutable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use super::{Bucket, Entries, Equivalent, IndexMap};
///
/// 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 hashmap **if the modification
/// 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.
Expand All @@ -23,12 +23,9 @@ pub trait MutableKeys: private::Sealed {
/// Return item index, mutable reference to key and value
///
/// Computes in **O(1)** time (average).
fn get_full_mut2<Q: ?Sized>(
&mut self,
key: &Q,
) -> Option<(usize, &mut Self::Key, &mut Self::Value)>
fn get_full_mut2<Q>(&mut self, key: &Q) -> Option<(usize, &mut Self::Key, &mut Self::Value)>
where
Q: Hash + Equivalent<Self::Key>;
Q: ?Sized + Hash + Equivalent<Self::Key>;

/// Return mutable reference to key and value at an index.
///
Expand All @@ -49,7 +46,7 @@ pub trait MutableKeys: private::Sealed {
F: FnMut(&mut Self::Key, &mut Self::Value) -> bool;
}

/// Opt-in mutable access to keys.
/// Opt-in mutable access to [`IndexMap`] keys.
///
/// See [`MutableKeys`] for more information.
impl<K, V, S> MutableKeys for IndexMap<K, V, S>
Expand All @@ -59,9 +56,9 @@ where
type Key = K;
type Value = V;

fn get_full_mut2<Q: ?Sized>(&mut self, key: &Q) -> Option<(usize, &mut K, &mut V)>
fn get_full_mut2<Q>(&mut self, key: &Q) -> Option<(usize, &mut K, &mut V)>
where
Q: Hash + Equivalent<K>,
Q: ?Sized + Hash + Equivalent<K>,
{
if let Some(i) = self.get_index_of(key) {
let entry = &mut self.as_entries_mut()[i];
Expand All @@ -79,7 +76,7 @@ where
where
F: FnMut(&mut K, &mut V) -> bool,
{
self.retain_mut(keep)
self.core.retain_in_order(keep);
}
}

Expand Down
1 change: 0 additions & 1 deletion src/map/slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,6 @@ impl_index!(
#[cfg(test)]
mod tests {
use super::*;
use alloc::vec::Vec;

#[test]
fn slice_index() {
Expand Down
Loading

0 comments on commit 3f0fffb

Please sign in to comment.