use crate::ecs::archetype::{Archetype, ArchetypeId};
use crate::ecs::component::{Component, ComponentIdRegistry};
use crate::ecs::entity::Entity;
use crate::ecs::universe::Universe;
pub trait QueryFilter {
fn query_mask(registry: &ComponentIdRegistry) -> ArchetypeId;
}
impl QueryFilter for () {
fn query_mask(_registry: &ComponentIdRegistry) -> ArchetypeId {
ArchetypeId::empty()
}
}
macro_rules! impl_query_filter {
($( ($($T:ident),+) ),+) => {
$(
#[allow(unused_parens)]
impl<$($T: Component),+> QueryFilter for ($(& $T),+) {
fn query_mask(registry: &ComponentIdRegistry) -> ArchetypeId {
let mut mask = ArchetypeId::empty();
$(mask.set(registry.id_for::<$T>());)+
mask
}
}
#[allow(unused_parens)]
impl<$($T: Component),+> QueryFilter for ($(&mut $T),+) {
fn query_mask(registry: &ComponentIdRegistry) -> ArchetypeId {
let mut mask = ArchetypeId::empty();
$(mask.set(registry.id_for::<$T>());)+
mask
}
}
)+
};
}
impl_query_filter!(
(A), (A, B), (A, B, C), (A, B, C, D),
(A, B, C, D, E), (A, B, C, D, E, F),
(A, B, C, D, E, F, G), (A, B, C, D, E, F, G, H),
(A, B, C, D, E, F, G, H, I), (A, B, C, D, E, F, G, H, I, J),
(A, B, C, D, E, F, G, H, I, J, K), (A, B, C, D, E, F, G, H, I, J, K, L),
(A, B, C, D, E, F, G, H, I, J, K, L, M), (A, B, C, D, E, F, G, H, I, J, K, L, M, N),
(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O), (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P)
);
impl<A: Component, B: Component> QueryFilter for (&A, &mut B) {
fn query_mask(registry: &ComponentIdRegistry) -> ArchetypeId {
let mut mask = ArchetypeId::empty();
mask.set(registry.id_for::<A>());
mask.set(registry.id_for::<B>());
mask
}
}
impl<A: Component, B: Component> QueryFilter for (&mut A, &B) {
fn query_mask(registry: &ComponentIdRegistry) -> ArchetypeId {
let mut mask = ArchetypeId::empty();
mask.set(registry.id_for::<A>());
mask.set(registry.id_for::<B>());
mask
}
}
pub trait QueryFetch {
type Item<'a>;
fn fetch<'a>(arch: &'a Archetype, index: usize, registry: &ComponentIdRegistry) -> Option<Self::Item<'a>>;
}
macro_rules! impl_query_fetch {
($($T:ident),+) => {
#[allow(unused_parens, non_snake_case)]
impl<$($T: Component),+> QueryFetch for ($(&$T),+) {
type Item<'a> = (Entity, $(&'a $T),+);
fn fetch<'a>(
arch: &'a Archetype, index: usize, registry: &ComponentIdRegistry,
) -> Option<Self::Item<'a>> {
let entity = arch.entity_at(index)?;
$(let $T = arch.get_comp::<$T>(index, registry)?;)+
Some((entity, $($T),+))
}
}
};
}
impl_query_fetch!(A);
impl_query_fetch!(A, B);
impl_query_fetch!(A, B, C);
impl_query_fetch!(A, B, C, D);
impl_query_fetch!(A, B, C, D, E);
impl_query_fetch!(A, B, C, D, E, F);
impl_query_fetch!(A, B, C, D, E, F, G);
impl_query_fetch!(A, B, C, D, E, F, G, H);
impl_query_fetch!(A, B, C, D, E, F, G, H, I);
impl_query_fetch!(A, B, C, D, E, F, G, H, I, J);
impl_query_fetch!(A, B, C, D, E, F, G, H, I, J, K);
impl_query_fetch!(A, B, C, D, E, F, G, H, I, J, K, L);
impl_query_fetch!(A, B, C, D, E, F, G, H, I, J, K, L, M);
impl_query_fetch!(A, B, C, D, E, F, G, H, I, J, K, L, M, N);
impl_query_fetch!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
impl_query_fetch!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
pub trait QueryFetchMut {
type Item<'a>;
fn fetch_mut<'a>(arch: &'a mut Archetype, index: usize, registry: &ComponentIdRegistry) -> Option<Self::Item<'a>>;
}
macro_rules! impl_query_fetch_mut_all {
($($T:ident),+) => {
#[allow(unused_parens, non_snake_case)]
impl<$($T: Component),+> QueryFetchMut for ($(&mut $T),+) {
type Item<'a> = (Entity, $(&'a mut $T),+);
fn fetch_mut<'a>(
arch: &'a mut Archetype, index: usize, registry: &ComponentIdRegistry,
) -> Option<Self::Item<'a>> {
let entity = arch.entity_at(index)?;
let arch_ptr = arch as *mut Archetype;
$(let $T = unsafe { (*arch_ptr).get_comp_mut::<$T>(index, registry)? as *mut $T };)+
Some((entity, $(unsafe { &mut *$T }),+))
}
}
};
}
impl_query_fetch_mut_all!(A);
impl_query_fetch_mut_all!(A, B);
impl_query_fetch_mut_all!(A, B, C);
impl_query_fetch_mut_all!(A, B, C, D);
impl_query_fetch_mut_all!(A, B, C, D, E);
impl_query_fetch_mut_all!(A, B, C, D, E, F);
impl_query_fetch_mut_all!(A, B, C, D, E, F, G);
impl_query_fetch_mut_all!(A, B, C, D, E, F, G, H);
impl_query_fetch_mut_all!(A, B, C, D, E, F, G, H, I);
impl_query_fetch_mut_all!(A, B, C, D, E, F, G, H, I, J);
impl_query_fetch_mut_all!(A, B, C, D, E, F, G, H, I, J, K);
impl_query_fetch_mut_all!(A, B, C, D, E, F, G, H, I, J, K, L);
impl_query_fetch_mut_all!(A, B, C, D, E, F, G, H, I, J, K, L, M);
impl_query_fetch_mut_all!(A, B, C, D, E, F, G, H, I, J, K, L, M, N);
impl_query_fetch_mut_all!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
impl_query_fetch_mut_all!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
impl<A: Component, B: Component> QueryFetchMut for (&A, &mut B) {
type Item<'a> = (Entity, &'a A, &'a mut B);
fn fetch_mut<'a>(arch: &'a mut Archetype, index: usize, registry: &ComponentIdRegistry) -> Option<Self::Item<'a>> {
let entity = arch.entity_at(index)?;
let arch_ptr = arch as *mut Archetype;
let a = unsafe { (*arch_ptr).get_comp::<A>(index, registry)? as *const A };
let b = unsafe { (*arch_ptr).get_comp_mut::<B>(index, registry)? as *mut B };
Some((entity, unsafe { &*a }, unsafe { &mut *b }))
}
}
impl<A: Component, B: Component> QueryFetchMut for (&mut A, &B) {
type Item<'a> = (Entity, &'a mut A, &'a B);
fn fetch_mut<'a>(arch: &'a mut Archetype, index: usize, registry: &ComponentIdRegistry) -> Option<Self::Item<'a>> {
let entity = arch.entity_at(index)?;
let arch_ptr = arch as *mut Archetype;
let a = unsafe { (*arch_ptr).get_comp_mut::<A>(index, registry)? as *mut A };
let b = unsafe { (*arch_ptr).get_comp::<B>(index, registry)? as *const B };
Some((entity, unsafe { &mut *a }, unsafe { &*b }))
}
}
pub struct QueryIter<'q, Q: QueryFilter + QueryFetch> {
archetypes: Vec<&'q Archetype>,
registry: &'q ComponentIdRegistry,
arch_idx: usize,
row: usize,
_marker: std::marker::PhantomData<Q>,
}
impl<'q, Q: QueryFilter + QueryFetch> QueryIter<'q, Q> {
pub fn new(universe: &'q Universe) -> Self {
let mask = Q::query_mask(universe.registry());
let archetypes: Vec<&Archetype> = universe
.archetypes()
.filter(|a| a.id().contains_all(&mask))
.collect();
Self {
archetypes,
registry: universe.registry(),
arch_idx: 0,
row: 0,
_marker: std::marker::PhantomData,
}
}
}
impl<'q, Q: QueryFilter + QueryFetch> Iterator for QueryIter<'q, Q> {
type Item = Q::Item<'q>;
fn next(&mut self) -> Option<Self::Item> {
loop {
let arch = self.archetypes.get(self.arch_idx)?;
if self.row < arch.len() {
let item = Q::fetch(arch, self.row, self.registry);
self.row += 1;
return item;
}
self.arch_idx += 1;
self.row = 0;
}
}
}
pub struct QueryIterMut<'q, Q: QueryFilter + QueryFetchMut> {
universe: &'q mut Universe,
arch_ids: Vec<ArchetypeId>,
arch_idx: usize,
row: usize,
_marker: std::marker::PhantomData<Q>,
}
impl<'q, Q: QueryFilter + QueryFetchMut> QueryIterMut<'q, Q> {
pub fn new(universe: &'q mut Universe) -> Self {
let mask = Q::query_mask(universe.registry());
let arch_ids: Vec<ArchetypeId> = universe
.archetypes()
.filter(|a| a.id().contains_all(&mask))
.map(|a| a.id().clone())
.collect();
Self {
universe,
arch_ids,
arch_idx: 0,
row: 0,
_marker: std::marker::PhantomData,
}
}
pub fn for_each<F>(mut self, mut f: F)
where
F: FnMut(&mut Universe, Entity),
{
while self.arch_idx < self.arch_ids.len() {
let arch_id = &self.arch_ids[self.arch_idx];
let (entity, next_row) = {
let arch = match self.universe.get_archetype_mut(arch_id) {
Some(a) => a,
None => {
self.arch_idx += 1;
self.row = 0;
continue;
}
};
if self.row >= arch.len() {
self.arch_idx += 1;
self.row = 0;
continue;
}
let entity = arch.entity_at(self.row).unwrap();
let next_row = self.row + 1;
(entity, next_row)
};
self.row = next_row;
f(&mut self.universe, entity);
}
}
}
impl Universe {
pub fn query<Q: QueryFilter + QueryFetch>(&self) -> QueryIter<'_, Q> {
QueryIter::new(self)
}
pub fn query_mut<Q: QueryFilter + QueryFetchMut>(&mut self) -> QueryIterMut<'_, Q> {
QueryIterMut::new(self)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::ecs::component::Component;
#[derive(Debug, Clone, PartialEq)]
struct Pos(i32, i32);
impl Component for Pos {}
#[derive(Debug, Clone, PartialEq)]
struct Vel(i32, i32);
impl Component for Vel {}
#[test]
fn query_iter() {
let mut u = Universe::new();
u.spawn((Pos(1, 2), Vel(3, 4)));
u.spawn((Pos(5, 6), Vel(7, 8)));
let count = u.query::<(&Pos, &Vel)>().count();
assert_eq!(count, 2);
}
#[test]
fn query_mut_for_each() {
let mut u = Universe::new();
u.spawn((Pos(1, 2), Vel(3, 4)));
u.query_mut::<(&Pos, &mut Vel)>().for_each(|universe, e| {
if let Some(v) = universe.get_mut::<Vel>(e) {
v.0 += 1;
}
});
assert_eq!(
u.query::<(&Pos, &Vel)>().next().map(|(_, _, v)| v.0),
Some(4)
);
}
}