use std::marker::PhantomData;
use crate::{
slot::{ArenaSlot, ArenaSlotState},
Arena, Key,
};
pub struct Iter<'a, T> {
next_occupied_slot_index: Option<usize>,
arena: &'a Arena<T>,
}
impl<'a, T> Iter<'a, T> {
pub(super) fn new(arena: &'a Arena<T>) -> Self {
Self {
next_occupied_slot_index: arena.first_occupied_slot_index,
arena,
}
}
}
impl<'a, T> Iterator for Iter<'a, T> {
type Item = (Key, &'a T);
fn next(&mut self) -> Option<Self::Item> {
if let Some(index) = self.next_occupied_slot_index {
let slot = &self.arena.slots[index];
if let ArenaSlotState::Occupied {
data,
next_occupied_slot_index,
..
} = &slot.state
{
self.next_occupied_slot_index = *next_occupied_slot_index;
Some((
Key {
index,
generation: slot.generation,
},
data,
))
} else {
panic!("the iterator should not encounter a free slot");
}
} else {
None
}
}
}
pub struct IterMut<'a, T> {
next_occupied_slot_index: Option<usize>,
slots: *mut [ArenaSlot<T>],
marker: PhantomData<&'a mut Arena<T>>,
}
impl<'a, T> IterMut<'a, T> {
pub(super) fn new(arena: &'a mut Arena<T>) -> Self {
Self {
next_occupied_slot_index: arena.first_occupied_slot_index,
slots: arena.slots.as_mut_slice(),
marker: PhantomData,
}
}
}
impl<'a, T> Iterator for IterMut<'a, T> {
type Item = (Key, &'a mut T);
fn next(&mut self) -> Option<Self::Item> {
if let Some(index) = self.next_occupied_slot_index {
let slot = {
let start_ptr = self.slots.cast::<ArenaSlot<T>>();
let slot_ptr = unsafe { start_ptr.add(index) };
unsafe { slot_ptr.as_mut::<'a>() }.unwrap()
};
if let ArenaSlotState::Occupied {
data,
next_occupied_slot_index,
..
} = &mut slot.state
{
self.next_occupied_slot_index = *next_occupied_slot_index;
Some((
Key {
index,
generation: slot.generation,
},
data,
))
} else {
panic!("the iterator should not encounter a free slot");
}
} else {
None
}
}
}
pub struct DrainFilter<'a, T, F: FnMut(&T) -> bool> {
arena: &'a mut Arena<T>,
filter: F,
next_occupied_slot_index: Option<usize>,
}
impl<'a, T, F: FnMut(&T) -> bool> DrainFilter<'a, T, F> {
pub(super) fn new(arena: &'a mut Arena<T>, filter: F) -> Self {
Self {
next_occupied_slot_index: arena.first_occupied_slot_index,
arena,
filter,
}
}
}
impl<T, F: FnMut(&T) -> bool> Iterator for DrainFilter<'_, T, F> {
type Item = (Key, T);
fn next(&mut self) -> Option<Self::Item> {
while let Some(index) = self.next_occupied_slot_index {
let slot = &mut self.arena.slots[index];
if let ArenaSlotState::Occupied {
data,
next_occupied_slot_index,
..
} = &mut slot.state
{
self.next_occupied_slot_index = *next_occupied_slot_index;
if (self.filter)(data) {
let key = Key {
index,
generation: slot.generation,
};
return self
.arena
.remove_from_slot(index)
.map(|element| (key, element));
}
} else {
panic!("the iterator should not encounter a free slot");
}
}
None
}
}