summaryrefslogtreecommitdiff
path: root/ecs/src/query.rs
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2024-11-03 21:12:57 +0100
committerHampusM <hampus@hampusmat.com>2024-11-03 21:12:57 +0100
commitcaef866b4e3f87fd6ae2dd5b979a1fe1a1f3e5f2 (patch)
treefa390998ff41b11bb0e60298a81f45619fbe4d69 /ecs/src/query.rs
parent373a0d53f31b838b3f650a37df39176a31a6c1c4 (diff)
feat(ecs): add read-only query iterating
Diffstat (limited to 'ecs/src/query.rs')
-rw-r--r--ecs/src/query.rs95
1 files changed, 89 insertions, 6 deletions
diff --git a/ecs/src/query.rs b/ecs/src/query.rs
index d0fa872..e7fd7a6 100644
--- a/ecs/src/query.rs
+++ b/ecs/src/query.rs
@@ -10,16 +10,20 @@ use crate::component::storage::{
EntityIter,
Storage as ComponentStorage,
};
-use crate::component::{Metadata as ComponentMetadata, Sequence as ComponentSequence};
+use crate::component::{
+ Component,
+ Metadata as ComponentMetadata,
+ Sequence as ComponentSequence,
+};
use crate::entity::Uid as EntityUid;
-use crate::lock::ReadGuard;
+use crate::lock::{ReadGuard, WriteGuard};
use crate::query::options::Options;
use crate::system::{
NoInitParamFlag as NoInitSystemParamFlag,
Param as SystemParam,
System,
};
-use crate::World;
+use crate::{EntityComponent, World};
pub mod options;
@@ -40,6 +44,28 @@ where
{
/// Iterates over the entities matching this query.
#[must_use]
+ pub fn iter_mut(
+ &'world self,
+ ) -> ComponentIterMut<'world, Comps, QueryEntityIter<'world>>
+ {
+ #[cfg(feature = "debug")]
+ tracing::debug!("Searching for {}", std::any::type_name::<Comps>());
+
+ #[allow(clippy::map_flatten)]
+ ComponentIterMut {
+ world: self.world,
+ entities: self
+ .component_storage
+ .find_entities(Comps::metadata())
+ .map(Archetype::entities as ComponentIterMapFn)
+ .flatten()
+ .filter(|entity| OptionsT::entity_filter(entity.components())),
+ comps_pd: PhantomData,
+ }
+ }
+
+ /// Iterates over the entities matching this query.
+ #[must_use]
pub fn iter(&'world self) -> ComponentIter<'world, Comps, QueryEntityIter<'world>>
{
#[cfg(feature = "debug")]
@@ -91,12 +117,12 @@ where
Comps: ComponentSequence,
OptionsT: Options,
{
- type IntoIter = ComponentIter<'world, Comps, QueryEntityIter<'world>>;
- type Item = Comps::Refs<'world>;
+ type IntoIter = ComponentIterMut<'world, Comps, QueryEntityIter<'world>>;
+ type Item = Comps::MutRefs<'world>;
fn into_iter(self) -> Self::IntoIter
{
- self.iter()
+ self.iter_mut()
}
}
@@ -152,6 +178,47 @@ type QueryEntityIter<'world> = Filter<
ComponentIterFilterFn,
>;
+pub struct ComponentIterMut<'world, Comps, EntityIter>
+where
+ EntityIter: Iterator<Item = &'world ArchetypeEntity>,
+{
+ world: &'world World,
+ entities: EntityIter,
+ comps_pd: PhantomData<Comps>,
+}
+
+impl<'world, Comps, EntityIter> Iterator for ComponentIterMut<'world, Comps, EntityIter>
+where
+ Comps: ComponentSequence + 'world,
+ EntityIter: Iterator<Item = &'world ArchetypeEntity>,
+{
+ type Item = Comps::MutRefs<'world>;
+
+ fn next(&mut self) -> Option<Self::Item>
+ {
+ Some(Comps::from_components_mut(
+ self.entities.next()?.components().iter(),
+ self.world,
+ lock_component_rw,
+ ))
+ }
+}
+
+fn lock_component_rw(
+ entity_component: &EntityComponent,
+) -> WriteGuard<'_, Box<dyn Component>>
+{
+ entity_component
+ .component
+ .write_nonblock()
+ .unwrap_or_else(|_| {
+ panic!(
+ "Failed to acquire read-write lock to component {}",
+ entity_component.name
+ );
+ })
+}
+
pub struct ComponentIter<'world, Comps, EntityIter>
where
EntityIter: Iterator<Item = &'world ArchetypeEntity>,
@@ -173,10 +240,26 @@ where
Some(Comps::from_components(
self.entities.next()?.components().iter(),
self.world,
+ lock_component_ro,
))
}
}
+fn lock_component_ro(
+ entity_component: &EntityComponent,
+) -> ReadGuard<'_, Box<dyn Component>>
+{
+ entity_component
+ .component
+ .read_nonblock()
+ .unwrap_or_else(|_| {
+ panic!(
+ "Failed to acquire read-write lock to component {}",
+ entity_component.name
+ );
+ })
+}
+
#[derive(Debug)]
struct QueryComponentIds
{