Don't do unsafe things with entries

This commit is contained in:
Gwilym Inzani 2023-05-09 22:00:13 +01:00
parent 722deafc2f
commit 05f387e41f

View file

@ -562,23 +562,30 @@ impl<K, V, ALLOCATOR: ClonableAllocator> IntoIterator for HashMap<K, V, ALLOCATO
} }
} }
/// A view into an occupied entry in a `HashMap`. This is part of the [`Entry`] enum. mod entries {
pub struct OccupiedEntry<'a, K: 'a, V: 'a, ALLOCATOR: Allocator> { use core::{alloc::Allocator, hash::Hash};
use super::{ClonableAllocator, HashMap};
/// A view into an occupied entry in a `HashMap`. This is part of the [`Entry`] enum.
pub struct OccupiedEntry<'a, K: 'a, V: 'a, ALLOCATOR: Allocator> {
key: K, key: K,
map: &'a mut HashMap<K, V, ALLOCATOR>, map: &'a mut HashMap<K, V, ALLOCATOR>,
location: usize, location: usize,
} }
impl<'a, K: 'a, V: 'a, ALLOCATOR: Allocator> OccupiedEntry<'a, K, V, ALLOCATOR> { impl<'a, K: 'a, V: 'a, ALLOCATOR: ClonableAllocator> OccupiedEntry<'a, K, V, ALLOCATOR> {
/// # Safety /// # Safety
/// ///
/// You must call this with a valid location (one where the entry is defined) /// You must call this with a valid location (one where the entry is defined)
unsafe fn new(key: K, map: &'a mut HashMap<K, V, ALLOCATOR>, location: usize) -> Self { pub(crate) unsafe fn new(
key: K,
map: &'a mut HashMap<K, V, ALLOCATOR>,
location: usize,
) -> Self {
Self { key, map, location } Self { key, map, location }
} }
}
impl<'a, K: 'a, V: 'a, ALLOCATOR: ClonableAllocator> OccupiedEntry<'a, K, V, ALLOCATOR> {
/// Gets a reference to the key in the entry. /// Gets a reference to the key in the entry.
pub fn key(&self) -> &K { pub fn key(&self) -> &K {
&self.key &self.key
@ -648,15 +655,19 @@ impl<'a, K: 'a, V: 'a, ALLOCATOR: ClonableAllocator> OccupiedEntry<'a, K, V, ALL
pub fn remove(self) -> V { pub fn remove(self) -> V {
self.map.nodes.remove_from_location(self.location) self.map.nodes.remove_from_location(self.location)
} }
} }
/// A view into a vacant entry in a `HashMap`. It is part of the [`Entry`] enum. /// A view into a vacant entry in a `HashMap`. It is part of the [`Entry`] enum.
pub struct VacantEntry<'a, K: 'a, V: 'a, ALLOCATOR: Allocator> { pub struct VacantEntry<'a, K: 'a, V: 'a, ALLOCATOR: Allocator> {
key: K, key: K,
map: &'a mut HashMap<K, V, ALLOCATOR>, map: &'a mut HashMap<K, V, ALLOCATOR>,
} }
impl<'a, K: 'a, V: 'a, ALLOCATOR: ClonableAllocator> VacantEntry<'a, K, V, ALLOCATOR> {
pub(crate) fn new(key: K, map: &'a mut HashMap<K, V, ALLOCATOR>) -> Self {
Self { key, map }
}
impl<'a, K: 'a, V: 'a, ALLOCATOR: ClonableAllocator> VacantEntry<'a, K, V, ALLOCATOR> {
/// Gets a reference to the key that would be used when inserting a value through `VacantEntry` /// Gets a reference to the key that would be used when inserting a value through `VacantEntry`
pub fn key(&self) -> &K { pub fn key(&self) -> &K {
&self.key &self.key
@ -674,8 +685,11 @@ impl<'a, K: 'a, V: 'a, ALLOCATOR: ClonableAllocator> VacantEntry<'a, K, V, ALLOC
{ {
self.map.insert_and_get(self.key, value) self.map.insert_and_get(self.key, value)
} }
}
} }
pub use entries::{OccupiedEntry, VacantEntry};
/// A view into a single entry in a map, which may be vacant or occupied. /// A view into a single entry in a map, which may be vacant or occupied.
/// ///
/// This is constructed using the [`entry`] method on [`HashMap`] /// This is constructed using the [`entry`] method on [`HashMap`]
@ -726,7 +740,7 @@ where
match self { match self {
Entry::Occupied(e) => e.into_mut(), Entry::Occupied(e) => e.into_mut(),
Entry::Vacant(e) => { Entry::Vacant(e) => {
let value = f(&e.key); let value = f(e.key());
e.insert(value) e.insert(value)
} }
} }
@ -762,8 +776,8 @@ where
/// Returns a reference to this entry's key. /// Returns a reference to this entry's key.
pub fn key(&self) -> &K { pub fn key(&self) -> &K {
match self { match self {
Entry::Occupied(e) => &e.key, Entry::Occupied(e) => e.key(),
Entry::Vacant(e) => &e.key, Entry::Vacant(e) => e.key(),
} }
} }
} }
@ -783,7 +797,7 @@ where
unsafe { OccupiedEntry::new(key, self, location) }, unsafe { OccupiedEntry::new(key, self, location) },
) )
} else { } else {
Entry::Vacant(VacantEntry { key, map: self }) Entry::Vacant(VacantEntry::new(key, self))
} }
} }
} }