From 2e985820519205c43dc40f50895a6d44ac13195c Mon Sep 17 00:00:00 2001 From: Yegor Vaskonyan Date: Tue, 16 Jul 2024 16:15:31 +0200 Subject: [PATCH 1/3] feat: add `get_index_of` to `index_map::FrozenIndexMap` and `index_set::FrozenIndexSet` --- src/index_map.rs | 28 ++++++++++++++++++++++++++++ src/index_set.rs | 28 ++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/src/index_map.rs b/src/index_map.rs index e5ccb69..4996eb2 100644 --- a/src/index_map.rs +++ b/src/index_map.rs @@ -8,6 +8,8 @@ use std::ops::Index; use indexmap::IndexMap; use stable_deref_trait::StableDeref; +pub use indexmap::Equivalent; + /// Append-only version of `indexmap::IndexMap` where /// insertion does not require mutable access pub struct FrozenIndexMap { @@ -127,6 +129,32 @@ impl FrozenIndexMap { ret } + /// Returns the index corresponding to the key + /// + /// # Examples + /// + /// ``` + /// use elsa::FrozenIndexMap; + /// + /// let map = FrozenIndexMap::new(); + /// map.insert(1, Box::new("a")); + /// assert_eq!(map.get_index_of(&1), Some(0)); + /// assert_eq!(map.get_index_of(&2), None); + /// ``` + pub fn get_index_of(&self, k: &Q) -> Option + where + Q: ?Sized + Hash + Equivalent, + { + assert!(!self.in_use.get()); + self.in_use.set(true); + let ret = unsafe { + let map = self.map.get(); + (*map).get_index_of(k) + }; + self.in_use.set(false); + ret + } + /// Returns a reference to the key-value mapping corresponding to an index. /// /// The key may be any borrowed form of the map's key type, but diff --git a/src/index_set.rs b/src/index_set.rs index 152ef5e..0186007 100644 --- a/src/index_set.rs +++ b/src/index_set.rs @@ -8,6 +8,8 @@ use std::ops::Index; use indexmap::IndexSet; use stable_deref_trait::StableDeref; +use crate::index_map::Equivalent; + /// Append-only version of `indexmap::IndexSet` where /// insertion does not require mutable access pub struct FrozenIndexSet { @@ -142,6 +144,32 @@ impl FrozenIndexSet { ret } + /// Returns the index corresponding to the value if present in the set + /// + /// # Examples + /// + /// ``` + /// use elsa::FrozenIndexSet; + /// + /// let set = FrozenIndexSet::new(); + /// set.insert(Box::new("a")); + /// assert_eq!(set.get_index_of(&Box::new("a")), Some(0)); + /// assert_eq!(set.get_index_of(&Box::new("b")), None); + /// ``` + pub fn get_index_of(&self, k: &Q) -> Option + where + Q: ?Sized + Hash + Equivalent, + { + assert!(!self.in_use.get()); + self.in_use.set(true); + let ret = unsafe { + let map = self.set.get(); + (*map).get_index_of(k) + }; + self.in_use.set(false); + ret + } + /// Returns a reference to the value passed as argument if present in the set, /// along with its index /// From 07bec537418d95ef352ae6a2fe728872e697567d Mon Sep 17 00:00:00 2001 From: Yegor Vaskonyan Date: Tue, 16 Jul 2024 16:27:57 +0200 Subject: [PATCH 2/3] feat: add `get_full` to `index_map::FrozenIndexMap` refactor: fix variable names in `index_map.rs` and `index_set.rs` --- src/index_map.rs | 29 ++++++++++++++++++++++++++++- src/index_set.rs | 10 +++++----- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/src/index_map.rs b/src/index_map.rs index 4996eb2..c432fad 100644 --- a/src/index_map.rs +++ b/src/index_map.rs @@ -134,7 +134,7 @@ impl FrozenIndexMap { /// # Examples /// /// ``` - /// use elsa::FrozenIndexMap; + /// use elsa::index_map::FrozenIndexMap; /// /// let map = FrozenIndexMap::new(); /// map.insert(1, Box::new("a")); @@ -186,6 +186,33 @@ impl FrozenIndexMap { ret } + /// Returns a reference to the key, along with its index and a reference to its value + /// + /// # Examples + /// + /// ``` + /// use elsa::index_map::FrozenIndexMap; + /// + /// let map = FrozenIndexMap::new(); + /// map.insert("1", Box::new("a")); + /// assert_eq!(map.get_full("1"), Some((0, "1", &"a"))); + /// assert_eq!(map.get_full("2"), None); + /// ``` + pub fn get_full(&self, k: &Q) -> Option<(usize, &K::Target, &V::Target)> + where + Q: ?Sized + Hash + Equivalent, + K: StableDeref, + { + assert!(!self.in_use.get()); + self.in_use.set(true); + let ret = unsafe { + let map = self.map.get(); + (*map).get_full(k).map(|(i, k, v)| (i, &**k, &**v)) + }; + self.in_use.set(false); + ret + } + /// Applies a function to the owner of the value corresponding to the key (if any). /// /// The key may be any borrowed form of the map's key type, but diff --git a/src/index_set.rs b/src/index_set.rs index 0186007..1645b90 100644 --- a/src/index_set.rs +++ b/src/index_set.rs @@ -74,9 +74,9 @@ impl FrozenIndexSet { /// # Example /// ``` /// use elsa::index_set::FrozenIndexSet; - /// let map = FrozenIndexSet::new(); - /// assert_eq!(map.insert_full(Box::new("a")), (0, &"a")); - /// assert_eq!(map.insert_full(Box::new("b")), (1, &"b")); + /// let set = FrozenIndexSet::new(); + /// assert_eq!(set.insert_full(Box::new("a")), (0, &"a")); + /// assert_eq!(set.insert_full(Box::new("b")), (1, &"b")); /// ``` pub fn insert_full(&self, value: T) -> (usize, &T::Target) { assert!(!self.in_use.get()); @@ -163,8 +163,8 @@ impl FrozenIndexSet { assert!(!self.in_use.get()); self.in_use.set(true); let ret = unsafe { - let map = self.set.get(); - (*map).get_index_of(k) + let set = self.set.get(); + (*set).get_index_of(k) }; self.in_use.set(false); ret From 1ae1448cb56865075e56b0a2b95f272b8adb946d Mon Sep 17 00:00:00 2001 From: Yegor Vaskonyan Date: Tue, 16 Jul 2024 17:04:49 +0200 Subject: [PATCH 3/3] feat: use and reexport `indexmap::Equivalent` trait Allow get_ methods of `index_map::FrozenIndexMap` and `index_set::FrozenIndexSet` to accept values that implement `Equivalent` or `Equivalent` as keys. --- src/index_map.rs | 49 +++++++++++++++++++----------------------------- src/index_set.rs | 22 ++++++++++++++-------- 2 files changed, 33 insertions(+), 38 deletions(-) diff --git a/src/index_map.rs b/src/index_map.rs index c432fad..406d094 100644 --- a/src/index_map.rs +++ b/src/index_map.rs @@ -1,4 +1,3 @@ -use std::borrow::Borrow; use std::cell::{Cell, UnsafeCell}; use std::collections::hash_map::RandomState; use std::hash::{BuildHasher, Hash}; @@ -43,10 +42,6 @@ impl FrozenIndexMap { /// /// Existing values are never overwritten. /// - /// The key may be any borrowed form of the map's key type, but - /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for - /// the key type. - /// /// # Example /// ``` /// use elsa::index_map::FrozenIndexMap; @@ -74,10 +69,6 @@ impl FrozenIndexMap { /// /// Existing values are never overwritten. /// - /// The key may be any borrowed form of the map's key type, but - /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for - /// the key type. - /// /// # Example /// ``` /// use elsa::index_map::FrozenIndexMap; @@ -99,10 +90,9 @@ impl FrozenIndexMap { } /// Returns a reference to the value corresponding to the key. - /// - /// The key may be any borrowed form of the map's key type, but - /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for - /// the key type. + /// + /// # Arguments + /// * `k` may be any type that implements [`Equivalent`]. /// /// # Examples /// @@ -114,10 +104,9 @@ impl FrozenIndexMap { /// assert_eq!(map.get(&1), Some(&"a")); /// assert_eq!(map.get(&2), None); /// ``` - pub fn get(&self, k: &Q) -> Option<&V::Target> + pub fn get(&self, k: &Q) -> Option<&V::Target> where - K: Borrow, - Q: Hash + Eq, + Q: ?Sized + Hash + Equivalent, { assert!(!self.in_use.get()); self.in_use.set(true); @@ -130,6 +119,9 @@ impl FrozenIndexMap { } /// Returns the index corresponding to the key + /// + /// # Arguments + /// * `k` may be any type that implements [`Equivalent`]. /// /// # Examples /// @@ -157,10 +149,6 @@ impl FrozenIndexMap { /// Returns a reference to the key-value mapping corresponding to an index. /// - /// The key may be any borrowed form of the map's key type, but - /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for - /// the key type. - /// /// # Examples /// /// ``` @@ -187,6 +175,9 @@ impl FrozenIndexMap { } /// Returns a reference to the key, along with its index and a reference to its value + /// + /// # Arguments + /// * `k` may be any type that implements [`Equivalent`]. /// /// # Examples /// @@ -215,9 +206,8 @@ impl FrozenIndexMap { /// Applies a function to the owner of the value corresponding to the key (if any). /// - /// The key may be any borrowed form of the map's key type, but - /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for - /// the key type. + /// # Arguments + /// * `k` may be any type that implements [`Equivalent`]. /// /// # Examples /// @@ -229,10 +219,9 @@ impl FrozenIndexMap { /// assert_eq!(map.map_get(&1, Clone::clone), Some(Box::new("a"))); /// assert_eq!(map.map_get(&2, Clone::clone), None); /// ``` - pub fn map_get(&self, k: &Q, f: F) -> Option + pub fn map_get(&self, k: &Q, f: F) -> Option where - K: Borrow, - Q: Hash + Eq, + Q: ?Sized + Hash + Equivalent, F: FnOnce(&V) -> T, { assert!(!self.in_use.get()); @@ -301,10 +290,10 @@ impl From> for FrozenIndexMap { } } -impl Index<&Q> for FrozenIndexMap +impl Index<&Q> for FrozenIndexMap where - Q: Eq + Hash, - K: Eq + Hash + Borrow, + Q: ?Sized + Hash + Equivalent, + K: Eq + Hash, V: StableDeref, S: BuildHasher, { @@ -320,7 +309,7 @@ where /// assert_eq!(map[&1], "a"); /// ``` fn index(&self, idx: &Q) -> &V::Target { - self.get(&idx) + self.get(idx) .expect("attempted to index FrozenIndexMap with unknown key") } } diff --git a/src/index_set.rs b/src/index_set.rs index 1645b90..d2713ca 100644 --- a/src/index_set.rs +++ b/src/index_set.rs @@ -1,4 +1,3 @@ -use std::borrow::Borrow; use std::cell::{Cell, UnsafeCell}; use std::collections::hash_map::RandomState; use std::hash::{BuildHasher, Hash}; @@ -118,6 +117,9 @@ impl FrozenIndexSet { // } /// Returns a reference to the value passed as argument if present in the set. + /// + /// # Arguments + /// * `k` may be any type that implements [`Equivalent`]. /// /// # Examples /// @@ -129,10 +131,9 @@ impl FrozenIndexSet { /// assert_eq!(set.get(&Box::new("a")), Some(&"a")); /// assert_eq!(set.get(&Box::new("b")), None); /// ``` - pub fn get(&self, k: &Q) -> Option<&T::Target> + pub fn get(&self, k: &Q) -> Option<&T::Target> where - T: Borrow, - Q: Hash + Eq, + Q: ?Sized + Hash + Equivalent, { assert!(!self.in_use.get()); self.in_use.set(true); @@ -145,7 +146,10 @@ impl FrozenIndexSet { } /// Returns the index corresponding to the value if present in the set - /// + /// + /// # Arguments + /// * `k` may be any type that implements [`Equivalent`]. + /// /// # Examples /// /// ``` @@ -172,6 +176,9 @@ impl FrozenIndexSet { /// Returns a reference to the value passed as argument if present in the set, /// along with its index + /// + /// # Arguments + /// * `k` may be any type that implements [`Equivalent`]. /// /// # Examples /// @@ -183,10 +190,9 @@ impl FrozenIndexSet { /// assert_eq!(set.get_full(&Box::new("a")), Some((0, &"a"))); /// assert_eq!(set.get_full(&Box::new("b")), None); /// ``` - pub fn get_full(&self, k: &Q) -> Option<(usize, &T::Target)> + pub fn get_full(&self, k: &Q) -> Option<(usize, &T::Target)> where - T: Borrow, - Q: Hash + Eq, + Q: ?Sized + Hash + Equivalent, { assert!(!self.in_use.get()); self.in_use.set(true);