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(new_inner, new_capacity, slot.key, &slot.value)
282                    };
283                    if unlikely(res.is_err()) {
284                        assert_hint(
285                            matches!(res, Err(InsertFailErr::NotEnoughSpace)),
286                            "invalid inner state is detected while reallocating: duplicate key",
287                        );
288
289                        // We should reallocate
290                        new_capacity = Self::greater_capacity(new_capacity);
291
292                        unsafe { dealloc(new_inner.cast(), layout) };
293
294                        continue 'allocate;
295                    }
296                }
297            }
298
299            // We recopied all the values, but we need to insert one more item.
300            let res = unsafe { Self::insert_or_fail(new_inner, new_capacity, key, &value) };
301
302            let mut commit_reallocate = || {
303                unsafe {
304                    dealloc(
305                        self.inner.cast(),
306                        unwrap_or_bug_hint(Layout::array::<Slot<V>>(self.capacity)),
307                    );
308                };
309
310                self.inner = new_inner;
311                self.capacity = new_capacity;
312            };
313
314            match res {
315                Ok(()) => {
316                    commit_reallocate();
317
318                    mem::forget(value);
319
320                    break Ok(());
321                }
322
323                Err(InsertFailErr::NotEnoughSpace) => {
324                    cold_path();
325
326                    // We should reallocate
327                    new_capacity = Self::greater_capacity(new_capacity);
328
329                    unsafe { dealloc(new_inner.cast(), layout) };
330
331                    continue 'allocate;
332                }
333
334                Err(InsertFailErr::KeyAlreadyExists) => {
335                    // We have already successfully resized the map, and one next insert will need it,
336                    // so we commit the resize but return an error
337
338                    commit_reallocate();
339
340                    break Err(value);
341                }
342            }
343        }
344    }
345
346    /// Allocates the map with one `key`/`value`.
347    #[cold]
348    #[inline(never)]
349    fn insert_first(&mut self, key: usize, value: V) {
350        Self::validate_key(key);
351
352        let layout = unwrap_or_bug_hint(Layout::array::<Slot<V>>(1));
353        let inner: *mut Slot<V> = unsafe { alloc(layout) }.cast();
354        unsafe { inner.write(Slot { key, value }) };
355
356        self.inner = inner;
357        self.capacity = 1;
358    }
359
360    /// Insert a key/value pair into the map.
361    ///
362    /// # Note
363    ///
364    /// This operation is very expensive! If you want to call it frequently,
365    /// consider using a `HashMap` instead.
366    ///
367    /// # Errors
368    ///
369    /// Returns `Err(V)` if the key already exists in the map; otherwise returns `Ok(())`.
370    ///
371    /// # Panics
372    ///
373    /// This function panics if `key` is equal to `usize::MAX`
374    pub fn insert(&mut self, key: usize, value: V) -> Result<(), V> {
375        Self::validate_key(key);
376
377        if unlikely(self.inner.is_null()) {
378            self.insert_first(key, value);
379
380            return Ok(());
381        }
382
383        let res = unsafe { Self::insert_or_fail(self.inner, self.capacity, key, &value) };
384        if likely(res.is_ok()) {
385            mem::forget(value);
386
387            return Ok(());
388        }
389
390        self.slow_insert(key, value)
391    }
392
393    /// Removes an item from the map and returns it if it exists.
394    ///
395    /// # Panics
396    ///
397    /// This function panics if `key` is equal to `usize::MAX`
398    pub fn remove(&mut self, key: usize) -> Option<V> {
399        Self::validate_key(key);
400
401        let idx = Self::get_started_slot_idx_for_key(key, self.capacity);
402        let slot = self.get_slot_mut(idx);
403        if unlikely(slot.key == usize::MAX) {
404            return None;
405        }
406
407        slot.key = usize::MAX;
408
409        Some(unsafe { ptr::read(&slot.value) })
410    }
411
412    /// Clears the [`NumberKeyMap`] with the provided function.
413    pub fn clear_with(&mut self, func: impl Fn((usize, V))) {
414        if self.inner.is_null() {
415            return;
416        }
417
418        for i in 0..self.capacity {
419            let slot_ptr = unsafe { self.inner.add(i) };
420            let slot = unsafe { &mut *slot_ptr };
421
422            if slot.key != usize::MAX {
423                func((slot.key, unsafe { ptr::read(&slot.value) }));
424                slot.key = usize::MAX;
425            }
426        }
427    }
428
429    /// Clears the [`NumberKeyMap`].
430    pub fn clear(&mut self) {
431        self.clear_with(drop);
432    }
433}
434
435impl<V> Default for NumberKeyMap<V> {
436    fn default() -> Self {
437        Self::new()
438    }
439}
440
441/// An iterator over the [`NumberKeyMap`].
442/// The item of this iterator is `(key, value)`.
443///
444/// This iterator consumes the [`NumberKeyMap`].
445pub struct IntoIter<V> {
446    start: *mut Slot<V>,
447    i: usize,
448    capacity: usize,
449}
450
451impl<V> Iterator for IntoIter<V> {
452    type Item = (usize, V);
453
454    fn next(&mut self) -> Option<Self::Item> {
455        unsafe {
456            while self.i < self.capacity {
457                let ptr = self.start.add(self.i);
458                let slot = &mut *ptr;
459
460                self.i += 1;
461
462                if slot.key != usize::MAX {
463                    return Some((slot.key, ptr::read(&slot.value)));
464                }
465            }
466
467            None
468        }
469    }
470}
471
472impl<V> Drop for IntoIter<V> {
473    fn drop(&mut self) {
474        unsafe {
475            // Drop remaining values
476            for (_k, v) in self.by_ref() {
477                drop(v);
478            }
479
480            // Free memory
481            let layout = Layout::array::<Slot<V>>(self.capacity).unwrap();
482
483            dealloc(self.start.cast(), layout);
484        }
485    }
486}
487
488impl<V> NumberKeyMap<V> {
489    /// Iterate immutably over all `(key, &value)`.
490    pub fn iter(&self) -> impl Iterator<Item = (usize, &V)> {
491        struct Iter<'a, V> {
492            ptr: *mut Slot<V>,
493            end: *mut Slot<V>,
494            _marker: core::marker::PhantomData<&'a V>,
495        }
496
497        impl<'a, V> Iterator for Iter<'a, V> {
498            type Item = (usize, &'a V);
499
500            fn next(&mut self) -> Option<Self::Item> {
501                unsafe {
502                    while self.ptr < self.end {
503                        let slot = &*self.ptr;
504
505                        self.ptr = self.ptr.add(1);
506
507                        if slot.key != usize::MAX {
508                            return Some((slot.key, &slot.value));
509                        }
510                    }
511
512                    None
513                }
514            }
515        }
516
517        Iter {
518            ptr: self.inner,
519            end: unsafe { self.inner.add(self.capacity) },
520            _marker: core::marker::PhantomData,
521        }
522    }
523
524    /// Iterate mutably over all `(key, &mut value)`.
525    pub fn iter_mut(&mut self) -> impl Iterator<Item = (usize, &mut V)> {
526        struct IterMut<'a, V> {
527            ptr: *mut Slot<V>,
528            end: *mut Slot<V>,
529            _marker: core::marker::PhantomData<&'a mut V>,
530        }
531
532        impl<'a, V: 'a> Iterator for IterMut<'a, V> {
533            type Item = (usize, &'a mut V);
534
535            fn next(&mut self) -> Option<Self::Item> {
536                unsafe {
537                    while self.ptr < self.end {
538                        let slot = &mut *self.ptr;
539
540                        self.ptr = self.ptr.add(1);
541
542                        if slot.key != usize::MAX {
543                            return Some((slot.key, &mut slot.value));
544                        }
545                    }
546
547                    None
548                }
549            }
550        }
551
552        IterMut {
553            ptr: self.inner,
554            end: unsafe { self.inner.add(self.capacity) },
555            _marker: core::marker::PhantomData,
556        }
557    }
558}
559
560impl<V: 'static> NumberKeyMap<V> {
561    /// Remove all entries and yield owned `(key, value)`.
562    pub fn drain(&mut self) -> impl Iterator<Item = (usize, V)> {
563        struct Drain<'a, V> {
564            ptr: *mut Slot<V>,
565            end: *mut Slot<V>,
566            _marker: core::marker::PhantomData<&'a mut V>,
567        }
568
569        impl<V: 'static> Iterator for Drain<'_, V> {
570            type Item = (usize, V);
571
572            fn next(&mut self) -> Option<Self::Item> {
573                unsafe {
574                    while self.ptr < self.end {
575                        let slot = &mut *self.ptr;
576
577                        self.ptr = self.ptr.add(1);
578
579                        if slot.key != usize::MAX {
580                            let key = slot.key;
581
582                            slot.key = usize::MAX;
583
584                            return Some((key, ptr::read(&slot.value)));
585                        }
586                    }
587
588                    None
589                }
590            }
591        }
592
593        Drain {
594            ptr: self.inner,
595            end: unsafe { self.inner.add(self.capacity) },
596            _marker: core::marker::PhantomData,
597        }
598    }
599}
600
601impl<V> IntoIterator for NumberKeyMap<V> {
602    type Item = (usize, V);
603    type IntoIter = IntoIter<V>;
604
605    fn into_iter(self) -> Self::IntoIter {
606        let iter = IntoIter {
607            start: self.inner,
608            i: 0,
609            capacity: self.capacity,
610        };
611
612        mem::forget(self);
613
614        iter
615    }
616}
617
618unsafe impl<V> Sync for NumberKeyMap<V> {}
619unsafe impl<V> Send for NumberKeyMap<V> {}
620
621impl<V> Drop for NumberKeyMap<V> {
622    fn drop(&mut self) {
623        if self.inner.is_null() {
624            return;
625        }
626
627        if mem::needs_drop::<V>() {
628            for i in 0..self.capacity {
629                let slot_ptr = unsafe { self.inner.add(i) };
630                let slot = unsafe { &mut *slot_ptr };
631
632                if slot.key != usize::MAX {
633                    unsafe { (&raw mut slot.value).drop_in_place() };
634                }
635            }
636        }
637
638        let layout = Layout::array::<Slot<V>>(self.capacity).unwrap();
639        unsafe {
640            dealloc(self.inner.cast(), layout);
641        }
642    }
643}
644
645#[cfg(test)]
646mod tests {
647    use super::*;
648
649    use alloc::rc::Rc;
650    #[cfg(feature = "no_std")]
651    use alloc::vec::Vec;
652    use core::cell::Cell;
653
654    #[derive(Debug)]
655    struct DropCounter(usize, Rc<Cell<usize>>);
656
657    impl Drop for DropCounter {
658        fn drop(&mut self) {
659            self.1.set(self.1.get() + 1);
660        }
661    }
662
663    #[test]
664    fn test_number_key_map_insert_and_get() {
665        const N: usize = 1_000_000;
666
667        let mut m = NumberKeyMap::new();
668        let drops = Rc::new(Cell::new(0));
669
670        for i in 0..N {
671            m.insert(i, DropCounter(i, drops.clone())).unwrap();
672
673            assert_eq!(m.get(i).map(|v| v.0), Some(i));
674            assert_eq!(m.get_mut(i).map(|v| v.0), Some(i));
675        }
676
677        for i in 0..N {
678            assert_eq!(m.get(i).map(|v| v.0), Some(i));
679        }
680
681        assert_eq!(drops.get(), 0);
682
683        for i in 0..N / 2 {
684            assert!(m.remove(i).is_some());
685            assert!(m.remove(i).is_none());
686        }
687
688        assert_eq!(drops.get(), N / 2);
689
690        drop(m);
691
692        assert_eq!(drops.get(), N);
693    }
694
695    #[test]
696    fn test_number_key_map_duplicate_key_returns_err() {
697        let mut m = NumberKeyMap::new();
698        let k = 1usize;
699        let drops = Rc::new(Cell::new(0));
700
701        m.insert(k, DropCounter(10, drops.clone())).unwrap();
702        assert!(m.insert(k, DropCounter(20, drops.clone())).is_err());
703
704        // original value remains
705        assert_eq!(m.get(k).map(|v| v.0), Some(10));
706
707        assert_eq!(drops.get(), 1);
708
709        drop(m);
710
711        assert_eq!(drops.get(), 2);
712    }
713
714    #[test]
715    fn test_number_key_map_clear() {
716        let mut m = NumberKeyMap::new();
717        let drops = Rc::new(Cell::new(0));
718
719        for i in 0..1_000_000 {
720            m.insert(i, DropCounter(i, drops.clone())).unwrap();
721        }
722
723        assert_eq!(drops.get(), 0);
724
725        m.clear();
726
727        assert_eq!(drops.get(), 1_000_000);
728
729        m.clear_with(|_| panic!("Not cleared"));
730
731        assert_eq!(drops.get(), 1_000_000);
732    }
733
734    #[test]
735    fn test_number_key_map_iter() {
736        let mut m = NumberKeyMap::new();
737        let drops = Rc::new(Cell::new(0));
738
739        for i in 0..10 {
740            m.insert(i, DropCounter(i, drops.clone())).unwrap();
741        }
742
743        let mut seen = Vec::new();
744        for (k, v) in m.iter() {
745            seen.push((k, v.0));
746        }
747
748        seen.sort_by_key(|x| x.0);
749
750        assert_eq!(seen, (0..10).map(|i| (i, i)).collect::<Vec<_>>());
751        assert_eq!(drops.get(), 0); // iter() should not drop
752    }
753
754    #[test]
755    fn test_number_key_map_iter_mut() {
756        let mut m = NumberKeyMap::new();
757        let drops = Rc::new(Cell::new(0));
758
759        for i in 0..10 {
760            m.insert(i, DropCounter(i, drops.clone())).unwrap();
761        }
762
763        for (_, v) in m.iter_mut() {
764            v.0 *= 2;
765        }
766
767        let mut collected = m.iter().map(|(_, v)| v.0).collect::<Vec<_>>();
768
769        collected.sort_by_key(|x| *x);
770
771        assert_eq!(collected, (0..10).map(|i| i * 2).collect::<Vec<_>>());
772        assert_eq!(drops.get(), 0); // iter_mut() should not drop
773    }
774
775    #[test]
776    fn test_number_key_map_into_iter() {
777        let drops = Rc::new(Cell::new(0));
778        let mut m = NumberKeyMap::new();
779
780        for i in 0..10 {
781            m.insert(i, DropCounter(i, drops.clone())).unwrap();
782        }
783
784        assert_eq!(drops.get(), 0);
785
786        let mut seen = Vec::new();
787        for (k, v) in m {
788            seen.push((k, v.0));
789        }
790
791        // after into_iter, the map is consumed
792        seen.sort_by_key(|x| x.0);
793
794        assert_eq!(seen, (0..10).map(|i| (i, i)).collect::<Vec<_>>());
795
796        // all values must be dropped exactly once
797        assert_eq!(drops.get(), 10);
798    }
799
800    #[test]
801    fn test_number_map_drain() {
802        let drops = Rc::new(Cell::new(0));
803        let mut m = NumberKeyMap::new();
804
805        for i in 0..10 {
806            m.insert(i, DropCounter(i, drops.clone())).unwrap();
807        }
808
809        assert_eq!(drops.get(), 0);
810
811        let mut seen = Vec::new();
812        for (k, v) in m.drain() {
813            seen.push((k, v.0));
814        }
815
816        // after drain, the map is consumed
817        seen.sort_by_key(|x| x.0);
818
819        assert_eq!(seen, (0..10).map(|i| (i, i)).collect::<Vec<_>>());
820
821        drop(m);
822
823        // all values must be dropped exactly once
824        assert_eq!(drops.get(), 10);
825
826        let mut m = NumberKeyMap::new();
827
828        for i in 0..10 {
829            m.insert(i, DropCounter(i, drops.clone())).unwrap();
830        }
831
832        let iter = m.drain();
833
834        #[allow(clippy::drop_non_drop, reason = "It is tested here")]
835        drop(iter);
836
837        assert_eq!(drops.get(), 10);
838    }
839}