use super::OrdMap;
use core::{
iter::FusedIterator,
mem::{ManuallyDrop, MaybeUninit},
ops::Range,
ptr,
};
#[derive(Debug)]
pub struct IntoIter<K, V, const N: usize> {
keys: [MaybeUninit<K>; N],
values: [MaybeUninit<V>; N],
range: Range<usize>,
}
impl<K, V, const N: usize> IntoIter<K, V, N> {
pub(super) fn new(map: OrdMap<K, V, N>) -> Self {
let map = ManuallyDrop::new(map);
let keys = unsafe { (&map.keys as *const [MaybeUninit<K>; N]).read() };
let values = unsafe { (&map.values as *const [MaybeUninit<V>; N]).read() };
Self {
keys,
values,
range: 0..map.len,
}
}
fn read(&mut self, index: usize) -> (K, V) {
let maybe_uninit_key = &self.keys[index];
let key = unsafe { maybe_uninit_key.assume_init_read() };
let maybe_uninit_value = &self.values[index];
let value = unsafe { maybe_uninit_value.assume_init_read() };
(key, value)
}
}
impl<K, V, const N: usize> Iterator for IntoIter<K, V, N> {
type Item = (K, V);
fn next(&mut self) -> Option<Self::Item> {
self.range.next().map(|index| self.read(index))
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.range.size_hint()
}
}
impl<K, V, const N: usize> DoubleEndedIterator for IntoIter<K, V, N> {
fn next_back(&mut self) -> Option<Self::Item> {
self.range.next_back().map(|index| self.read(index))
}
}
impl<K, V, const N: usize> ExactSizeIterator for IntoIter<K, V, N> {}
impl<K, V, const N: usize> FusedIterator for IntoIter<K, V, N> {}
impl<K, V, const N: usize> Drop for IntoIter<K, V, N> {
fn drop(&mut self) {
if self.range.is_empty() {
return;
}
let key_slice = {
let ptr = self.keys.as_mut_ptr() as *mut K;
let ptr = unsafe { ptr.add(self.range.start) };
ptr::slice_from_raw_parts_mut(ptr, self.range.len())
};
let value_slice = {
let ptr = self.values.as_mut_ptr() as *mut V;
let ptr = unsafe { ptr.add(self.range.start) };
ptr::slice_from_raw_parts_mut(ptr, self.range.len())
};
unsafe {
ptr::drop_in_place(key_slice);
ptr::drop_in_place(value_slice);
}
}
}