Skip to content

Commit 291ebbc

Browse files
committed
Make methods that get RawBucket parameters unsafe; add safety comments
These methods trust their caller to pass correct RawBucket values, so we mark them unsafe to use the common safe/unsafe distinction. I used allow(unused_unsafe) to write the functions in the (hopefully) future style of internal unsafe blocks in unsafe functions.
1 parent e42b469 commit 291ebbc

File tree

1 file changed

+32
-12
lines changed

1 file changed

+32
-12
lines changed

src/map_core.rs

+32-12
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,8 @@ impl<K, V> IndexMapCore<K, V> {
216216
K: Eq,
217217
{
218218
match self.find_equivalent(hash, &key) {
219+
// Safety: The entry is created with a live raw bucket, at the same time we have a &mut
220+
// reference to the map, so it can not be modified further.
219221
Some(raw_bucket) => Entry::Occupied(OccupiedEntry {
220222
map: self,
221223
raw_bucket,
@@ -250,7 +252,7 @@ impl<K, V> IndexMapCore<K, V> {
250252
Q: ?Sized + Equivalent<K>,
251253
{
252254
match self.find_equivalent(hash, key) {
253-
Some(raw_bucket) => Some(self.shift_remove_bucket(raw_bucket)),
255+
Some(raw_bucket) => unsafe { Some(self.shift_remove_bucket(raw_bucket)) },
254256
None => None,
255257
}
256258
}
@@ -261,12 +263,17 @@ impl<K, V> IndexMapCore<K, V> {
261263
Some(entry) => self.find_index(entry.hash, index).unwrap(),
262264
None => return None,
263265
};
264-
let (_, key, value) = self.shift_remove_bucket(raw_bucket);
265-
Some((key, value))
266+
unsafe {
267+
let (_, key, value) = self.shift_remove_bucket(raw_bucket);
268+
Some((key, value))
269+
}
266270
}
267271

268272
/// Remove an entry by shifting all entries that follow it
269-
fn shift_remove_bucket(&mut self, raw_bucket: RawBucket) -> (usize, K, V) {
273+
///
274+
/// Safety: The caller must pass a live `raw_bucket`.
275+
#[allow(unused_unsafe)]
276+
unsafe fn shift_remove_bucket(&mut self, raw_bucket: RawBucket) -> (usize, K, V) {
270277
// use Vec::remove, but then we need to update the indices that point
271278
// to all of the other entries that have to move
272279
let index = unsafe {
@@ -306,7 +313,7 @@ impl<K, V> IndexMapCore<K, V> {
306313
Q: ?Sized + Equivalent<K>,
307314
{
308315
match self.find_equivalent(hash, key) {
309-
Some(raw_bucket) => Some(self.swap_remove_bucket(raw_bucket)),
316+
Some(raw_bucket) => unsafe { Some(self.swap_remove_bucket(raw_bucket)) },
310317
None => None,
311318
}
312319
}
@@ -317,12 +324,17 @@ impl<K, V> IndexMapCore<K, V> {
317324
Some(entry) => self.find_index(entry.hash, index).unwrap(),
318325
None => return None,
319326
};
320-
let (_, key, value) = self.swap_remove_bucket(raw_bucket);
321-
Some((key, value))
327+
unsafe {
328+
let (_, key, value) = self.swap_remove_bucket(raw_bucket);
329+
Some((key, value))
330+
}
322331
}
323332

324333
/// Remove an entry by swapping it with the last
325-
fn swap_remove_bucket(&mut self, raw_bucket: RawBucket) -> (usize, K, V) {
334+
///
335+
/// Safety: The caller must pass a live `raw_bucket`.
336+
#[allow(unused_unsafe)]
337+
unsafe fn swap_remove_bucket(&mut self, raw_bucket: RawBucket) -> (usize, K, V) {
326338
// use swap_remove, but then we need to update the index that points
327339
// to the other entry that has to move
328340
let index = unsafe {
@@ -570,8 +582,12 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> {
570582
///
571583
/// Computes in **O(1)** time (average).
572584
pub fn swap_remove_entry(self) -> (K, V) {
573-
let (_, key, value) = self.map.swap_remove_bucket(self.raw_bucket);
574-
(key, value)
585+
// This is safe because it can only happen once (self is consumed)
586+
// and map.indices have not been modified since entry construction
587+
unsafe {
588+
let (_, key, value) = self.map.swap_remove_bucket(self.raw_bucket);
589+
(key, value)
590+
}
575591
}
576592

577593
/// Remove and return the key, value pair stored in the map for this entry
@@ -582,8 +598,12 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> {
582598
///
583599
/// Computes in **O(n)** time (average).
584600
pub fn shift_remove_entry(self) -> (K, V) {
585-
let (_, key, value) = self.map.shift_remove_bucket(self.raw_bucket);
586-
(key, value)
601+
// This is safe because it can only happen once (self is consumed)
602+
// and map.indices have not been modified since entry construction
603+
unsafe {
604+
let (_, key, value) = self.map.shift_remove_bucket(self.raw_bucket);
605+
(key, value)
606+
}
587607
}
588608
}
589609

0 commit comments

Comments
 (0)