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

Opt-in mutable access on IndexSet, release 2.2.6 #323

Merged
merged 4 commits into from
Mar 23, 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.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