Add safety comments

This commit is contained in:
Gwilym Inzani 2023-05-09 21:55:14 +01:00
parent 35061ffb6a
commit 722deafc2f
2 changed files with 69 additions and 24 deletions

View file

@ -15,6 +15,8 @@
#![deny(rustdoc::private_intra_doc_links)] #![deny(rustdoc::private_intra_doc_links)]
#![deny(rustdoc::invalid_html_tags)] #![deny(rustdoc::invalid_html_tags)]
#![deny(unreachable_pub)] #![deny(unreachable_pub)]
#![deny(clippy::missing_safety_doc)]
#![deny(clippy::undocumented_unsafe_blocks)]
extern crate alloc; extern crate alloc;
@ -352,11 +354,14 @@ where
let hash = self.hash(key); let hash = self.hash(key);
let location = self.nodes.location(key, hash)?; let location = self.nodes.location(key, hash)?;
Some(unsafe { Some(
self.nodes // SAFETY: we know that a node exists and has a value from the location call above
.node_at_unchecked(location) unsafe {
.key_value_ref_unchecked() self.nodes
}) .node_at_unchecked(location)
.key_value_ref_unchecked()
},
)
} }
/// Returns a reference to the value corresponding to the key. Returns [`None`] if there is /// Returns a reference to the value corresponding to the key. Returns [`None`] if there is
@ -403,11 +408,14 @@ where
let hash = self.hash(key); let hash = self.hash(key);
let location = self.nodes.location(key, hash)?; let location = self.nodes.location(key, hash)?;
Some(unsafe { Some(
self.nodes // SAFETY: we know that a node exists and has a value from the location call above
.node_at_unchecked_mut(location) unsafe {
.value_mut_unchecked() self.nodes
}) .node_at_unchecked_mut(location)
.value_mut_unchecked()
},
)
} }
/// Removes the given key from the map. Returns the current value if it existed, or [`None`] /// Removes the given key from the map. Returns the current value if it existed, or [`None`]
@ -561,6 +569,15 @@ pub struct OccupiedEntry<'a, K: 'a, V: 'a, ALLOCATOR: Allocator> {
location: usize, location: usize,
} }
impl<'a, K: 'a, V: 'a, ALLOCATOR: Allocator> OccupiedEntry<'a, K, V, ALLOCATOR> {
/// # Safety
///
/// 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 {
Self { key, map, location }
}
}
impl<'a, K: 'a, V: 'a, ALLOCATOR: ClonableAllocator> OccupiedEntry<'a, K, V, ALLOCATOR> { 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 {
@ -575,6 +592,7 @@ impl<'a, K: 'a, V: 'a, ALLOCATOR: ClonableAllocator> OccupiedEntry<'a, K, V, ALL
/// Gets a reference to the value in the entry. /// Gets a reference to the value in the entry.
pub fn get(&self) -> &V { pub fn get(&self) -> &V {
// SAFETY: This can only be constructed with valid locations
unsafe { unsafe {
self.map self.map
.nodes .nodes
@ -590,6 +608,7 @@ impl<'a, K: 'a, V: 'a, ALLOCATOR: ClonableAllocator> OccupiedEntry<'a, K, V, ALL
/// ///
/// [`into_mut`]: Self::into_mut /// [`into_mut`]: Self::into_mut
pub fn get_mut(&mut self) -> &mut V { pub fn get_mut(&mut self) -> &mut V {
// SAFETY: This can only be constructed with valid locations
unsafe { unsafe {
self.map self.map
.nodes .nodes
@ -605,6 +624,7 @@ impl<'a, K: 'a, V: 'a, ALLOCATOR: ClonableAllocator> OccupiedEntry<'a, K, V, ALL
/// ///
/// [`get_mut`]: Self::get_mut /// [`get_mut`]: Self::get_mut
pub fn into_mut(self) -> &'a mut V { pub fn into_mut(self) -> &'a mut V {
// SAFETY: This can only be constructed with valid locations
unsafe { unsafe {
self.map self.map
.nodes .nodes
@ -615,6 +635,7 @@ impl<'a, K: 'a, V: 'a, ALLOCATOR: ClonableAllocator> OccupiedEntry<'a, K, V, ALL
/// Sets the value of the entry and returns the entry's old value. /// Sets the value of the entry and returns the entry's old value.
pub fn insert(&mut self, value: V) -> V { pub fn insert(&mut self, value: V) -> V {
// SAFETY: This can only be constructed with valid locations
unsafe { unsafe {
self.map self.map
.nodes .nodes
@ -757,11 +778,10 @@ where
let location = self.nodes.location(&key, hash); let location = self.nodes.location(&key, hash);
if let Some(location) = location { if let Some(location) = location {
Entry::Occupied(OccupiedEntry { Entry::Occupied(
key, // SAFETY: location is valid by the call to location above
location, unsafe { OccupiedEntry::new(key, self, location) },
map: self, )
})
} else { } else {
Entry::Vacant(VacantEntry { key, map: self }) Entry::Vacant(VacantEntry { key, map: self })
} }

View file

@ -40,7 +40,10 @@ impl<K, V> Node<K, V> {
pub(crate) fn value_mut(&mut self) -> Option<&mut V> { pub(crate) fn value_mut(&mut self) -> Option<&mut V> {
if self.has_value() { if self.has_value() {
Some(unsafe { self.value_mut_unchecked() }) Some(
// SAFETY: has a value
unsafe { self.value_mut_unchecked() },
)
} else { } else {
None None
} }
@ -52,7 +55,10 @@ impl<K, V> Node<K, V> {
pub(crate) fn key_ref(&self) -> Option<&K> { pub(crate) fn key_ref(&self) -> Option<&K> {
if self.distance_to_initial_bucket >= 0 { if self.distance_to_initial_bucket >= 0 {
Some(unsafe { self.key.assume_init_ref() }) Some(
// SAFETY: has a value
unsafe { self.key.assume_init_ref() },
)
} else { } else {
None None
} }
@ -60,7 +66,10 @@ impl<K, V> Node<K, V> {
pub(crate) fn key_value_ref(&self) -> Option<(&K, &V)> { pub(crate) fn key_value_ref(&self) -> Option<(&K, &V)> {
if self.has_value() { if self.has_value() {
Some(unsafe { self.key_value_ref_unchecked() }) Some(
// SAFETY: has a value
unsafe { self.key_value_ref_unchecked() },
)
} else { } else {
None None
} }
@ -72,7 +81,10 @@ impl<K, V> Node<K, V> {
pub(crate) fn key_value_mut(&mut self) -> Option<(&K, &mut V)> { pub(crate) fn key_value_mut(&mut self) -> Option<(&K, &mut V)> {
if self.has_value() { if self.has_value() {
Some(unsafe { (self.key.assume_init_ref(), self.value.assume_init_mut()) }) Some(
// SAFETY: has a value
unsafe { (self.key.assume_init_ref(), self.value.assume_init_mut()) },
)
} else { } else {
None None
} }
@ -88,7 +100,10 @@ impl<K, V> Node<K, V> {
let value = mem::replace(&mut self.value, MaybeUninit::uninit()); let value = mem::replace(&mut self.value, MaybeUninit::uninit());
self.distance_to_initial_bucket = -1; self.distance_to_initial_bucket = -1;
Some(unsafe { (key.assume_init(), value.assume_init(), self.hash) }) Some(
// SAFETY: has a value
unsafe { (key.assume_init(), value.assume_init(), self.hash) },
)
} else { } else {
None None
} }
@ -104,6 +119,7 @@ impl<K, V> Node<K, V> {
let old_key = mem::replace(&mut self.key, MaybeUninit::new(key)); let old_key = mem::replace(&mut self.key, MaybeUninit::new(key));
let old_value = mem::replace(&mut self.value, MaybeUninit::new(value)); let old_value = mem::replace(&mut self.value, MaybeUninit::new(value));
// SAFETY: has a value
unsafe { (old_key.assume_init(), old_value.assume_init()) } unsafe { (old_key.assume_init(), old_value.assume_init()) }
} else { } else {
panic!("Cannot replace an uninitialised node"); panic!("Cannot replace an uninitialised node");
@ -133,8 +149,11 @@ impl<K, V> Node<K, V> {
impl<K, V> Drop for Node<K, V> { impl<K, V> Drop for Node<K, V> {
fn drop(&mut self) { fn drop(&mut self) {
if self.has_value() { if self.has_value() {
unsafe { ptr::drop_in_place(self.key.as_mut_ptr()) }; // SAFETY: has a value
unsafe { ptr::drop_in_place(self.value.as_mut_ptr()) }; unsafe {
ptr::drop_in_place(self.key.as_mut_ptr());
ptr::drop_in_place(self.value.as_mut_ptr());
}
} }
} }
} }
@ -155,8 +174,14 @@ where
Self { Self {
hash: self.hash, hash: self.hash,
distance_to_initial_bucket: self.distance_to_initial_bucket, distance_to_initial_bucket: self.distance_to_initial_bucket,
key: MaybeUninit::new(unsafe { self.key.assume_init_ref() }.clone()), key: MaybeUninit::new(
value: MaybeUninit::new(unsafe { self.value.assume_init_ref() }.clone()), // SAFETY: has a value
unsafe { self.key.assume_init_ref() }.clone(),
),
value: MaybeUninit::new(
// SAFETY: has a value
unsafe { self.value.assume_init_ref() }.clone(),
),
} }
} else { } else {
Self { Self {