From 99ea5727ca4638efd2979218a128e56c0ce32c44 Mon Sep 17 00:00:00 2001 From: HampusM Date: Thu, 29 Feb 2024 19:57:59 +0100 Subject: feat(ecs): add iterating over queries non-mutably --- ecs/src/lib.rs | 130 ++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 105 insertions(+), 25 deletions(-) (limited to 'ecs/src/lib.rs') diff --git a/ecs/src/lib.rs b/ecs/src/lib.rs index 4e3e4a1..3c59554 100644 --- a/ecs/src/lib.rs +++ b/ecs/src/lib.rs @@ -5,7 +5,7 @@ use std::collections::{HashMap, HashSet}; use std::fmt::Debug; use std::hash::Hash; use std::marker::PhantomData; -use std::slice::IterMut as SliceIterMut; +use std::slice::{Iter as SliceIter, IterMut as SliceIterMut}; use crate::component::{Component, Sequence as ComponentSequence}; use crate::system::{ @@ -128,9 +128,18 @@ impl<'world, Comps> Query<'world, Comps> where Comps: ComponentSequence, { - pub fn iter_mut(&mut self) -> QueryComponentIter + pub fn iter(&self) -> QueryComponentIter { QueryComponentIter { + entity_iter: self.component_storage.entities.iter(), + component_type_ids: Comps::type_ids(), + comps_pd: PhantomData, + } + } + + pub fn iter_mut(&mut self) -> QueryComponentMutIter + { + QueryComponentMutIter { entity_iter: self.component_storage.entities.iter_mut(), component_type_ids: Comps::type_ids(), comps_pd: PhantomData, @@ -138,11 +147,24 @@ where } } -impl<'world, Comps> IntoIterator for &'world mut Query<'world, Comps> +impl<'world, Comps> IntoIterator for &'world Query<'world, Comps> where - Comps: ComponentSequence + 'world, + Comps: ComponentSequence, { type IntoIter = QueryComponentIter<'world, Comps>; + type Item = Comps::Refs<'world>; + + fn into_iter(self) -> Self::IntoIter + { + self.iter() + } +} + +impl<'world, Comps> IntoIterator for &'world mut Query<'world, Comps> +where + Comps: ComponentSequence, +{ + type IntoIter = QueryComponentMutIter<'world, Comps>; type Item = Comps::MutRefs<'world>; fn into_iter(self) -> Self::IntoIter @@ -217,12 +239,36 @@ impl QueryComponentIds pub struct QueryComponentIter<'world, Comps> { - entity_iter: SliceIterMut<'world, Entity>, + entity_iter: SliceIter<'world, Entity>, component_type_ids: Vec, comps_pd: PhantomData, } impl<'world, Comps> Iterator for QueryComponentIter<'world, Comps> +where + Comps: ComponentSequence + 'world, +{ + type Item = Comps::Refs<'world>; + + fn next(&mut self) -> Option + { + let matching_entity = find_entity_with_components::<&Entity>( + &mut self.entity_iter, + &self.component_type_ids, + )?; + + Some(Comps::from_components(&matching_entity.components)) + } +} + +pub struct QueryComponentMutIter<'world, Comps> +{ + entity_iter: SliceIterMut<'world, Entity>, + component_type_ids: Vec, + comps_pd: PhantomData, +} + +impl<'world, Comps> Iterator for QueryComponentMutIter<'world, Comps> where Comps: ComponentSequence + 'world, { @@ -230,29 +276,63 @@ where fn next(&mut self) -> Option { - // TODO: This is a really dumb and slow way to do this. Refactor the world - // to store components in archetypes - let entity = - self.entity_iter.find(|entity| { - let entity_components: HashSet<_> = entity - .components - .iter() - .map(|component| component.as_ref().type_id()) - .collect(); - - if self.component_type_ids.iter().all(|component_type_id| { - entity_components.contains(component_type_id) - }) { - return true; - } - - false - })?; - - Some(Comps::from_components(&mut entity.components)) + let matching_entity = find_entity_with_components::<&mut Entity>( + &mut self.entity_iter, + &self.component_type_ids, + )?; + + Some(Comps::from_components_mut(&mut matching_entity.components)) + } +} + +trait EntityRef +{ + fn components(&self) -> &[Box]; +} + +impl EntityRef for &Entity +{ + fn components(&self) -> &[Box] + { + &self.components } } +impl EntityRef for &mut Entity +{ + fn components(&self) -> &[Box] + { + &self.components + } +} + +fn find_entity_with_components( + entity_iter: &mut impl Iterator, + component_type_ids: &[TypeId], +) -> Option +where + EntityRefT: EntityRef, +{ + // TODO: This is a really dumb and slow way to do this. Refactor the world + // to store components in archetypes + entity_iter.find(|entity| { + let entity_components: HashSet<_> = entity + .components() + .iter() + .map(|component| component.as_ref().type_id()) + .collect(); + + if component_type_ids + .iter() + .all(|component_type_id| entity_components.contains(component_type_id)) + { + return true; + } + + false + }) +} + #[derive(Debug)] pub struct ComponentStorage { -- cgit v1.2.3-18-g5258