diff --git a/Cargo.toml b/Cargo.toml index eaef973..97e5c89 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "ordermap" edition = "2021" -version = "0.5.6" +version = "0.5.7" documentation = "https://docs.rs/ordermap/" repository = "https://github.com/indexmap-rs/ordermap" license = "Apache-2.0 OR MIT" @@ -14,12 +14,12 @@ rust-version = "1.63" bench = false [dependencies] -indexmap = { version = "2.8.0", default-features = false } +indexmap = { version = "2.9.0", default-features = false } arbitrary = { version = "1.0", optional = true, default-features = false } quickcheck = { version = "1.0", optional = true, default-features = false } serde = { version = "1.0", optional = true, default-features = false } -borsh = { version = "1.2", optional = true, default-features = false } +borsh = { version = "1.5.6", optional = true, default-features = false } rayon = { version = "1.9", optional = true } [dev-dependencies] @@ -38,7 +38,7 @@ arbitrary = ["dep:arbitrary", "indexmap/arbitrary"] quickcheck = ["dep:quickcheck", "indexmap/quickcheck"] rayon = ["dep:rayon", "indexmap/rayon"] serde = ["dep:serde", "indexmap/serde"] -borsh = ["dep:borsh", "indexmap/borsh"] +borsh = ["dep:borsh", "borsh/indexmap"] [profile.bench] debug = true diff --git a/RELEASES.md b/RELEASES.md index 7738f26..54454ae 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,5 +1,13 @@ # Releases +## 0.5.7 (2025-04-04) + +- Added a `get_disjoint_mut` method to `OrderMap`, matching Rust 1.86's + `HashMap` method. +- Added a `get_disjoint_indices_mut` method to `OrderMap`, matching Rust 1.86's + `get_disjoint_mut` method on slices. +- Updated the `indexmap` dependency to version 2.9.0. + ## 0.5.6 (2025-03-10) - Added `ordermap_with_default!` and `orderset_with_default!` to be used with diff --git a/src/lib.rs b/src/lib.rs index f9bdcbf..e50038c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -116,4 +116,4 @@ pub mod set; pub use crate::map::OrderMap; pub use crate::set::OrderSet; -pub use indexmap::{Equivalent, TryReserveError}; +pub use indexmap::{Equivalent, GetDisjointMutError, TryReserveError}; diff --git a/src/macros.rs b/src/macros.rs index bfe43fd..9cc57fc 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -1,5 +1,5 @@ /// Create an [`OrderMap`][crate::OrderMap] from a list of key-value pairs -/// and a `BuildHasherDefault`-wrapped custom hasher. +/// and a [`BuildHasherDefault`][core::hash::BuildHasherDefault]-wrapped custom hasher. /// /// ## Example /// @@ -73,7 +73,7 @@ macro_rules! ordermap { } /// Create an [`OrderSet`][crate::OrderSet] from a list of values -/// and a `BuildHasherDefault`-wrapped custom hasher. +/// and a [`BuildHasherDefault`][core::hash::BuildHasherDefault]-wrapped custom hasher. /// /// ## Example /// diff --git a/src/map.rs b/src/map.rs index afa5cac..21c61d2 100644 --- a/src/map.rs +++ b/src/map.rs @@ -49,7 +49,7 @@ use alloc::vec::Vec; #[cfg(feature = "std")] use std::collections::hash_map::RandomState; -use crate::{Equivalent, TryReserveError}; +use crate::{Equivalent, GetDisjointMutError, TryReserveError}; /// A hash table where the iteration order of the key-value pairs is independent /// of the hash values of the keys. @@ -677,6 +677,21 @@ where self.inner.get_full_mut(key) } + /// Return the values for `N` keys. If any key is duplicated, this function will panic. + /// + /// # Examples + /// + /// ``` + /// let mut map = ordermap::OrderMap::from([(1, 'a'), (3, 'b'), (2, 'c')]); + /// assert_eq!(map.get_disjoint_mut([&2, &1]), [Some(&mut 'c'), Some(&mut 'a')]); + /// ``` + pub fn get_disjoint_mut(&mut self, keys: [&Q; N]) -> [Option<&mut V>; N] + where + Q: ?Sized + Hash + Equivalent, + { + self.inner.get_disjoint_mut(keys) + } + /// Remove the key-value pair equivalent to `key` and return its value. /// /// **NOTE:** This is equivalent to [`IndexMap::shift_remove`], and @@ -1011,6 +1026,23 @@ impl OrderMap { self.inner.get_index_entry(index).map(IndexedEntry::new) } + /// Get an array of `N` key-value pairs by `N` indices + /// + /// Valid indices are *0 <= index < self.len()* and each index needs to be unique. + /// + /// # Examples + /// + /// ``` + /// let mut map = ordermap::OrderMap::from([(1, 'a'), (3, 'b'), (2, 'c')]); + /// assert_eq!(map.get_disjoint_indices_mut([2, 0]), Ok([(&2, &mut 'c'), (&1, &mut 'a')])); + /// ``` + pub fn get_disjoint_indices_mut( + &mut self, + indices: [usize; N], + ) -> Result<[(&K, &mut V); N], GetDisjointMutError> { + self.as_mut_slice().get_disjoint_mut(indices) + } + /// Returns a slice of key-value pairs in the given range of indices. /// /// Valid indices are `0 <= index < self.len()`. diff --git a/src/map/tests.rs b/src/map/tests.rs index 5578130..08c1c89 100644 --- a/src/map/tests.rs +++ b/src/map/tests.rs @@ -548,7 +548,7 @@ fn drain_range() { 20..30, // sweep everything ] { let mut vec = Vec::from_iter(0..100); - let mut map: IndexMap = (0..100).map(|i| (i, ())).collect(); + let mut map: OrderMap = (0..100).map(|i| (i, ())).collect(); drop(vec.drain(range.clone())); drop(map.drain(range)); assert!(vec.iter().eq(map.keys())); @@ -810,3 +810,181 @@ fn test_partition_point() { assert_eq!(b.partition_point(|_, &x| x < 7), 4); assert_eq!(b.partition_point(|_, &x| x < 8), 5); } + +#[test] +fn disjoint_mut_empty_map() { + let mut map: OrderMap = OrderMap::default(); + assert_eq!( + map.get_disjoint_mut([&0, &1, &2, &3]), + [None, None, None, None] + ); +} + +#[test] +fn disjoint_mut_empty_param() { + let mut map: OrderMap = OrderMap::default(); + map.insert(1, 10); + assert_eq!(map.get_disjoint_mut([] as [&u32; 0]), []); +} + +#[test] +fn disjoint_mut_single_fail() { + let mut map: OrderMap = OrderMap::default(); + map.insert(1, 10); + assert_eq!(map.get_disjoint_mut([&0]), [None]); +} + +#[test] +fn disjoint_mut_single_success() { + let mut map: OrderMap = OrderMap::default(); + map.insert(1, 10); + assert_eq!(map.get_disjoint_mut([&1]), [Some(&mut 10)]); +} + +#[test] +fn disjoint_mut_multi_success() { + let mut map: OrderMap = OrderMap::default(); + map.insert(1, 100); + map.insert(2, 200); + map.insert(3, 300); + map.insert(4, 400); + assert_eq!( + map.get_disjoint_mut([&1, &2]), + [Some(&mut 100), Some(&mut 200)] + ); + assert_eq!( + map.get_disjoint_mut([&1, &3]), + [Some(&mut 100), Some(&mut 300)] + ); + assert_eq!( + map.get_disjoint_mut([&3, &1, &4, &2]), + [ + Some(&mut 300), + Some(&mut 100), + Some(&mut 400), + Some(&mut 200) + ] + ); +} + +#[test] +fn disjoint_mut_multi_success_unsized_key() { + let mut map: OrderMap<&'static str, u32> = OrderMap::default(); + map.insert("1", 100); + map.insert("2", 200); + map.insert("3", 300); + map.insert("4", 400); + + assert_eq!( + map.get_disjoint_mut(["1", "2"]), + [Some(&mut 100), Some(&mut 200)] + ); + assert_eq!( + map.get_disjoint_mut(["1", "3"]), + [Some(&mut 100), Some(&mut 300)] + ); + assert_eq!( + map.get_disjoint_mut(["3", "1", "4", "2"]), + [ + Some(&mut 300), + Some(&mut 100), + Some(&mut 400), + Some(&mut 200) + ] + ); +} + +#[test] +fn disjoint_mut_multi_success_borrow_key() { + let mut map: OrderMap = OrderMap::default(); + map.insert("1".into(), 100); + map.insert("2".into(), 200); + map.insert("3".into(), 300); + map.insert("4".into(), 400); + + assert_eq!( + map.get_disjoint_mut(["1", "2"]), + [Some(&mut 100), Some(&mut 200)] + ); + assert_eq!( + map.get_disjoint_mut(["1", "3"]), + [Some(&mut 100), Some(&mut 300)] + ); + assert_eq!( + map.get_disjoint_mut(["3", "1", "4", "2"]), + [ + Some(&mut 300), + Some(&mut 100), + Some(&mut 400), + Some(&mut 200) + ] + ); +} + +#[test] +fn disjoint_mut_multi_fail_missing() { + let mut map: OrderMap = OrderMap::default(); + map.insert(1, 100); + map.insert(2, 200); + map.insert(3, 300); + map.insert(4, 400); + + assert_eq!(map.get_disjoint_mut([&1, &5]), [Some(&mut 100), None]); + assert_eq!(map.get_disjoint_mut([&5, &6]), [None, None]); + assert_eq!( + map.get_disjoint_mut([&1, &5, &4]), + [Some(&mut 100), None, Some(&mut 400)] + ); +} + +#[test] +#[should_panic] +fn disjoint_mut_multi_fail_duplicate_panic() { + let mut map: OrderMap = OrderMap::default(); + map.insert(1, 100); + map.get_disjoint_mut([&1, &2, &1]); +} + +#[test] +fn disjoint_indices_mut_fail_oob() { + let mut map: OrderMap = OrderMap::default(); + map.insert(1, 10); + map.insert(321, 20); + assert_eq!( + map.get_disjoint_indices_mut([1, 3]), + Err(crate::GetDisjointMutError::IndexOutOfBounds) + ); +} + +#[test] +fn disjoint_indices_mut_empty() { + let mut map: OrderMap = OrderMap::default(); + map.insert(1, 10); + map.insert(321, 20); + assert_eq!(map.get_disjoint_indices_mut([]), Ok([])); +} + +#[test] +fn disjoint_indices_mut_success() { + let mut map: OrderMap = OrderMap::default(); + map.insert(1, 10); + map.insert(321, 20); + assert_eq!(map.get_disjoint_indices_mut([0]), Ok([(&1, &mut 10)])); + + assert_eq!(map.get_disjoint_indices_mut([1]), Ok([(&321, &mut 20)])); + assert_eq!( + map.get_disjoint_indices_mut([0, 1]), + Ok([(&1, &mut 10), (&321, &mut 20)]) + ); +} + +#[test] +fn disjoint_indices_mut_fail_duplicate() { + let mut map: OrderMap = OrderMap::default(); + map.insert(1, 10); + map.insert(321, 20); + assert_eq!( + map.get_disjoint_indices_mut([1, 0, 1]), + Err(crate::GetDisjointMutError::OverlappingIndices) + ); +}