From 3e509487b6f241f60c77bf3eb62c79a8aafa1143 Mon Sep 17 00:00:00 2001
From: HampusM <hampus@hampusmat.com>
Date: Fri, 10 Jan 2025 20:47:48 +0100
Subject: feat(ecs): add support for custom inner ComponentIter iter

---
 ecs/src/query.rs          | 52 +++++++++++++++++++++++++++++++++++++++--------
 ecs/src/query/flexible.rs |  2 +-
 2 files changed, 44 insertions(+), 10 deletions(-)

diff --git a/ecs/src/query.rs b/ecs/src/query.rs
index 2f8b285..8c1ede5 100644
--- a/ecs/src/query.rs
+++ b/ecs/src/query.rs
@@ -1,7 +1,11 @@
 use std::marker::PhantomData;
 
 use crate::component::RefSequence as ComponentRefSequence;
-use crate::query::flexible::{Iter as FlexibleQueryIter, Query as FlexibleQuery};
+use crate::query::flexible::{
+    EntityHandle,
+    Iter as FlexibleQueryIter,
+    Query as FlexibleQuery,
+};
 use crate::query::options::Options;
 use crate::system::{Param as SystemParam, System};
 use crate::uid::Uid;
@@ -27,12 +31,13 @@ where
 {
     /// Iterates over the entities matching this query.
     #[must_use]
-    pub fn iter<'query>(&'query self) -> ComponentIter<'query, 'world, Comps>
+    pub fn iter<'query>(
+        &'query self,
+    ) -> ComponentIter<'query, 'world, Comps, FlexibleQueryIter<'query>>
     {
         #[cfg(feature = "debug")]
         tracing::debug!("Searching for {}", std::any::type_name::<Comps>());
 
-        #[allow(clippy::map_flatten)]
         ComponentIter {
             world: self.world,
             iter: self.inner.iter::<OptionsT>(),
@@ -40,6 +45,29 @@ where
         }
     }
 
+    /// Iterates over the entities matching this query using the iterator returned by
+    /// `func`.
+    ///
+    /// This function exists so that a custom [`EntityHandle`] iterator can be given to
+    /// [`ComponentIter`] without giving the user access to a reference to the [`World`].
+    #[must_use]
+    pub fn iter_with<'query, OutIter>(
+        &'query self,
+        func: impl FnOnce(FlexibleQueryIter<'query>) -> OutIter,
+    ) -> ComponentIter<'query, 'world, Comps, OutIter>
+    where
+        OutIter: Iterator<Item = EntityHandle<'query>>,
+    {
+        #[cfg(feature = "debug")]
+        tracing::debug!("Searching for {}", std::any::type_name::<Comps>());
+
+        ComponentIter {
+            world: self.world,
+            iter: func(self.inner.iter::<OptionsT>()),
+            comps_pd: PhantomData,
+        }
+    }
+
     /// Returns the UID of the entity at the given query iteration index.
     #[must_use]
     pub fn get_entity_uid(&self, entity_index: usize) -> Option<Uid>
@@ -63,7 +91,7 @@ where
     Comps: ComponentRefSequence + 'world,
     OptionsT: Options,
 {
-    type IntoIter = ComponentIter<'query, 'world, Comps>;
+    type IntoIter = ComponentIter<'query, 'world, Comps, FlexibleQueryIter<'query>>;
     type Item = Comps::Handles<'query>;
 
     fn into_iter(self) -> Self::IntoIter
@@ -95,27 +123,33 @@ where
     }
 }
 
-pub struct ComponentIter<'query, 'world, Comps>
+pub struct ComponentIter<'query, 'world, Comps, EntityHandleIter>
+where
+    EntityHandleIter: Iterator<Item = EntityHandle<'query>>,
 {
     world: &'world World,
-    iter: FlexibleQueryIter<'query>,
+    iter: EntityHandleIter,
     comps_pd: PhantomData<Comps>,
 }
 
-impl<'query, 'world, Comps> ComponentIter<'query, 'world, Comps>
+impl<'query, 'world, Comps, EntityHandleIter>
+    ComponentIter<'query, 'world, Comps, EntityHandleIter>
 where
     Comps: ComponentRefSequence + 'world,
+    EntityHandleIter: Iterator<Item = EntityHandle<'query>>,
     'world: 'query,
 {
-    pub(crate) fn new(world: &'world World, iter: FlexibleQueryIter<'query>) -> Self
+    pub(crate) fn new(world: &'world World, iter: EntityHandleIter) -> Self
     {
         Self { world, iter, comps_pd: PhantomData }
     }
 }
 
-impl<'query, 'world, Comps> Iterator for ComponentIter<'query, 'world, Comps>
+impl<'query, 'world, Comps, EntityHandleIter> Iterator
+    for ComponentIter<'query, 'world, Comps, EntityHandleIter>
 where
     Comps: ComponentRefSequence + 'world,
+    EntityHandleIter: Iterator<Item = EntityHandle<'query>>,
     'world: 'query,
 {
     type Item = Comps::Handles<'query>;
diff --git a/ecs/src/query/flexible.rs b/ecs/src/query/flexible.rs
index d081d31..5c23e68 100644
--- a/ecs/src/query/flexible.rs
+++ b/ecs/src/query/flexible.rs
@@ -84,7 +84,7 @@ impl<'query> Iter<'query>
     pub fn into_component_iter<'world, Comps>(
         self,
         world: &'world World,
-    ) -> ComponentIter<'query, 'world, Comps>
+    ) -> ComponentIter<'query, 'world, Comps, Self>
     where
         Comps: ComponentRefSequence + 'world,
         'world: 'query,
-- 
cgit v1.2.3-18-g5258