@@ -2,6 +2,7 @@ use crate::storage::SparseSetIndex;
2
2
use bevy_utils:: HashSet ;
3
3
use core:: fmt;
4
4
use fixedbitset:: FixedBitSet ;
5
+ use smallvec:: SmallVec ;
5
6
use std:: marker:: PhantomData ;
6
7
7
8
/// A wrapper struct to make Debug representations of [`FixedBitSet`] easier
@@ -25,6 +26,7 @@ struct FormattedBitSet<'a, T: SparseSetIndex> {
25
26
bit_set : & ' a FixedBitSet ,
26
27
_marker : PhantomData < T > ,
27
28
}
29
+
28
30
impl < ' a , T : SparseSetIndex > FormattedBitSet < ' a , T > {
29
31
fn new ( bit_set : & ' a FixedBitSet ) -> Self {
30
32
Self {
@@ -33,6 +35,7 @@ impl<'a, T: SparseSetIndex> FormattedBitSet<'a, T> {
33
35
}
34
36
}
35
37
}
38
+
36
39
impl < ' a , T : SparseSetIndex + fmt:: Debug > fmt:: Debug for FormattedBitSet < ' a , T > {
37
40
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
38
41
f. debug_list ( )
@@ -41,6 +44,28 @@ impl<'a, T: SparseSetIndex + fmt::Debug> fmt::Debug for FormattedBitSet<'a, T> {
41
44
}
42
45
}
43
46
47
+ struct FormattedExpandedOrWithAccesses < ' a , T : SparseSetIndex > {
48
+ with : & ' a ExpandedOrWithAccesses ,
49
+ _marker : PhantomData < T > ,
50
+ }
51
+
52
+ impl < ' a , T : SparseSetIndex > FormattedExpandedOrWithAccesses < ' a , T > {
53
+ fn new ( with : & ' a ExpandedOrWithAccesses ) -> Self {
54
+ Self {
55
+ with,
56
+ _marker : PhantomData ,
57
+ }
58
+ }
59
+ }
60
+
61
+ impl < ' a , T : SparseSetIndex + fmt:: Debug > fmt:: Debug for FormattedExpandedOrWithAccesses < ' a , T > {
62
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
63
+ f. debug_list ( )
64
+ . entries ( self . with . arr . iter ( ) . map ( FormattedBitSet :: < T > :: new) )
65
+ . finish ( )
66
+ }
67
+ }
68
+
44
69
/// Tracks read and write access to specific elements in a collection.
45
70
///
46
71
/// Used internally to ensure soundness during system initialization and execution.
@@ -69,6 +94,7 @@ impl<T: SparseSetIndex + fmt::Debug> fmt::Debug for Access<T> {
69
94
. finish ( )
70
95
}
71
96
}
97
+
72
98
impl < T : SparseSetIndex > Default for Access < T > {
73
99
fn default ( ) -> Self {
74
100
Self :: new ( )
@@ -213,20 +239,24 @@ impl<T: SparseSetIndex> Access<T> {
213
239
/// is read/write `T`, read `U`. It must still have a read `U` access otherwise the following
214
240
/// queries would be incorrectly considered disjoint:
215
241
/// - `Query<&mut T>` read/write `T`
216
- /// - `Query<Option<&T>` accesses nothing
242
+ /// - `Query<Option<&T>> ` accesses nothing
217
243
///
218
244
/// See comments the `WorldQuery` impls of `AnyOf`/`Option`/`Or` for more information.
219
245
#[ derive( Clone , Eq , PartialEq ) ]
220
246
pub struct FilteredAccess < T : SparseSetIndex > {
221
247
access : Access < T > ,
222
- with : FixedBitSet ,
248
+ with : ExpandedOrWithAccesses ,
223
249
without : FixedBitSet ,
224
250
}
251
+
225
252
impl < T : SparseSetIndex + fmt:: Debug > fmt:: Debug for FilteredAccess < T > {
226
253
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
227
254
f. debug_struct ( "FilteredAccess" )
228
255
. field ( "access" , & self . access )
229
- . field ( "with" , & FormattedBitSet :: < T > :: new ( & self . with ) )
256
+ . field (
257
+ "with" ,
258
+ & FormattedExpandedOrWithAccesses :: < T > :: new ( & self . with ) ,
259
+ )
230
260
. field ( "without" , & FormattedBitSet :: < T > :: new ( & self . without ) )
231
261
. finish ( )
232
262
}
@@ -277,8 +307,7 @@ impl<T: SparseSetIndex> FilteredAccess<T> {
277
307
278
308
/// Retains only combinations where the element given by `index` is also present.
279
309
pub fn add_with ( & mut self , index : T ) {
280
- self . with . grow ( index. sparse_set_index ( ) + 1 ) ;
281
- self . with . insert ( index. sparse_set_index ( ) ) ;
310
+ self . with . add ( index. sparse_set_index ( ) ) ;
282
311
}
283
312
284
313
/// Retains only combinations where the element given by `index` is not present.
@@ -289,7 +318,7 @@ impl<T: SparseSetIndex> FilteredAccess<T> {
289
318
290
319
pub fn extend_intersect_filter ( & mut self , other : & FilteredAccess < T > ) {
291
320
self . without . intersect_with ( & other. without ) ;
292
- self . with . intersect_with ( & other. with ) ;
321
+ self . with . extend_with_or ( & other. with ) ;
293
322
}
294
323
295
324
pub fn extend_access ( & mut self , other : & FilteredAccess < T > ) {
@@ -325,6 +354,57 @@ impl<T: SparseSetIndex> FilteredAccess<T> {
325
354
}
326
355
}
327
356
357
+ // A struct to express something like `Or<(With<A>, With<B>)>`.
358
+ // Filters like `(With<A>, Or<(With<B>, With<C>)>` are expanded into `Or<(With<(A, B)>, With<(B, C)>)>`.
359
+ #[ derive( Clone , Eq , PartialEq ) ]
360
+ struct ExpandedOrWithAccesses {
361
+ arr : SmallVec < [ FixedBitSet ; 8 ] > ,
362
+ }
363
+
364
+ impl Default for ExpandedOrWithAccesses {
365
+ fn default ( ) -> Self {
366
+ Self {
367
+ arr : smallvec:: smallvec![ FixedBitSet :: default ( ) ] ,
368
+ }
369
+ }
370
+ }
371
+
372
+ impl ExpandedOrWithAccesses {
373
+ fn add ( & mut self , index : usize ) {
374
+ for with in & mut self . arr {
375
+ with. grow ( index + 1 ) ;
376
+ with. insert ( index) ;
377
+ }
378
+ }
379
+
380
+ fn extend_with_or ( & mut self , other : & ExpandedOrWithAccesses ) {
381
+ self . arr . append ( & mut other. arr . clone ( ) ) ;
382
+ }
383
+
384
+ fn is_disjoint ( & self , without : & FixedBitSet ) -> bool {
385
+ self . arr . iter ( ) . any ( |with| with. is_disjoint ( without) )
386
+ }
387
+
388
+ fn union_with ( & mut self , other : & Self ) {
389
+ if other. arr . len ( ) == 1 {
390
+ for with in & mut self . arr {
391
+ with. union_with ( & other. arr [ 0 ] ) ;
392
+ }
393
+ return ;
394
+ }
395
+
396
+ let mut new_with = SmallVec :: with_capacity ( self . arr . len ( ) * other. arr . len ( ) ) ;
397
+ for with in & self . arr {
398
+ for other_with in & other. arr {
399
+ let mut w = with. clone ( ) ;
400
+ w. union_with ( other_with) ;
401
+ new_with. push ( w) ;
402
+ }
403
+ }
404
+ self . arr = new_with;
405
+ }
406
+ }
407
+
328
408
/// A collection of [`FilteredAccess`] instances.
329
409
///
330
410
/// Used internally to statically check if systems have conflicting access.
0 commit comments