lyra-engine/lyra-ecs/src/query/view.rs

175 lines
5.2 KiB
Rust
Raw Normal View History

2023-11-25 23:43:11 +00:00
use std::ops::Range;
use crate::{archetype::Archetype, world::{ArchetypeEntityId, World}, EntityId, Tick};
2023-11-25 23:43:11 +00:00
use super::{Query, Fetch, AsQuery};
2023-11-25 23:43:11 +00:00
2024-03-03 01:20:38 +00:00
pub type View<'a, Q, F = ()> = ViewState<'a, <Q as AsQuery>::Query, <F as AsQuery>::Query>;
pub struct ViewState<'a, Q: Query, F: Query> {
2023-11-30 04:21:27 +00:00
world: &'a World,
2024-03-03 01:20:38 +00:00
query: Q,
filter: F,
2023-11-25 23:43:11 +00:00
archetypes: Vec<&'a Archetype>,
}
2024-03-03 01:20:38 +00:00
impl<'a, Q, F> ViewState<'a, Q, F>
2023-11-25 23:43:11 +00:00
where
2024-03-03 01:20:38 +00:00
Q: Query,
F: Query,
2023-11-25 23:43:11 +00:00
{
2024-03-03 01:20:38 +00:00
pub fn new(world: &'a World, query: Q, filter: F, 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,
2024-03-03 01:20:38 +00:00
filter,
2023-11-25 23:43:11 +00:00
archetypes,
}
}
2024-03-03 01:20:38 +00:00
/// Converts self into an iterator
pub fn iter(self) -> ViewIter<'a, Q, F> {
self.into_iter()
}
/// Consumes `self`, adding a query to the view.
pub fn expand<U: AsQuery>(self, query: U::Query) -> ViewState<'a, (Q, U::Query), F> {
ViewState::new(self.world, (self.query, query), self.filter, self.archetypes)
}
/// Consumes `self`, adding a filter to the view.
pub fn with<U: AsQuery>(self, filter: U::Query) -> ViewState<'a, Q, (F, U::Query)> {
ViewState::new(self.world, self.query, (self.filter, filter), self.archetypes)
}
2023-11-25 23:43:11 +00:00
}
2024-03-03 01:20:38 +00:00
impl<'a, Q, F> IntoIterator for ViewState<'a, Q, F>
2023-11-25 23:43:11 +00:00
where
2024-03-03 01:20:38 +00:00
Q: Query,
F: Query,
2023-11-25 23:43:11 +00:00
{
2024-03-03 01:20:38 +00:00
type Item = Q::Item<'a>;
2023-11-25 23:43:11 +00:00
2024-03-03 01:20:38 +00:00
type IntoIter = ViewIter<'a, Q, F>;
2023-11-25 23:43:11 +00:00
fn into_iter(self) -> Self::IntoIter {
2024-03-03 01:20:38 +00:00
let tick = self.world.tick_tracker().tick_when(Q::MUTATES);
2023-12-26 19:12:53 +00:00
2023-11-25 23:43:11 +00:00
ViewIter {
2023-11-30 04:21:27 +00:00
world: self.world,
2023-12-26 19:12:53 +00:00
tick,
2023-11-25 23:43:11 +00:00
query: self.query,
2024-03-03 01:20:38 +00:00
filter: self.filter,
fetcher: None,
2024-03-03 01:20:38 +00:00
filter_fetcher: None,
2023-11-25 23:43:11 +00:00
archetypes: self.archetypes,
next_archetype: 0,
component_indices: 0..0,
}
}
}
2024-03-03 01:20:38 +00:00
pub struct ViewIter<'a, Q: Query, F: Query> {
2023-11-30 04:21:27 +00:00
world: &'a World,
2023-12-26 19:12:53 +00:00
tick: Tick,
2023-11-25 23:43:11 +00:00
query: Q,
2024-03-03 01:20:38 +00:00
filter: F,
fetcher: Option<Q::Fetch<'a>>,
2024-03-03 01:20:38 +00:00
filter_fetcher: Option<F::Fetch<'a>>,
2023-11-25 23:43:11 +00:00
archetypes: Vec<&'a Archetype>,
next_archetype: usize,
component_indices: Range<u64>,
}
2024-03-03 01:20:38 +00:00
impl<'a, Q, F> Iterator for ViewIter<'a, Q, F>
2023-11-25 23:43:11 +00:00
where
Q: Query,
2024-03-03 01:20:38 +00:00
F: Query,
2023-11-25 23:43:11 +00:00
{
type Item = Q::Item<'a>;
fn next(&mut self) -> Option<Self::Item> {
loop {
2024-03-08 05:19:23 +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() {
let fetcher = self.fetcher.as_mut().unwrap();
2024-03-03 01:20:38 +00:00
let filter_fetcher = self.filter_fetcher.as_mut().unwrap();
2023-11-25 23:43:11 +00:00
let entity_index = ArchetypeEntityId(entity_index);
2024-03-03 01:20:38 +00:00
if fetcher.can_visit_item(entity_index) && filter_fetcher.can_visit_item(entity_index) {
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) };
2024-03-03 02:20:19 +00:00
if arch.entity_ids.is_empty() {
2023-11-25 23:43:11 +00:00
continue;
}
2024-03-03 01:20:38 +00:00
if self.query.can_visit_archetype(arch) && self.filter.can_visit_archetype(arch) {
unsafe {
self.fetcher = Some(self.query.fetch(self.world, arch, self.tick));
self.filter_fetcher = Some(self.filter.fetch(self.world, arch, self.tick));
}
2024-03-03 02:20:19 +00:00
self.component_indices = 0..arch.entity_ids.len() as u64;
2023-11-25 23:43:11 +00:00
}
}
}
}
}
pub struct ViewOne<'a, Q: Query> {
world: &'a World,
2023-12-26 19:12:53 +00:00
tick: Tick,
entity: EntityId,
query: Q,
}
impl<'a, Q: Query> ViewOne<'a, Q> {
pub fn new(world: &'a World, entity: EntityId, query: Q) -> Self {
2023-12-26 19:12:53 +00:00
let tick = world.tick_tracker().tick_when(Q::MUTATES);
Self {
world,
2023-12-26 19:12:53 +00:00
tick,
entity,
query
}
}
pub fn get(&self) -> Option<Q::Item<'a>> {
if let Some(record) = self.world.entities.arch_index.get(&self.entity) {
let arch = self.world.archetypes.get(&record.id)
.expect("An invalid record was specified for an entity");
if self.query.can_visit_archetype(arch) {
2023-12-26 19:12:53 +00:00
let mut fetch = unsafe { self.query.fetch(self.world, arch, self.tick) };
if fetch.can_visit_item(record.index) {
return Some(unsafe { fetch.get_item(record.index) });
}
}
}
None
}
2023-11-25 23:43:11 +00:00
}