Skip to main content

orengine_utils/
number_key_map.rs

1//! This module provides the [`NumberKeyMap`] struct.
2//!
3//! The [`NumberKeyMap`] is a compact, open-addressing map specialized for `usize` keys
4//! and generic values `V`.
5//! The implementation stores an internal contiguous array of `Slot<V>` entries and performs
6//! direct indexing of slots based on `key % capacity` with a small number of probe steps.
7//!
8//! The [`NumberKeyMap`] is optimized for zero-misses and so optimized for 99+% reading operations.
9
10use crate::hints::{assert_hint, cold_path, likely, unlikely, unwrap_or_bug_hint};
11use alloc::alloc::{alloc, dealloc, Layout};
12use core::ptr::null_mut;
13use core::{mem, ptr};
14
15/// Internal error codes used by the low-level insertion routine.
16///
17/// This enum describes why `insert_or_fail` failed: either there was no free slot
18/// available inside the currently probed region, or the same key was already present.
19enum InsertFailErr {
20    /// Not enough free slots were found in the target probing region.
21    NotEnoughSpace,
22    /// The key is already present in the map.
23    KeyAlreadyExists,
24}
25
26/// A single map slot that stores a key together with its associated value.
27///
28/// `Slot` is the in-memory element type of the internal contiguous buffer. Keys that are
29/// unused are expected to equal `usize::MAX`.
30struct Slot<V> {
31    key: usize,
32    value: V,
33}
34
35/// A small, specialized hash map keyed by `usize` values.
36///
37/// It is optimized for zero-misses and so optimized for 99+% reading operations.
38///
39/// It is optimized for integer keys and expects an external invariant
40/// that `usize::MAX` marks vacant slots.
41///
42/// # Example
43///
44/// ```rust
45/// use std::sync::{Mutex, RwLock};
46/// use orengine_utils::NumberKeyMap;
47///
48/// static POOLS: RwLock<NumberKeyMap<Mutex<Vec<Box<[u8]>>>>> = RwLock::new(NumberKeyMap::new());
49///
50/// fn acquire_from_pool(size: usize) -> Box<[u8]> {
51///     if let Some(v) = POOLS.read().unwrap().get(size) {
52///         v.lock().unwrap().pop().unwrap_or_else(|| vec![0; size].into_boxed_slice())
53///     } else {
54///         vec![0; size].into_boxed_slice()
55///     }
56/// }
57///
58/// fn put_to_pool(buf: Box<[u8]>) {
59///     let read_pool = POOLS.read().unwrap();
60///
61///     if let Some(v) = read_pool.get(buf.len()) {
62///         v.lock().unwrap().push(buf);
63///         return;
64///     }
65///
66///     drop(read_pool);
67///
68///     let mut write_pool = POOLS.write().unwrap();
69///     let res = write_pool.insert(buf.len(), Mutex::new(vec![buf]));
70///
71///     if let Err(mut v) = res {
72///         let buf = v.get_mut().unwrap().pop().unwrap();
73///
74///         write_pool.get(buf.len()).unwrap().lock().unwrap().push(buf);
75///     }
76/// }
77/// ```
78pub struct NumberKeyMap<V> {
79    // Because max misses are 0 for now and should be very close to it in the future,
80    // we should use `*mut Slot<V>` instead of *mut [key] and *mut [value].
81    inner: *mut Slot<V>,
82    capacity: usize,
83}
84
85impl<V> NumberKeyMap<V> {
86    /// Create an empty `NumberKeyMap`.
87    pub const fn new() -> Self {
88        Self {
89            inner: null_mut(),
90            capacity: 0,
91        }
92    }
93
94    /// Compute the start index in the buffer for the provided `key` and `capacity`.
95    ///
96    /// This is the primary hash function used by the map: `key % capacity`.
97    fn get_started_slot_idx_for_key(key: usize, capacity: usize) -> usize {
98        key % capacity
99    }
100
101    /// Validate a key for use in the map.
102    ///
103    /// The implementation reserves `usize::MAX` as the special vacant key marker, so
104    /// real keys must not be equal to that value.
105    fn validate_key(key: usize) {
106        assert_hint(key != usize::MAX, "`key` should be not equal to usize::MAX");
107    }
108
109    /// Compute a raw pointer to the slot at `idx` inside the `inner` buffer.
110    ///
111    /// # Panics
112    ///
113    /// This function uses `assert_hint` to check that `inner` is not null and that
114    /// `idx < capacity`. These checks are considered programmer errors in the
115    /// original code and will abort the program if violated.
116    fn get_slot_ptr(inner: *mut Slot<V>, capacity: usize, idx: usize) -> *mut Slot<V> {
117        assert_hint(
118            !inner.is_null(),
119            "NumberKeyMap is allocated at `get_slot_ptr`",
120        );
121        assert_hint(idx < capacity, "`idx` is out of bounds at `get_slot_ptr`");
122
123        unsafe { inner.add(idx) }
124    }
125
126    /// Get an immutable reference to the slot at `idx`.
127    fn get_slot(&self, idx: usize) -> &Slot<V> {
128        unsafe { &*Self::get_slot_ptr(self.inner, self.capacity, idx) }
129    }
130
131    /// Get a mutable reference to the slot at `idx`.
132    fn get_slot_mut(&mut self, idx: usize) -> &mut Slot<V> {
133        unsafe { &mut *Self::get_slot_ptr(self.inner, self.capacity, idx) }
134    }
135
136    /// Retrieve a reference to a value stored under `key`, if present.
137    ///
138    /// If the slot is occupied and contains the requested key, a reference to the
139    /// value is returned.
140    ///
141    /// # Panics
142    ///
143    /// This function panics if `key` is equal to `usize::MAX`.
144    pub fn get(&self, key: usize) -> Option<&V> {
145        Self::validate_key(key);
146
147        if unlikely(self.inner.is_null()) {
148            return None;
149        }
150
151        let idx = Self::get_started_slot_idx_for_key(key, self.capacity);
152        let slot = self.get_slot(idx);
153
154        if likely(slot.key == key) {
155            return Some(&slot.value);
156        }
157
158        None
159    }
160
161    /// Retrieve a mutable reference to a value stored under `key`, if present.
162    ///
163    /// If the slot is occupied and contains the requested key, a reference to the
164    /// value is returned.
165    ///
166    /// # Panics
167    ///
168    /// This function panics if `key` is equal to `usize::MAX`.
169    pub fn get_mut(&mut self, key: usize) -> Option<&mut V> {
170        Self::validate_key(key);
171
172        if unlikely(self.inner.is_null()) {
173            return None;
174        }
175
176        let idx = Self::get_started_slot_idx_for_key(key, self.capacity);
177        let slot = self.get_slot_mut(idx);
178
179        if likely(slot.key == key) {
180            return Some(&mut slot.value);
181        }
182
183        None
184    }
185
186    /// Compute a larger capacity when resizing is needed.
187    ///
188    /// The growth formula is conservative for small capacities and uses a factor
189    /// of `8/7` for larger ones. The function ensures the new capacity is never
190    /// a power of two (it increments by one if so) to prevent bad key distributing.
191    fn greater_capacity(capacity: usize) -> usize {
192        if unlikely(capacity < 16) {
193            return capacity * 2 + 2; // 1 -> 4 -> 10 -> 22 and next this condition is always false
194        }
195
196        let new_capacity = capacity * 8 / 7;
197        if unlikely(new_capacity.is_power_of_two()) {
198            new_capacity + 1
199        } else {
200            new_capacity
201        }
202    }
203
204    /// Low-level attempt to insert a value into an already-allocated buffer.
205    ///
206    /// Tries to write `value_ptr.read()` into the slot chosen by `key % capacity`.
207    /// On success returns `Ok(())`. On failure returns `Err(InsertFailErr)` with the
208    /// reason: either `NotEnoughSpace` when the slot is not vacant, or `KeyAlreadyExists`
209    /// if the same key is found and the caller semantics expect that.
210    ///
211    /// # Safety
212    ///
213    /// On success the caller must forget the `value_ptr`.
214    unsafe fn insert_or_fail(
215        inner: *mut Slot<V>,
216        capacity: usize,
217        key: usize,
218        value_ptr: *const V,
219    ) -> Result<(), InsertFailErr> {
220        assert_hint(
221            !inner.is_null(),
222            "null pointer is provided to `insert_or_fail`",
223        );
224
225        let idx = Self::get_started_slot_idx_for_key(key, capacity);
226        let slot_ptr = Self::get_slot_ptr(inner, capacity, idx);
227        let slot = unsafe { &mut *slot_ptr };
228
229        if likely(slot.key == usize::MAX) {
230            unsafe {
231                slot_ptr.write(Slot {
232                    key,
233                    value: value_ptr.read(),
234                });
235            }
236
237            Ok(())
238        } else if unlikely(key == slot.key) {
239            Err(InsertFailErr::KeyAlreadyExists)
240        } else {
241            // slot.key != usize::MAX && slot.key != key = occupied by another key
242            Err(InsertFailErr::NotEnoughSpace)
243        }
244    }
245
246    /// Increases the capacity of the map and inserts `key`/`value` into the new buffer.
247    ///
248    /// This method is marked `#[cold]` and `#[inline(never)]` because it is expected
249    /// to run rarely (only on reallocation). It allocates a larger buffer, attempts to
250    /// copy existing entries into it, and finally inserts the provided `(key, value)`.
251    ///
252    /// # Errors
253    ///
254    /// Returns `Err(V)` only when the `key` already exists in the map; otherwise it
255    /// commits the reallocation and returns `Ok(())`.
256    #[cold]
257    #[inline(never)]
258    fn slow_insert(&mut self, key: usize, value: V) -> Result<(), V> {
259        let mut new_capacity = Self::greater_capacity(self.capacity);
260
261        'allocate: loop {
262            let layout = unwrap_or_bug_hint(Layout::array::<Slot<V>>(new_capacity));
263            // It is more expensive to first check if the capacity is good enough
264            // for zero-misses and only after allocate and insert
265            // than inserts from the start and reallocate if needed.
266            let new_inner: *mut Slot<V> = unsafe { alloc(layout) }.cast();
267
268            for i in 0..new_capacity {
269                unsafe {
270                    let slot = new_inner.add(i);
271
272                    (*slot).key = usize::MAX;
273                };
274            }
275
276            for idx in 0..self.capacity {
277                let slot = self.get_slot(idx);
278
279                if slot.key != usize::MAX {
280                    let res = unsafe {
281                        Self::insert_or_fail(
282                            new_inner,
283                            new_capacity,
284                            slot.key,
285                            &raw const slot.value,
286                        )
287                    };
288                    if unlikely(res.is_err()) {
289                        assert_hint(
290                            matches!(res, Err(InsertFailErr::NotEnoughSpace)),
291                            "invalid inner state is detected while reallocating: duplicate key",
292                        );
293
294                        // We should reallocate
295                        new_capacity = Self::greater_capacity(new_capacity);
296
297                        unsafe { dealloc(new_inner.cast(), layout) };
298
299                        continue 'allocate;
300                    }
301                }
302            }
303
304            // We recopied all the values, but we need to insert one more item.
305            let res =
306                unsafe { Self::insert_or_fail(new_inner, new_capacity, key, &raw const value) };
307
308            let mut commit_reallocate = || {
309                unsafe {
310                    dealloc(
311                        self.inner.cast(),
312                        unwrap_or_bug_hint(Layout::array::<Slot<V>>(self.capacity)),
313                    );
314                };
315
316                self.inner = new_inner;
317                self.capacity = new_capacity;
318            };
319
320            match res {
321                Ok(()) => {
322                    commit_reallocate();
323
324                    mem::forget(value);
325
326                    break Ok(());
327                }
328
329                Err(InsertFailErr::NotEnoughSpace) => {
330                    cold_path();
331
332                    // We should reallocate
333                    new_capacity = Self::greater_capacity(new_capacity);
334
335                    unsafe { dealloc(new_inner.cast(), layout) };
336
337                    // continue 'allocate;
338                }
339
340                Err(InsertFailErr::KeyAlreadyExists) => {
341                    // We have already successfully resized the map, and one next insert will need it,
342                    // so we commit the resize but return an error
343
344                    commit_reallocate();
345
346                    break Err(value);
347                }
348            }
349        }
350    }
351
352    /// Allocates the map with one `key`/`value`.
353    #[cold]
354    #[inline(never)]
355    fn insert_first(&mut self, key: usize, value: V) {
356        Self::validate_key(key);
357
358        let layout = unwrap_or_bug_hint(Layout::array::<Slot<V>>(1));
359        let inner: *mut Slot<V> = unsafe { alloc(layout) }.cast();
360        unsafe { inner.write(Slot { key, value }) };
361
362        self.inner = inner;
363        self.capacity = 1;
364    }
365
366    /// Insert a key/value pair into the map.
367    ///
368    /// # Note
369    ///
370    /// This operation is very expensive! If you want to call it frequently,
371    /// consider using a `HashMap` instead.
372    ///
373    /// # Errors
374    ///
375    /// Returns `Err(V)` if the key already exists in the map; otherwise returns `Ok(())`.
376    ///
377    /// # Panics
378    ///
379    /// This function panics if `key` is equal to `usize::MAX`
380    pub fn insert(&mut self, key: usize, value: V) -> Result<(), V> {
381        Self::validate_key(key);
382
383        if unlikely(self.inner.is_null()) {
384            self.insert_first(key, value);
385
386            return Ok(());
387        }
388
389        let res = unsafe { Self::insert_or_fail(self.inner, self.capacity, key, &raw const value) };
390        if likely(res.is_ok()) {
391            mem::forget(value);
392
393            return Ok(());
394        }
395
396        self.slow_insert(key, value)
397    }
398
399    /// Removes an item from the map and returns it if it exists.
400    ///
401    /// # Panics
402    ///
403    /// This function panics if `key` is equal to `usize::MAX`
404    pub fn remove(&mut self, key: usize) -> Option<V> {
405        Self::validate_key(key);
406
407        let idx = Self::get_started_slot_idx_for_key(key, self.capacity);
408        let slot = self.get_slot_mut(idx);
409        if unlikely(slot.key == usize::MAX) {
410            return None;
411        }
412
413        slot.key = usize::MAX;
414
415        Some(unsafe { ptr::read(&raw const slot.value) })
416    }
417
418    /// Clears the [`NumberKeyMap`] with the provided function.
419    pub fn clear_with(&mut self, func: impl Fn((usize, V))) {
420        if self.inner.is_null() {
421            return;
422        }
423
424        for i in 0..self.capacity {
425            let slot_ptr = unsafe { self.inner.add(i) };
426            let slot = unsafe { &mut *slot_ptr };
427
428            if slot.key != usize::MAX {
429                func((slot.key, unsafe { ptr::read(&raw const slot.value) }));
430                slot.key = usize::MAX;
431            }
432        }
433    }
434
435    /// Clears the [`NumberKeyMap`].
436    pub fn clear(&mut self) {
437        self.clear_with(drop);
438    }
439}
440
441impl<V> Default for NumberKeyMap<V> {
442    fn default() -> Self {
443        Self::new()
444    }
445}
446
447/// An iterator over the [`NumberKeyMap`].
448/// The item of this iterator is `(key, value)`.
449///
450/// This iterator consumes the [`NumberKeyMap`].
451pub struct IntoIter<V> {
452    start: *mut Slot<V>,
453    i: usize,
454    capacity: usize,
455}
456
457impl<V> Iterator for IntoIter<V> {
458    type Item = (usize, V);
459
460    fn next(&mut self) -> Option<Self::Item> {
461        unsafe {
462            while self.i < self.capacity {
463                let ptr = self.start.add(self.i);
464                let slot = &mut *ptr;
465
466                self.i += 1;
467
468                if slot.key != usize::MAX {
469                    return Some((slot.key, ptr::read(&raw const slot.value)));
470                }
471            }
472
473            None
474        }
475    }
476}
477
478impl<V> Drop for IntoIter<V> {
479    fn drop(&mut self) {
480        unsafe {
481            // Drop remaining values
482            for (_k, v) in self.by_ref() {
483                drop(v);
484            }
485
486            // Free memory
487            let layout = Layout::array::<Slot<V>>(self.capacity).unwrap();
488
489            dealloc(self.start.cast(), layout);
490        }
491    }
492}
493
494impl<V> NumberKeyMap<V> {
495    /// Iterate immutably over all `(key, &value)`.
496    pub fn iter(&self) -> impl Iterator<Item = (usize, &V)> {
497        struct Iter<'a, V> {
498            ptr: *mut Slot<V>,
499            end: *mut Slot<V>,
500            _marker: core::marker::PhantomData<&'a V>,
501        }
502
503        impl<'a, V> Iterator for Iter<'a, V> {
504            type Item = (usize, &'a V);
505
506            fn next(&mut self) -> Option<Self::Item> {
507                unsafe {
508                    while self.ptr < self.end {
509                        let slot = &*self.ptr;
510
511                        self.ptr = self.ptr.add(1);
512
513                        if slot.key != usize::MAX {
514                            return Some((slot.key, &slot.value));
515                        }
516                    }
517
518                    None
519                }
520            }
521        }
522
523        Iter {
524            ptr: self.inner,
525            end: unsafe { self.inner.add(self.capacity) },
526            _marker: core::marker::PhantomData,
527        }
528    }
529
530    /// Iterate mutably over all `(key, &mut value)`.
531    pub fn iter_mut(&mut self) -> impl Iterator<Item = (usize, &mut V)> {
532        struct IterMut<'a, V> {
533            ptr: *mut Slot<V>,
534            end: *mut Slot<V>,
535            _marker: core::marker::PhantomData<&'a mut V>,
536        }
537
538        impl<'a, V: 'a> Iterator for IterMut<'a, V> {
539            type Item = (usize, &'a mut V);
540
541            fn next(&mut self) -> Option<Self::Item> {
542                unsafe {
543                    while self.ptr < self.end {
544                        let slot = &mut *self.ptr;
545
546                        self.ptr = self.ptr.add(1);
547
548                        if slot.key != usize::MAX {
549                            return Some((slot.key, &mut slot.value));
550                        }
551                    }
552
553                    None
554                }
555            }
556        }
557
558        IterMut {
559            ptr: self.inner,
560            end: unsafe { self.inner.add(self.capacity) },
561            _marker: core::marker::PhantomData,
562        }
563    }
564}
565
566impl<V: 'static> NumberKeyMap<V> {
567    /// Remove all entries and yield owned `(key, value)`.
568    pub fn drain(&mut self) -> impl Iterator<Item = (usize, V)> {
569        struct Drain<'a, V> {
570            ptr: *mut Slot<V>,
571            end: *mut Slot<V>,
572            _marker: core::marker::PhantomData<&'a mut V>,
573        }
574
575        impl<V: 'static> Iterator for Drain<'_, V> {
576            type Item = (usize, V);
577
578            fn next(&mut self) -> Option<Self::Item> {
579                unsafe {
580                    while self.ptr < self.end {
581                        let slot = &mut *self.ptr;
582
583                        self.ptr = self.ptr.add(1);
584
585                        if slot.key != usize::MAX {
586                            let key = slot.key;
587
588                            slot.key = usize::MAX;
589
590                            return Some((key, ptr::read(&raw const slot.value)));
591                        }
592                    }
593
594                    None
595                }
596            }
597        }
598
599        Drain {
600            ptr: self.inner,
601            end: unsafe { self.inner.add(self.capacity) },
602            _marker: core::marker::PhantomData,
603        }
604    }
605}
606
607impl<V> IntoIterator for NumberKeyMap<V> {
608    type Item = (usize, V);
609    type IntoIter = IntoIter<V>;
610
611    fn into_iter(self) -> Self::IntoIter {
612        let iter = IntoIter {
613            start: self.inner,
614            i: 0,
615            capacity: self.capacity,
616        };
617
618        mem::forget(self);
619
620        iter
621    }
622}
623
624unsafe impl<V> Sync for NumberKeyMap<V> {}
625unsafe impl<V> Send for NumberKeyMap<V> {}
626
627impl<V> Drop for NumberKeyMap<V> {
628    fn drop(&mut self) {
629        if self.inner.is_null() {
630            return;
631        }
632
633        if mem::needs_drop::<V>() {
634            for i in 0..self.capacity {
635                let slot_ptr = unsafe { self.inner.add(i) };
636                let slot = unsafe { &mut *slot_ptr };
637
638                if slot.key != usize::MAX {
639                    unsafe { (&raw mut slot.value).drop_in_place() };
640                }
641            }
642        }
643
644        let layout = Layout::array::<Slot<V>>(self.capacity).unwrap();
645        unsafe {
646            dealloc(self.inner.cast(), layout);
647        }
648    }
649}
650
651#[cfg(test)]
652mod tests {
653    use super::*;
654
655    use alloc::rc::Rc;
656    #[cfg(feature = "no_std")]
657    use alloc::vec::Vec;
658    use core::cell::Cell;
659
660    #[derive(Debug)]
661    struct DropCounter(usize, Rc<Cell<usize>>);
662
663    impl Drop for DropCounter {
664        fn drop(&mut self) {
665            self.1.set(self.1.get() + 1);
666        }
667    }
668
669    #[test]
670    fn test_number_key_map_insert_and_get() {
671        const N: usize = 1_000_000;
672
673        let mut m = NumberKeyMap::new();
674        let drops = Rc::new(Cell::new(0));
675
676        for i in 0..N {
677            m.insert(i, DropCounter(i, drops.clone())).unwrap();
678
679            assert_eq!(m.get(i).map(|v| v.0), Some(i));
680            assert_eq!(m.get_mut(i).map(|v| v.0), Some(i));
681        }
682
683        for i in 0..N {
684            assert_eq!(m.get(i).map(|v| v.0), Some(i));
685        }
686
687        assert_eq!(drops.get(), 0);
688
689        for i in 0..N / 2 {
690            assert!(m.remove(i).is_some());
691            assert!(m.remove(i).is_none());
692        }
693
694        assert_eq!(drops.get(), N / 2);
695
696        drop(m);
697
698        assert_eq!(drops.get(), N);
699    }
700
701    #[test]
702    fn test_number_key_map_duplicate_key_returns_err() {
703        let mut m = NumberKeyMap::new();
704        let k = 1usize;
705        let drops = Rc::new(Cell::new(0));
706
707        m.insert(k, DropCounter(10, drops.clone())).unwrap();
708        assert!(m.insert(k, DropCounter(20, drops.clone())).is_err());
709
710        // original value remains
711        assert_eq!(m.get(k).map(|v| v.0), Some(10));
712
713        assert_eq!(drops.get(), 1);
714
715        drop(m);
716
717        assert_eq!(drops.get(), 2);
718    }
719
720    #[test]
721    fn test_number_key_map_clear() {
722        let mut m = NumberKeyMap::new();
723        let drops = Rc::new(Cell::new(0));
724
725        for i in 0..1_000_000 {
726            m.insert(i, DropCounter(i, drops.clone())).unwrap();
727        }
728
729        assert_eq!(drops.get(), 0);
730
731        m.clear();
732
733        assert_eq!(drops.get(), 1_000_000);
734
735        m.clear_with(|_| panic!("Not cleared"));
736
737        assert_eq!(drops.get(), 1_000_000);
738    }
739
740    #[test]
741    fn test_number_key_map_iter() {
742        let mut m = NumberKeyMap::new();
743        let drops = Rc::new(Cell::new(0));
744
745        for i in 0..10 {
746            m.insert(i, DropCounter(i, drops.clone())).unwrap();
747        }
748
749        let mut seen = Vec::new();
750        for (k, v) in m.iter() {
751            seen.push((k, v.0));
752        }
753
754        seen.sort_by_key(|x| x.0);
755
756        assert_eq!(seen, (0..10).map(|i| (i, i)).collect::<Vec<_>>());
757        assert_eq!(drops.get(), 0); // iter() should not drop
758    }
759
760    #[test]
761    fn test_number_key_map_iter_mut() {
762        let mut m = NumberKeyMap::new();
763        let drops = Rc::new(Cell::new(0));
764
765        for i in 0..10 {
766            m.insert(i, DropCounter(i, drops.clone())).unwrap();
767        }
768
769        for (_, v) in m.iter_mut() {
770            v.0 *= 2;
771        }
772
773        let mut collected = m.iter().map(|(_, v)| v.0).collect::<Vec<_>>();
774
775        collected.sort_by_key(|x| *x);
776
777        assert_eq!(collected, (0..10).map(|i| i * 2).collect::<Vec<_>>());
778        assert_eq!(drops.get(), 0); // iter_mut() should not drop
779    }
780
781    #[test]
782    fn test_number_key_map_into_iter() {
783        let drops = Rc::new(Cell::new(0));
784        let mut m = NumberKeyMap::new();
785
786        for i in 0..10 {
787            m.insert(i, DropCounter(i, drops.clone())).unwrap();
788        }
789
790        assert_eq!(drops.get(), 0);
791
792        let mut seen = Vec::new();
793        for (k, v) in m {
794            seen.push((k, v.0));
795        }
796
797        // after into_iter, the map is consumed
798        seen.sort_by_key(|x| x.0);
799
800        assert_eq!(seen, (0..10).map(|i| (i, i)).collect::<Vec<_>>());
801
802        // all values must be dropped exactly once
803        assert_eq!(drops.get(), 10);
804    }
805
806    #[test]
807    fn test_number_map_drain() {
808        let drops = Rc::new(Cell::new(0));
809        let mut m = NumberKeyMap::new();
810
811        for i in 0..10 {
812            m.insert(i, DropCounter(i, drops.clone())).unwrap();
813        }
814
815        assert_eq!(drops.get(), 0);
816
817        let mut seen = Vec::new();
818        for (k, v) in m.drain() {
819            seen.push((k, v.0));
820        }
821
822        // after drain, the map is consumed
823        seen.sort_by_key(|x| x.0);
824
825        assert_eq!(seen, (0..10).map(|i| (i, i)).collect::<Vec<_>>());
826
827        drop(m);
828
829        // all values must be dropped exactly once
830        assert_eq!(drops.get(), 10);
831
832        let mut m = NumberKeyMap::new();
833
834        for i in 0..10 {
835            m.insert(i, DropCounter(i, drops.clone())).unwrap();
836        }
837
838        let iter = m.drain();
839
840        #[allow(clippy::drop_non_drop, reason = "It is tested here")]
841        drop(iter);
842
843        assert_eq!(drops.get(), 10);
844    }
845}