@@ -169,6 +169,21 @@ where
169
169
. collect ( ) ,
170
170
}
171
171
}
172
+
173
+ /// Creates an iterator which uses a closure to determine if recursive [`RelationshipTarget`]s
174
+ /// should be yielded.
175
+ ///
176
+ /// Once the the provided closure returns `false` for an [`Entity`] it and its recursive
177
+ /// [`RelationshipTarget`]s will not be yielded, effectively skipping that sub hierarchy.
178
+ pub fn filter_hierarchies < HF > ( self , filter : HF ) -> FilterDescendantIter < ' w , ' s , D , F , S , HF >
179
+ where
180
+ HF : FnMut ( & Entity ) -> bool ,
181
+ {
182
+ FilterDescendantIter {
183
+ iter : self ,
184
+ hierarchy_filter : filter,
185
+ }
186
+ }
172
187
}
173
188
174
189
impl < ' w , ' s , D : QueryData , F : QueryFilter , S : RelationshipTarget > Iterator
@@ -270,3 +285,108 @@ where
270
285
self . next
271
286
}
272
287
}
288
+
289
+ /// An [`Iterator`] of [`Entity`]s over the descendants of an [`Entity`].
290
+ ///
291
+ /// Allows conditional skipping of sub hierarchies.
292
+ pub struct FilterDescendantIter < ' w , ' s , D , QF , S , HF >
293
+ where
294
+ D : QueryData ,
295
+ D :: ReadOnly : QueryData < Item < ' w , ' s > = & ' w S > ,
296
+ QF : QueryFilter ,
297
+ S : RelationshipTarget ,
298
+ HF : FnMut ( & Entity ) -> bool ,
299
+ {
300
+ iter : DescendantIter < ' w , ' s , D , QF , S > ,
301
+ hierarchy_filter : HF ,
302
+ }
303
+
304
+ impl < ' w , ' s , D , QF , S , HF > Iterator for FilterDescendantIter < ' w , ' s , D , QF , S , HF >
305
+ where
306
+ D : QueryData ,
307
+ D :: ReadOnly : QueryData < Item < ' w , ' s > = & ' w S > ,
308
+ QF : QueryFilter ,
309
+ S : RelationshipTarget ,
310
+ HF : FnMut ( & Entity ) -> bool ,
311
+ {
312
+ type Item = Entity ;
313
+
314
+ fn next ( & mut self ) -> Option < Self :: Item > {
315
+ let mut entity = self . iter . vecdeque . pop_front ( ) ?;
316
+
317
+ while !( self . hierarchy_filter ) ( & entity) {
318
+ entity = self . iter . vecdeque . pop_front ( ) ?;
319
+ }
320
+
321
+ if let Ok ( children) = self . iter . children_query . get ( entity) {
322
+ self . iter . vecdeque . extend ( children. iter ( ) ) ;
323
+ }
324
+
325
+ Some ( entity)
326
+ }
327
+ }
328
+
329
+ #[ cfg( test) ]
330
+ mod test_iter_descendants {
331
+ use crate :: {
332
+ prelude:: * ,
333
+ system:: { RunSystemError , RunSystemOnce } ,
334
+ } ;
335
+ use alloc:: { vec, vec:: Vec } ;
336
+
337
+ #[ test]
338
+ fn filter_hierarchies_all ( ) -> Result < ( ) , RunSystemError > {
339
+ let mut world = World :: new ( ) ;
340
+ let root = world. spawn_empty ( ) . id ( ) ;
341
+ let children = vec ! [
342
+ world. spawn( ChildOf ( root) ) . id( ) ,
343
+ world. spawn( ChildOf ( root) ) . id( ) ,
344
+ world. spawn( ChildOf ( root) ) . id( ) ,
345
+ ] ;
346
+
347
+ let descendants = world. run_system_once ( move |q : Query < & Children > | {
348
+ q. iter_descendants ( root)
349
+ . filter_hierarchies ( |_| true )
350
+ . collect :: < Vec < _ > > ( )
351
+ } ) ?;
352
+
353
+ assert_eq ! ( descendants, children) ;
354
+ Ok ( ( ) )
355
+ }
356
+
357
+ #[ test]
358
+ fn filter_hierarchies_skip_flat ( ) -> Result < ( ) , RunSystemError > {
359
+ let mut world = World :: new ( ) ;
360
+ let root = world. spawn_empty ( ) . id ( ) ;
361
+ let c0 = world. spawn ( ChildOf ( root) ) . id ( ) ;
362
+ let c_skip = world. spawn ( ChildOf ( root) ) . id ( ) ;
363
+ let c2 = world. spawn ( ChildOf ( root) ) . id ( ) ;
364
+
365
+ let descendants = world. run_system_once ( move |q : Query < & Children > | {
366
+ q. iter_descendants ( root)
367
+ . filter_hierarchies ( |e| e != & c_skip)
368
+ . collect :: < Vec < _ > > ( )
369
+ } ) ?;
370
+
371
+ assert_eq ! ( descendants, vec![ c0, c2] ) ;
372
+ Ok ( ( ) )
373
+ }
374
+
375
+ #[ test]
376
+ fn filter_hierarchies_skip_sub_hierarchy ( ) -> Result < ( ) , RunSystemError > {
377
+ let mut world = World :: new ( ) ;
378
+ let root = world. spawn_empty ( ) . id ( ) ;
379
+ let c0 = world. spawn ( ChildOf ( root) ) . id ( ) ;
380
+ let c_skip = world. spawn ( ( ChildOf ( root) , children ! [ ( ) , ( ) ] ) ) . id ( ) ;
381
+ let c2 = world. spawn ( ChildOf ( root) ) . id ( ) ;
382
+
383
+ let descendants = world. run_system_once ( move |q : Query < & Children > | {
384
+ q. iter_descendants ( root)
385
+ . filter_hierarchies ( |e| e != & c_skip)
386
+ . collect :: < Vec < _ > > ( )
387
+ } ) ?;
388
+
389
+ assert_eq ! ( descendants, vec![ c0, c2] ) ;
390
+ Ok ( ( ) )
391
+ }
392
+ }
0 commit comments