Skip to content

Commit b63e4a1

Browse files
authored
Merge pull request #341 from cuviper/from-entry
Implement `From` between `IndexedEntry` and `OccupiedEntry`
2 parents 9b93dd5 + ba16981 commit b63e4a1

File tree

3 files changed

+60
-6
lines changed

3 files changed

+60
-6
lines changed

src/map/core/entry.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,17 @@ impl<K: fmt::Debug, V: fmt::Debug> fmt::Debug for OccupiedEntry<'_, K, V> {
282282
}
283283
}
284284

285+
impl<'a, K, V> From<IndexedEntry<'a, K, V>> for OccupiedEntry<'a, K, V> {
286+
fn from(entry: IndexedEntry<'a, K, V>) -> Self {
287+
Self {
288+
raw: entry
289+
.map
290+
.index_raw_entry(entry.index)
291+
.expect("index not found"),
292+
}
293+
}
294+
}
295+
285296
/// A view into a vacant entry in an [`IndexMap`][crate::IndexMap].
286297
/// It is part of the [`Entry`] enum.
287298
pub struct VacantEntry<'a, K, V> {
@@ -491,3 +502,10 @@ impl<K: fmt::Debug, V: fmt::Debug> fmt::Debug for IndexedEntry<'_, K, V> {
491502
.finish()
492503
}
493504
}
505+
506+
impl<'a, K, V> From<OccupiedEntry<'a, K, V>> for IndexedEntry<'a, K, V> {
507+
fn from(entry: OccupiedEntry<'a, K, V>) -> Self {
508+
let (map, index) = entry.raw.into_inner();
509+
Self { map, index }
510+
}
511+
}

src/map/core/raw.rs

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -83,16 +83,19 @@ impl<K, V> IndexMapCore<K, V> {
8383
let entries = &*self.entries;
8484
let eq = move |&i: &usize| is_match(&entries[i].key);
8585
match self.indices.find(hash.get(), eq) {
86-
// SAFETY: The entry is created with a live raw bucket, at the same time
87-
// we have a &mut reference to the map, so it can not be modified further.
88-
Some(raw_bucket) => Ok(RawTableEntry {
89-
map: self,
90-
raw_bucket,
91-
}),
86+
// SAFETY: The bucket is valid because we *just* found it in this map.
87+
Some(raw_bucket) => Ok(unsafe { RawTableEntry::new(self, raw_bucket) }),
9288
None => Err(self),
9389
}
9490
}
9591

92+
pub(super) fn index_raw_entry(&mut self, index: usize) -> Option<RawTableEntry<'_, K, V>> {
93+
let hash = self.entries.get(index)?.hash;
94+
let raw_bucket = self.indices.find(hash.get(), move |&i| i == index)?;
95+
// SAFETY: The bucket is valid because we *just* found it in this map.
96+
Some(unsafe { RawTableEntry::new(self, raw_bucket) })
97+
}
98+
9699
pub(super) fn indices_mut(&mut self) -> impl Iterator<Item = &mut usize> {
97100
// SAFETY: we're not letting any of the buckets escape this function,
98101
// only the item references that are appropriately bound to `&mut self`.
@@ -113,6 +116,13 @@ pub(super) struct RawTableEntry<'a, K, V> {
113116
unsafe impl<K: Sync, V: Sync> Sync for RawTableEntry<'_, K, V> {}
114117

115118
impl<'a, K, V> RawTableEntry<'a, K, V> {
119+
/// The caller must ensure that the `raw_bucket` is valid in the given `map`,
120+
/// and then we hold the `&mut` reference for exclusive access.
121+
#[inline]
122+
unsafe fn new(map: &'a mut IndexMapCore<K, V>, raw_bucket: RawBucket) -> Self {
123+
Self { map, raw_bucket }
124+
}
125+
116126
/// Return the index of the key-value pair
117127
#[inline]
118128
pub(super) fn index(&self) -> usize {
@@ -146,6 +156,7 @@ impl<'a, K, V> RawTableEntry<'a, K, V> {
146156
}
147157

148158
/// Take no action, just return the index and the original map reference.
159+
#[inline]
149160
pub(super) fn into_inner(self) -> (&'a mut IndexMapCore<K, V>, usize) {
150161
let index = self.index();
151162
(self.map, index)

src/map/tests.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,31 @@ fn get_index_entry() {
416416
assert_eq!(*map.get(&3).unwrap(), "4");
417417
}
418418

419+
#[test]
420+
fn from_entries() {
421+
let mut map = IndexMap::from([(1, "1"), (2, "2"), (3, "3")]);
422+
423+
{
424+
let e = match map.entry(1) {
425+
Entry::Occupied(e) => IndexedEntry::from(e),
426+
Entry::Vacant(_) => panic!(),
427+
};
428+
assert_eq!(e.index(), 0);
429+
assert_eq!(*e.key(), 1);
430+
assert_eq!(*e.get(), "1");
431+
}
432+
433+
{
434+
let e = match map.get_index_entry(1) {
435+
Some(e) => OccupiedEntry::from(e),
436+
None => panic!(),
437+
};
438+
assert_eq!(e.index(), 1);
439+
assert_eq!(*e.key(), 2);
440+
assert_eq!(*e.get(), "2");
441+
}
442+
}
443+
419444
#[test]
420445
fn keys() {
421446
let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];

0 commit comments

Comments
 (0)