52
52
53
53
#[ inline( always) ]
54
54
fn next ( & mut self ) -> Option < Self :: Item > {
55
+ // SAFETY:
56
+ // `tables` and `archetypes` belong to the same world that the cursor was initialized for.
57
+ // `query_state` is the state that was passed to `QueryIterationCursor::init`.
55
58
unsafe {
56
59
self . cursor
57
60
. next ( self . tables , self . archetypes , self . query_state )
@@ -150,33 +153,42 @@ where
150
153
151
154
#[ inline( always) ]
152
155
fn next ( & mut self ) -> Option < Self :: Item > {
153
- unsafe {
154
- for entity in self . entity_iter . by_ref ( ) {
155
- let location = match self . entities . get ( * entity. borrow ( ) ) {
156
- Some ( location) => location,
157
- None => continue ,
158
- } ;
159
-
160
- if !self
161
- . query_state
162
- . matched_archetypes
163
- . contains ( location. archetype_id . index ( ) )
164
- {
165
- continue ;
166
- }
156
+ for entity in self . entity_iter . by_ref ( ) {
157
+ let location = match self . entities . get ( * entity. borrow ( ) ) {
158
+ Some ( location) => location,
159
+ None => continue ,
160
+ } ;
161
+
162
+ if !self
163
+ . query_state
164
+ . matched_archetypes
165
+ . contains ( location. archetype_id . index ( ) )
166
+ {
167
+ continue ;
168
+ }
167
169
168
- let archetype = & self . archetypes [ location. archetype_id ] ;
170
+ let archetype = & self . archetypes [ location. archetype_id ] ;
169
171
172
+ // SAFETY: `archetype` is from the world that `fetch/filter` were created for,
173
+ // `fetch_state`/`filter_state` are the states that `fetch/filter` were initialized with
174
+ unsafe {
170
175
self . fetch
171
176
. set_archetype ( & self . query_state . fetch_state , archetype, self . tables ) ;
177
+ }
178
+ // SAFETY: `table` is from the world that `fetch/filter` were created for,
179
+ // `fetch_state`/`filter_state` are the states that `fetch/filter` were initialized with
180
+ unsafe {
172
181
self . filter
173
182
. set_archetype ( & self . query_state . filter_state , archetype, self . tables ) ;
174
- if self . filter . archetype_filter_fetch ( location. index ) {
175
- return Some ( self . fetch . archetype_fetch ( location. index ) ) ;
176
- }
177
183
}
178
- None
184
+ // SAFETY: set_archetype was called prior.
185
+ // `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
186
+ if unsafe { self . filter . archetype_filter_fetch ( location. index ) } {
187
+ // SAFETY: set_archetype was called prior, `location.index` is an archetype index in range of the current archetype
188
+ return Some ( unsafe { self . fetch . archetype_fetch ( location. index ) } ) ;
189
+ }
179
190
}
191
+ None
180
192
}
181
193
182
194
fn size_hint ( & self ) -> ( usize , Option < usize > ) {
@@ -289,7 +301,7 @@ impl<'w, 's, Q: WorldQuery, F: WorldQuery, const K: usize> QueryCombinationIter<
289
301
for < ' a > QueryFetch < ' a , Q > : Clone ,
290
302
for < ' a > QueryFetch < ' a , F > : Clone ,
291
303
{
292
- // safety : we are limiting the returned reference to self,
304
+ // SAFETY : we are limiting the returned reference to self,
293
305
// making sure this method cannot be called multiple times without getting rid
294
306
// of any previously returned unique references first, thus preventing aliasing.
295
307
unsafe {
@@ -374,7 +386,9 @@ struct QueryIterationCursor<'w, 's, Q: WorldQuery, QF: Fetch<'w, State = Q::Stat
374
386
archetype_id_iter : std:: slice:: Iter < ' s , ArchetypeId > ,
375
387
fetch : QF ,
376
388
filter : QueryFetch < ' w , F > ,
389
+ // length of the table table or length of the archetype, depending on whether both `Q`'s and `F`'s fetches are dense
377
390
current_len : usize ,
391
+ // either table row or archetype index, depending on whether both `Q`'s and `F`'s fetches are dense
378
392
current_index : usize ,
379
393
phantom : PhantomData < ( & ' w ( ) , Q ) > ,
380
394
}
@@ -461,6 +475,10 @@ where
461
475
462
476
// NOTE: If you are changing query iteration code, remember to update the following places, where relevant:
463
477
// QueryIterationCursor, QueryState::for_each_unchecked_manual, QueryState::par_for_each_unchecked_manual
478
+ /// # Safety
479
+ /// `tables` and `archetypes` must belong to the same world that the [`QueryIterationCursor`]
480
+ /// was initialized for.
481
+ /// `query_state` must be the same [`QueryState`] that was passed to `init` or `init_empty`.
464
482
#[ inline( always) ]
465
483
unsafe fn next (
466
484
& mut self ,
@@ -470,21 +488,28 @@ where
470
488
) -> Option < QF :: Item > {
471
489
if Self :: IS_DENSE {
472
490
loop {
491
+ // we are on the beginning of the query, or finished processing a table, so skip to the next
473
492
if self . current_index == self . current_len {
474
493
let table_id = self . table_id_iter . next ( ) ?;
475
494
let table = & tables[ * table_id] ;
495
+ // SAFETY: `table` is from the world that `fetch/filter` were created for,
496
+ // `fetch_state`/`filter_state` are the states that `fetch/filter` were initialized with
476
497
self . fetch . set_table ( & query_state. fetch_state , table) ;
477
498
self . filter . set_table ( & query_state. filter_state , table) ;
478
499
self . current_len = table. len ( ) ;
479
500
self . current_index = 0 ;
480
501
continue ;
481
502
}
482
503
504
+ // SAFETY: set_table was called prior.
505
+ // `current_index` is a table row in range of the current table, because if it was not, then the if above would have been executed.
483
506
if !self . filter . table_filter_fetch ( self . current_index ) {
484
507
self . current_index += 1 ;
485
508
continue ;
486
509
}
487
510
511
+ // SAFETY: set_table was called prior.
512
+ // `current_index` is a table row in range of the current table, because if it was not, then the if above would have been executed.
488
513
let item = self . fetch . table_fetch ( self . current_index ) ;
489
514
490
515
self . current_index += 1 ;
@@ -495,6 +520,8 @@ where
495
520
if self . current_index == self . current_len {
496
521
let archetype_id = self . archetype_id_iter . next ( ) ?;
497
522
let archetype = & archetypes[ * archetype_id] ;
523
+ // SAFETY: `archetype` and `tables` are from the world that `fetch/filter` were created for,
524
+ // `fetch_state`/`filter_state` are the states that `fetch/filter` were initialized with
498
525
self . fetch
499
526
. set_archetype ( & query_state. fetch_state , archetype, tables) ;
500
527
self . filter
@@ -504,11 +531,15 @@ where
504
531
continue ;
505
532
}
506
533
534
+ // SAFETY: set_archetype was called prior.
535
+ // `current_index` is an archetype index row in range of the current archetype, because if it was not, then the if above would have been executed.
507
536
if !self . filter . archetype_filter_fetch ( self . current_index ) {
508
537
self . current_index += 1 ;
509
538
continue ;
510
539
}
511
540
541
+ // SAFETY: set_archetype was called prior, `current_index` is an archetype index in range of the current archetype
542
+ // `current_index` is an archetype index row in range of the current archetype, because if it was not, then the if above would have been executed.
512
543
let item = self . fetch . archetype_fetch ( self . current_index ) ;
513
544
self . current_index += 1 ;
514
545
return Some ( item) ;
0 commit comments