summaryrefslogtreecommitdiff
path: root/ecs/src/lib.rs
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2024-02-29 19:57:59 +0100
committerHampusM <hampus@hampusmat.com>2024-02-29 19:58:10 +0100
commit99ea5727ca4638efd2979218a128e56c0ce32c44 (patch)
treef167d9d88ad8b4cfe7089df3cc67e1be9b0f9a06 /ecs/src/lib.rs
parentbd627c91819ea98e551b29027de6eaaccbe45ed6 (diff)
feat(ecs): add iterating over queries non-mutably
Diffstat (limited to 'ecs/src/lib.rs')
-rw-r--r--ecs/src/lib.rs130
1 files changed, 105 insertions, 25 deletions
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<Comps>
+ pub fn iter(&self) -> QueryComponentIter<Comps>
{
QueryComponentIter {
+ entity_iter: self.component_storage.entities.iter(),
+ component_type_ids: Comps::type_ids(),
+ comps_pd: PhantomData,
+ }
+ }
+
+ pub fn iter_mut(&mut self) -> QueryComponentMutIter<Comps>
+ {
+ 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,7 +239,7 @@ impl QueryComponentIds
pub struct QueryComponentIter<'world, Comps>
{
- entity_iter: SliceIterMut<'world, Entity>,
+ entity_iter: SliceIter<'world, Entity>,
component_type_ids: Vec<TypeId>,
comps_pd: PhantomData<Comps>,
}
@@ -226,33 +248,91 @@ impl<'world, Comps> Iterator for QueryComponentIter<'world, Comps>
where
Comps: ComponentSequence + 'world,
{
+ type Item = Comps::Refs<'world>;
+
+ fn next(&mut self) -> Option<Self::Item>
+ {
+ 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<TypeId>,
+ comps_pd: PhantomData<Comps>,
+}
+
+impl<'world, Comps> Iterator for QueryComponentMutIter<'world, Comps>
+where
+ Comps: ComponentSequence + 'world,
+{
type Item = Comps::MutRefs<'world>;
fn next(&mut self) -> Option<Self::Item>
{
- // 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<dyn Component>];
+}
+
+impl EntityRef for &Entity
+{
+ fn components(&self) -> &[Box<dyn Component>]
+ {
+ &self.components
}
}
+impl EntityRef for &mut Entity
+{
+ fn components(&self) -> &[Box<dyn Component>]
+ {
+ &self.components
+ }
+}
+
+fn find_entity_with_components<EntityRefT>(
+ entity_iter: &mut impl Iterator<Item = EntityRefT>,
+ component_type_ids: &[TypeId],
+) -> Option<EntityRefT>
+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
{