2023-11-25 23:43:11 +00:00
|
|
|
use std::ops::Range;
|
|
|
|
|
2023-11-30 04:21:27 +00:00
|
|
|
use crate::{archetype::{Archetype, ArchetypeId}, world::{ArchetypeEntityId, World}};
|
2023-11-25 23:43:11 +00:00
|
|
|
|
|
|
|
use super::{Query, Fetch};
|
|
|
|
|
|
|
|
pub struct View<'a, Q: Query> {
|
2023-11-30 04:21:27 +00:00
|
|
|
world: &'a World,
|
2023-11-25 23:43:11 +00:00
|
|
|
query: Q,
|
|
|
|
archetypes: Vec<&'a Archetype>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a, Q> View<'a, Q>
|
|
|
|
where
|
|
|
|
Q: Query,
|
|
|
|
{
|
2023-11-30 04:21:27 +00:00
|
|
|
pub fn new(world: &'a World, query: Q, archetypes: Vec<&'a Archetype>) -> Self {
|
2023-11-25 23:43:11 +00:00
|
|
|
Self {
|
2023-11-30 04:21:27 +00:00
|
|
|
world,
|
2023-11-25 23:43:11 +00:00
|
|
|
query,
|
|
|
|
archetypes,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a, Q> IntoIterator for View<'a, Q>
|
|
|
|
where
|
|
|
|
Q: Query,
|
|
|
|
{
|
|
|
|
type Item = Q::Item<'a>;
|
|
|
|
|
|
|
|
type IntoIter = ViewIter<'a, Q>;
|
|
|
|
|
|
|
|
fn into_iter(self) -> Self::IntoIter {
|
|
|
|
ViewIter {
|
2023-11-30 04:21:27 +00:00
|
|
|
world: self.world,
|
2023-11-25 23:43:11 +00:00
|
|
|
query: self.query,
|
2023-12-01 04:05:06 +00:00
|
|
|
fetcher: None,
|
2023-11-25 23:43:11 +00:00
|
|
|
archetypes: self.archetypes,
|
|
|
|
next_archetype: 0,
|
|
|
|
component_indices: 0..0,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct ViewIter<'a, Q: Query> {
|
2023-11-30 04:21:27 +00:00
|
|
|
world: &'a World,
|
2023-11-25 23:43:11 +00:00
|
|
|
query: Q,
|
2023-12-01 04:05:06 +00:00
|
|
|
fetcher: Option<Q::Fetch<'a>>,
|
2023-11-25 23:43:11 +00:00
|
|
|
archetypes: Vec<&'a Archetype>,
|
|
|
|
next_archetype: usize,
|
|
|
|
component_indices: Range<u64>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a, Q> Iterator for ViewIter<'a, Q>
|
|
|
|
where
|
|
|
|
Q: Query,
|
|
|
|
{
|
|
|
|
type Item = Q::Item<'a>;
|
|
|
|
|
|
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
|
|
loop {
|
2023-12-01 04:05:06 +00:00
|
|
|
if Q::ALWAYS_FETCHES {
|
|
|
|
// only fetch this query once.
|
|
|
|
// fetcher gets set to Some after this `next` call.
|
|
|
|
if self.fetcher.is_none() {
|
|
|
|
if let Some(mut fetch) = unsafe { self.query.fetch_world(self.world) } {
|
|
|
|
let res = unsafe { Some(fetch.get_item(ArchetypeEntityId(0))) };
|
|
|
|
self.fetcher = Some(fetch);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-25 23:43:11 +00:00
|
|
|
if let Some(entity_index) = self.component_indices.next() {
|
2023-12-01 04:05:06 +00:00
|
|
|
let fetcher = self.fetcher.as_mut().unwrap();
|
2023-11-25 23:43:11 +00:00
|
|
|
let entity_index = ArchetypeEntityId(entity_index);
|
2023-12-01 04:05:06 +00:00
|
|
|
if !fetcher.can_visit_item(entity_index) {
|
2023-11-25 23:43:11 +00:00
|
|
|
continue;
|
|
|
|
} else {
|
2023-12-01 04:05:06 +00:00
|
|
|
let i = unsafe { fetcher.get_item(entity_index) };
|
2023-11-25 23:43:11 +00:00
|
|
|
return Some(i);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if self.next_archetype >= self.archetypes.len() {
|
|
|
|
return None; // ran out of archetypes to go through
|
|
|
|
}
|
|
|
|
|
|
|
|
let arch_id = self.next_archetype;
|
|
|
|
self.next_archetype += 1;
|
|
|
|
let arch = unsafe { self.archetypes.get_unchecked(arch_id) };
|
|
|
|
|
|
|
|
if arch.entities.len() == 0 {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if !self.query.can_visit_archetype(arch) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2023-12-01 04:05:06 +00:00
|
|
|
self.fetcher = unsafe { Some(self.query.fetch(self.world, ArchetypeId(arch_id as u64), arch)) };
|
2023-11-25 23:43:11 +00:00
|
|
|
self.component_indices = 0..arch.entities.len() as u64;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|