goud_engine/ecs/query/
iter.rs1use crate::ecs::archetype::ArchetypeId;
4use crate::ecs::entity::Entity;
5use crate::ecs::World;
6
7use super::fetch::WorldQuery;
8use super::query_type::Query;
9
10pub struct QueryIter<'w, 'q, Q: WorldQuery, F: WorldQuery> {
19 query: &'q Query<Q, F>,
21 world: &'w World,
23 cursor: usize,
26 entity_index: usize,
28 cached: bool,
30}
31
32impl<'w, 'q, Q: WorldQuery, F: WorldQuery> QueryIter<'w, 'q, Q, F> {
33 #[inline]
35 pub(crate) fn new(query: &'q Query<Q, F>, world: &'w World) -> Self {
36 let cached = query.archetype_cache.is_some();
37 Self {
38 query,
39 world,
40 cursor: 0,
41 entity_index: 0,
42 cached,
43 }
44 }
45
46 #[inline]
48 fn current_archetype_index(&self) -> Option<usize> {
49 if self.cached {
50 let cache = self.query.archetype_cache.as_ref()?;
52 let indices = cache.archetype_indices();
53 if self.cursor < indices.len() {
54 Some(indices[self.cursor])
55 } else {
56 None
57 }
58 } else {
59 let total = self.world.archetypes().len();
60 if self.cursor < total {
61 Some(self.cursor)
62 } else {
63 None
64 }
65 }
66 }
67}
68
69impl<'w, 'q, Q: WorldQuery, F: WorldQuery> Iterator for QueryIter<'w, 'q, Q, F> {
70 type Item = Q::Item<'w>;
71
72 fn next(&mut self) -> Option<Self::Item> {
73 loop {
74 let graph_index = self.current_archetype_index()?;
75 let id = ArchetypeId::new(graph_index as u32);
76 let archetype = self.world.archetypes().get(id)?;
77
78 if !self.cached && !self.query.matches_archetype(archetype) {
80 self.cursor += 1;
81 self.entity_index = 0;
82 continue;
83 }
84
85 let entities = archetype.entities();
86
87 if self.entity_index >= entities.len() {
88 self.cursor += 1;
89 self.entity_index = 0;
90 continue;
91 }
92
93 let entity = entities[self.entity_index];
94 self.entity_index += 1;
95
96 if let Some(item) = self.query.get(self.world, entity) {
98 return Some(item);
99 }
100 }
102 }
103}
104
105pub struct QueryIterMut<'w, 'q, Q: WorldQuery, F: WorldQuery> {
114 query: &'q Query<Q, F>,
116 world: &'w mut World,
118 entities: Vec<Entity>,
120 current_index: usize,
122}
123
124impl<'w, 'q, Q: WorldQuery, F: WorldQuery> QueryIterMut<'w, 'q, Q, F> {
125 #[inline]
127 pub(crate) fn new(query: &'q Query<Q, F>, world: &'w mut World) -> Self {
128 let mut entities = Vec::new();
130
131 if let Some(cache) = &query.archetype_cache {
132 let archetypes = world.archetypes();
134 for &idx in cache.archetype_indices() {
135 let id = ArchetypeId::new(idx as u32);
136 if let Some(archetype) = archetypes.get(id) {
137 entities.extend_from_slice(archetype.entities());
138 }
139 }
140 } else {
141 for archetype in world.archetypes().iter() {
143 if query.matches_archetype(archetype) {
144 entities.extend_from_slice(archetype.entities());
145 }
146 }
147 }
148
149 Self {
150 query,
151 world,
152 entities,
153 current_index: 0,
154 }
155 }
156}
157
158impl<'w, 'q, Q: WorldQuery, F: WorldQuery> Iterator for QueryIterMut<'w, 'q, Q, F> {
159 type Item = Q::Item<'w>;
160
161 fn next(&mut self) -> Option<Self::Item> {
162 loop {
163 if self.current_index >= self.entities.len() {
164 return None;
165 }
166
167 let entity = self.entities[self.current_index];
168 self.current_index += 1;
169
170 let world_ptr = self.world as *mut World;
175 let world_ref: &'w mut World = unsafe { &mut *world_ptr };
176
177 if F::fetch(&self.query.filter_state, world_ref, entity).is_none() {
179 continue;
180 }
181
182 if let Some(item) = Q::fetch_mut(&self.query.query_state, world_ref, entity) {
184 return Some(item);
185 }
186 }
188 }
189}