@@ -214,6 +214,155 @@ where
214
214
{
215
215
}
216
216
217
+ /// An [`Iterator`] over [`Query`](crate::system::Query) results a list mapped to [`Entity`]'s and the list items.
218
+ ///
219
+ /// This struct is created by the [`Query::iter_join_map`](crate::system::Query::iter_join_map) and [`Query::iter_join_map_mut`](crate::system::Query::iter_join_map_mut) methods.
220
+ pub struct QueryJoinMapIter < ' w , ' s , Q : WorldQuery , F : WorldQuery , I : Iterator , MapFn >
221
+ where
222
+ MapFn : FnMut ( & I :: Item ) -> Entity ,
223
+ {
224
+ list : I ,
225
+ map_f : MapFn ,
226
+ entities : & ' w Entities ,
227
+ tables : & ' w Tables ,
228
+ archetypes : & ' w Archetypes ,
229
+ fetch : QueryFetch < ' w , Q > ,
230
+ filter : QueryFetch < ' w , F > ,
231
+ query_state : & ' s QueryState < Q , F > ,
232
+ }
233
+
234
+ impl < ' w , ' s , Q : WorldQuery , F : WorldQuery , I : Iterator , MapFn >
235
+ QueryJoinMapIter < ' w , ' s , Q , F , I , MapFn >
236
+ where
237
+ MapFn : FnMut ( & I :: Item ) -> Entity ,
238
+ {
239
+ /// # Safety
240
+ /// This does not check for mutable query correctness. To be safe, make sure mutable queries
241
+ /// have unique access to the components they query.
242
+ /// This does not validate that `world.id()` matches `query_state.world_id`. Calling this on a `world`
243
+ /// with a mismatched [`WorldId`](crate::world::WorldId) is unsound.
244
+ pub ( crate ) unsafe fn new < II : IntoIterator < IntoIter = I > > (
245
+ world : & ' w World ,
246
+ query_state : & ' s QueryState < Q , F > ,
247
+ last_change_tick : u32 ,
248
+ change_tick : u32 ,
249
+ entity_map : II ,
250
+ map_f : MapFn ,
251
+ ) -> QueryJoinMapIter < ' w , ' s , Q , F , I , MapFn > {
252
+ let fetch = Q :: init_fetch (
253
+ world,
254
+ & query_state. fetch_state ,
255
+ last_change_tick,
256
+ change_tick,
257
+ ) ;
258
+ let filter = F :: init_fetch (
259
+ world,
260
+ & query_state. filter_state ,
261
+ last_change_tick,
262
+ change_tick,
263
+ ) ;
264
+ QueryJoinMapIter {
265
+ query_state,
266
+ entities : & world. entities ,
267
+ archetypes : & world. archetypes ,
268
+ tables : & world. storages . tables ,
269
+ fetch,
270
+ filter,
271
+ list : entity_map. into_iter ( ) ,
272
+ map_f,
273
+ }
274
+ }
275
+
276
+ /// SAFETY:
277
+ /// The lifetime here is not restrictive enough for Fetch with &mut access,
278
+ /// as calling `fetch_next_aliased_unchecked` multiple times can produce multiple
279
+ /// references to the same component, leading to unique reference aliasing.
280
+ ///
281
+ /// It is always safe for immutable borrows.
282
+ #[ inline( always) ]
283
+ unsafe fn fetch_next_aliased_unchecked ( & mut self ) -> Option < ( QueryItem < ' w , Q > , I :: Item ) > {
284
+ for item in self . list . by_ref ( ) {
285
+ let location = match self . entities . get ( ( self . map_f ) ( & item) ) {
286
+ Some ( location) => location,
287
+ None => continue ,
288
+ } ;
289
+
290
+ if !self
291
+ . query_state
292
+ . matched_archetypes
293
+ . contains ( location. archetype_id . index ( ) )
294
+ {
295
+ continue ;
296
+ }
297
+
298
+ let archetype = & self . archetypes [ location. archetype_id ] ;
299
+
300
+ // SAFETY: `archetype` is from the world that `fetch/filter` were created for,
301
+ // `fetch_state`/`filter_state` are the states that `fetch/filter` were initialized with
302
+ Q :: set_archetype (
303
+ & mut self . fetch ,
304
+ & self . query_state . fetch_state ,
305
+ archetype,
306
+ self . tables ,
307
+ ) ;
308
+ // SAFETY: `table` is from the world that `fetch/filter` were created for,
309
+ // `fetch_state`/`filter_state` are the states that `fetch/filter` were initialized with
310
+ F :: set_archetype (
311
+ & mut self . filter ,
312
+ & self . query_state . filter_state ,
313
+ archetype,
314
+ self . tables ,
315
+ ) ;
316
+ // SAFETY: set_archetype was called prior.
317
+ // `location.index` is an archetype index row in range of the current archetype, because if it was not, the match above would have `continue`d
318
+ if F :: archetype_filter_fetch ( & mut self . filter , location. index ) {
319
+ // SAFETY: set_archetype was called prior, `location.index` is an archetype index in range of the current archetype
320
+ return Some ( ( Q :: archetype_fetch ( & mut self . fetch , location. index ) , item) ) ;
321
+ }
322
+ }
323
+ None
324
+ }
325
+
326
+ /// Get the next item from the iterator.
327
+ #[ inline( always) ]
328
+ pub fn fetch_next ( & mut self ) -> Option < ( QueryItem < ' _ , Q > , I :: Item ) > {
329
+ // safety: we are limiting the returned reference to self,
330
+ // making sure this method cannot be called multiple times without getting rid
331
+ // of any previously returned unique references first, thus preventing aliasing.
332
+ unsafe {
333
+ self . fetch_next_aliased_unchecked ( )
334
+ . map ( |( q_item, item) | ( Q :: shrink ( q_item) , item) )
335
+ }
336
+ }
337
+ }
338
+
339
+ impl < ' w , ' s , Q : ReadOnlyWorldQuery , F : ReadOnlyWorldQuery , I : Iterator , MapFn > Iterator
340
+ for QueryJoinMapIter < ' w , ' s , Q , F , I , MapFn >
341
+ where
342
+ MapFn : FnMut ( & I :: Item ) -> Entity ,
343
+ {
344
+ type Item = ( QueryItem < ' w , Q > , I :: Item ) ;
345
+
346
+ #[ inline( always) ]
347
+ fn next ( & mut self ) -> Option < Self :: Item > {
348
+ // SAFETY: it is safe to alias for ReadOnlyWorldQuery
349
+ unsafe { self . fetch_next_aliased_unchecked ( ) }
350
+ }
351
+
352
+ fn size_hint ( & self ) -> ( usize , Option < usize > ) {
353
+ let ( _, max_size) = self . list . size_hint ( ) ;
354
+ ( 0 , max_size)
355
+ }
356
+ }
357
+
358
+ // This is correct as QueryJoinMapIter always returns `None` once exhausted.
359
+ impl < ' w , ' s , Q : ReadOnlyWorldQuery , F : ReadOnlyWorldQuery , I : Iterator , MapFn > FusedIterator
360
+ for QueryJoinMapIter < ' w , ' s , Q , F , I , MapFn >
361
+ where
362
+ MapFn : FnMut ( & I :: Item ) -> Entity ,
363
+ {
364
+ }
365
+
217
366
/// An iterator over `K`-sized combinations of query items without repetition.
218
367
///
219
368
/// In this context, a combination is an unordered subset of `K` elements.
0 commit comments