use std::fmt::{Debug, Formatter};
use std::marker::PhantomData;
use std::ops::Range;
use ouroboros::self_referencing;
use super::source_set::AbstractPropertySource;
use crate::entity::{Entity, EntityId, PopulationIterator};
use crate::hashing::{IndexSet, IndexSetIter};
#[derive(Clone)]
pub(super) struct PopulationRangeIterator<E: Entity> {
range: Range<usize>,
next: usize,
_phantom: PhantomData<E>,
}
impl<E: Entity> PopulationRangeIterator<E> {
pub fn new(range: Range<usize>) -> Self {
Self {
next: range.start,
range,
_phantom: PhantomData,
}
}
#[must_use]
pub fn range(&self) -> Range<usize> {
self.range.clone()
}
pub fn from_population_iterator(iter: PopulationIterator<E>) -> Self {
Self::new(0..iter.population())
}
}
impl<E: Entity> Iterator for PopulationRangeIterator<E> {
type Item = EntityId<E>;
fn next(&mut self) -> Option<Self::Item> {
if self.next < self.range.end {
let current = self.next;
self.next += 1;
Some(EntityId::new(current))
} else {
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let remaining = self.len();
(remaining, Some(remaining))
}
fn count(self) -> usize {
self.len()
}
fn nth(&mut self, n: usize) -> Option<Self::Item> {
self.next = self.next.saturating_add(n).min(self.range.end);
self.next()
}
fn last(self) -> Option<Self::Item>
where
Self: Sized,
{
if self.next < self.range.end {
Some(EntityId::new(self.range.end - 1))
} else {
None
}
}
fn for_each<F>(mut self, mut f: F)
where
F: FnMut(Self::Item),
{
while self.next < self.range.end {
let current = self.next;
self.next += 1;
f(EntityId::new(current));
}
}
fn fold<B, F>(mut self, init: B, mut f: F) -> B
where
F: FnMut(B, Self::Item) -> B,
{
let mut acc = init;
while self.next < self.range.end {
let current = self.next;
self.next += 1;
acc = f(acc, EntityId::new(current));
}
acc
}
}
impl<E: Entity> ExactSizeIterator for PopulationRangeIterator<E> {
fn len(&self) -> usize {
self.range.end.saturating_sub(self.next)
}
}
impl<E: Entity> std::iter::FusedIterator for PopulationRangeIterator<E> {}
#[self_referencing]
pub(super) struct IndexSetIterator<'a, E: Entity> {
index_set: &'a IndexSet<EntityId<E>>,
#[borrows(index_set)]
#[covariant]
iter: IndexSetIter<'this, EntityId<E>>,
}
impl<'a, E: Entity> IndexSetIterator<'a, E> {
pub fn from_index_set(index_set: &'a IndexSet<EntityId<E>>) -> Self {
IndexSetIteratorBuilder {
index_set,
iter_builder: |index_set| index_set.iter(),
}
.build()
}
}
pub(super) enum SourceIterator<'a, E: Entity> {
IndexIter(IndexSetIterator<'a, E>),
PropertyVecIter(Box<dyn AbstractPropertySource<'a, E> + 'a>),
PopulationRange(PopulationRangeIterator<E>),
}
impl<'a, E: Entity> Debug for SourceIterator<'a, E> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
SourceIterator::IndexIter(_iter) => write!(f, "IndexIter"),
SourceIterator::PropertyVecIter(_iter) => write!(f, "PropertyVecIter"),
SourceIterator::PopulationRange(..) => write!(f, "PopulationRange"),
}
}
}
impl<'a, E: Entity> SourceIterator<'a, E> {
#[must_use]
#[inline]
pub(super) fn contains(&self, id: EntityId<E>) -> bool {
match self {
SourceIterator::IndexIter(iter) => {
iter.with_index_set(|index_set| index_set.contains(&id))
}
SourceIterator::PropertyVecIter(source) => source.contains(id),
SourceIterator::PopulationRange(source) => source.range().contains(&id.0),
}
}
}
impl<'a, E: Entity> Iterator for SourceIterator<'a, E> {
type Item = EntityId<E>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
match self {
SourceIterator::IndexIter(index_set_iter) => {
index_set_iter.with_iter_mut(|iter| iter.next().copied())
}
SourceIterator::PropertyVecIter(iter) => iter.next(),
SourceIterator::PopulationRange(iter) => iter.next(),
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
match self {
SourceIterator::IndexIter(iter) => iter.with_iter(|iter| iter.size_hint()),
SourceIterator::PropertyVecIter(iter) => iter.size_hint(),
SourceIterator::PopulationRange(iter) => iter.size_hint(),
}
}
fn count(self) -> usize {
match self {
SourceIterator::IndexIter(mut iter) => iter.with_iter_mut(|iter| iter.count()),
SourceIterator::PropertyVecIter(iter) => iter.count(),
SourceIterator::PopulationRange(iter) => iter.count(),
}
}
fn last(self) -> Option<Self::Item> {
match self {
Self::IndexIter(mut iter) => iter.with_iter_mut(|iter| iter.last().copied()),
Self::PropertyVecIter(iter) => iter.last(),
Self::PopulationRange(iter) => iter.last(),
}
}
#[inline]
fn nth(&mut self, n: usize) -> Option<Self::Item> {
match self {
Self::IndexIter(iter) => iter.with_iter_mut(|iter| iter.nth(n).copied()),
Self::PropertyVecIter(iter) => iter.nth(n),
Self::PopulationRange(iter) => iter.nth(n),
}
}
fn for_each<F>(self, mut f: F)
where
F: FnMut(Self::Item),
{
match self {
Self::IndexIter(mut iter) => {
iter.with_iter_mut(|iter| iter.for_each(|entity_id| f(*entity_id)))
}
Self::PropertyVecIter(iter) => iter.for_each(f),
Self::PopulationRange(iter) => iter.for_each(f),
}
}
fn fold<B, F>(self, init: B, mut f: F) -> B
where
F: FnMut(B, Self::Item) -> B,
{
match self {
Self::IndexIter(mut iter) => {
iter.with_iter_mut(|iter| iter.fold(init, |acc, entity_id| f(acc, *entity_id)))
}
Self::PropertyVecIter(iter) => iter.fold(init, f),
Self::PopulationRange(iter) => iter.fold(init, f),
}
}
}
impl<'c, E: Entity> std::iter::FusedIterator for SourceIterator<'c, E> {}
#[cfg(test)]
mod tests {
use super::super::source_set::{ConcretePropertySource, SourceSet};
use crate::entity::property_value_store_core::RawPropertyValueVec;
use crate::entity::EntityId;
use crate::hashing::IndexSet;
use crate::{define_entity, define_property};
define_entity!(Person);
define_property!(struct Age(u8), Person, default_const = Age(0));
#[test]
fn source_iterator_contains_for_index_source_uses_original_set() {
let values: RawPropertyValueVec<Age> =
[0u8, 3, 2, 3, 4, 5, 3].into_iter().map(Age).collect();
let people_set: IndexSet<EntityId<Person>> = IndexSet::from_iter([
EntityId::new(0),
EntityId::new(2),
EntityId::new(3),
EntityId::new(6),
]);
let people_set_ref = &people_set;
let mut iter = SourceSet::IndexSet(people_set_ref).into_iter();
assert_eq!(iter.next(), Some(EntityId::new(0)));
assert!(iter.contains(EntityId::new(0)));
assert!(iter.contains(EntityId::new(6)));
assert!(!iter.contains(EntityId::new(5)));
let mut property_iter = SourceSet::PropertySet(Box::new(ConcretePropertySource::<
Person,
Age,
>::new(
&values, Age(3u8), 8
)))
.into_iter();
assert_eq!(property_iter.next(), Some(EntityId::new(1)));
assert!(property_iter.contains(EntityId::new(1)));
assert!(property_iter.contains(EntityId::new(3)));
assert!(!property_iter.contains(EntityId::new(4)));
}
#[test]
fn source_iterator_contains_for_empty_population_range() {
let empty_iter = SourceSet::<Person>::PopulationRange(0..0).into_iter();
assert!(!empty_iter.contains(EntityId::new(0)));
}
#[test]
fn source_iterator_contains_for_population_range_uses_original_set() {
let mut iter = SourceSet::<Person>::PopulationRange(3..7).into_iter();
assert_eq!(iter.next(), Some(EntityId::new(3)));
assert!(iter.contains(EntityId::new(3)));
assert!(iter.contains(EntityId::new(6)));
assert!(!iter.contains(EntityId::new(2)));
assert!(!iter.contains(EntityId::new(7)));
assert_eq!(
iter.collect::<Vec<_>>(),
vec![EntityId::new(4), EntityId::new(5), EntityId::new(6)]
);
}
}