@@ -13,16 +13,20 @@ pub struct Access<T: SparseSetIndex> {
13
13
reads_and_writes : FixedBitSet ,
14
14
/// The exclusively-accessed elements.
15
15
writes : FixedBitSet ,
16
- /// Is `true` if this has access to all elements in the collection?
16
+ /// Is `true` if this has access to all elements in the collection.
17
17
/// This field is a performance optimization for `&World` (also harder to mess up for soundness).
18
18
reads_all : bool ,
19
+ /// Is `true` if this has exclusive access to all elements in the collection.
20
+ /// This field is a performance optimization for `&mut World` (also harder to mess up for soundness).
21
+ writes_all : bool ,
19
22
marker : PhantomData < T > ,
20
23
}
21
24
22
25
impl < T : SparseSetIndex > Default for Access < T > {
23
26
fn default ( ) -> Self {
24
27
Self {
25
28
reads_all : false ,
29
+ writes_all : false ,
26
30
reads_and_writes : Default :: default ( ) ,
27
31
writes : Default :: default ( ) ,
28
32
marker : PhantomData ,
@@ -64,7 +68,11 @@ impl<T: SparseSetIndex> Access<T> {
64
68
65
69
/// Returns `true` if this can exclusively access the element given by `index`.
66
70
pub fn has_write ( & self , index : T ) -> bool {
67
- self . writes . contains ( index. sparse_set_index ( ) )
71
+ if self . writes_all {
72
+ true
73
+ } else {
74
+ self . writes . contains ( index. sparse_set_index ( ) )
75
+ }
68
76
}
69
77
70
78
/// Sets this as having access to all indexed elements (i.e. `&World`).
@@ -77,16 +85,29 @@ impl<T: SparseSetIndex> Access<T> {
77
85
self . reads_all
78
86
}
79
87
88
+ /// Sets this as having exclusive access to all indexed elements (i.e. `&mut World`).
89
+ pub fn write_all ( & mut self ) {
90
+ self . reads_all = true ;
91
+ self . writes_all = true ;
92
+ }
93
+
94
+ /// Returns `true` if this has exclusive access to all indexed elements (i.e. `&mut World`).
95
+ pub fn has_write_all ( & self ) -> bool {
96
+ self . writes_all
97
+ }
98
+
80
99
/// Removes all accesses.
81
100
pub fn clear ( & mut self ) {
82
101
self . reads_all = false ;
102
+ self . writes_all = false ;
83
103
self . reads_and_writes . clear ( ) ;
84
104
self . writes . clear ( ) ;
85
105
}
86
106
87
107
/// Adds all access from `other`.
88
108
pub fn extend ( & mut self , other : & Access < T > ) {
89
109
self . reads_all = self . reads_all || other. reads_all ;
110
+ self . writes_all = self . writes_all || other. writes_all ;
90
111
self . reads_and_writes . union_with ( & other. reads_and_writes ) ;
91
112
self . writes . union_with ( & other. writes ) ;
92
113
}
@@ -96,6 +117,12 @@ impl<T: SparseSetIndex> Access<T> {
96
117
/// `Access` instances are incompatible if one can write
97
118
/// an element that the other can read or write.
98
119
pub fn is_compatible ( & self , other : & Access < T > ) -> bool {
120
+ // All systems make a `&World` reference before running to update change detection info.
121
+ // Since exclusive systems produce a `&mut World`, we cannot let other systems run.
122
+ if self . writes_all || other. writes_all {
123
+ return false ;
124
+ }
125
+
99
126
// Only systems that do not write data are compatible with systems that operate on `&World`.
100
127
if self . reads_all {
101
128
return other. writes . count_ones ( ..) == 0 ;
@@ -112,15 +139,31 @@ impl<T: SparseSetIndex> Access<T> {
112
139
/// Returns a vector of elements that the access and `other` cannot access at the same time.
113
140
pub fn get_conflicts ( & self , other : & Access < T > ) -> Vec < T > {
114
141
let mut conflicts = FixedBitSet :: default ( ) ;
115
- if self . reads_all {
116
- conflicts. extend ( other. writes . ones ( ) ) ;
142
+
143
+ if self . writes_all {
144
+ conflicts. extend ( other. reads_and_writes . ones ( ) ) ;
117
145
}
118
146
119
- if other. reads_all {
120
- conflicts. extend ( self . writes . ones ( ) ) ;
147
+ if other. writes_all {
148
+ conflicts. extend ( self . reads_and_writes . ones ( ) ) ;
149
+ }
150
+
151
+ if !( self . writes_all || other. writes_all ) {
152
+ match ( self . reads_all , other. reads_all ) {
153
+ ( false , false ) => {
154
+ conflicts. extend ( self . writes . intersection ( & other. reads_and_writes ) ) ;
155
+ conflicts. extend ( self . reads_and_writes . intersection ( & other. writes ) ) ;
156
+ }
157
+ ( false , true ) => {
158
+ conflicts. extend ( self . writes . ones ( ) ) ;
159
+ }
160
+ ( true , false ) => {
161
+ conflicts. extend ( other. writes . ones ( ) ) ;
162
+ }
163
+ ( true , true ) => ( ) ,
164
+ }
121
165
}
122
- conflicts. extend ( self . writes . intersection ( & other. reads_and_writes ) ) ;
123
- conflicts. extend ( self . reads_and_writes . intersection ( & other. writes ) ) ;
166
+
124
167
conflicts
125
168
. ones ( )
126
169
. map ( SparseSetIndex :: get_sparse_set_index)
@@ -266,6 +309,11 @@ impl<T: SparseSetIndex> FilteredAccess<T> {
266
309
pub fn read_all ( & mut self ) {
267
310
self . access . read_all ( ) ;
268
311
}
312
+
313
+ /// Sets the underlying unfiltered access as having exclusive access to all indexed elements.
314
+ pub fn write_all ( & mut self ) {
315
+ self . access . write_all ( ) ;
316
+ }
269
317
}
270
318
271
319
/// A collection of [`FilteredAccess`] instances.
@@ -306,6 +354,20 @@ impl<T: SparseSetIndex> FilteredAccessSet<T> {
306
354
true
307
355
}
308
356
357
+ /// Returns `true` if this and `filtered_access` can be active at the same time.
358
+ pub fn is_compatible_single ( & self , filtered_access : & FilteredAccess < T > ) -> bool {
359
+ if self . combined_access . is_compatible ( filtered_access. access ( ) ) {
360
+ return true ;
361
+ }
362
+ for filtered in & self . filtered_accesses {
363
+ if !filtered. is_compatible ( filtered_access) {
364
+ return false ;
365
+ }
366
+ }
367
+
368
+ true
369
+ }
370
+
309
371
/// Returns a vector of elements that this set and `other` cannot access at the same time.
310
372
pub fn get_conflicts ( & self , other : & FilteredAccessSet < T > ) -> Vec < T > {
311
373
// if the unfiltered access is incompatible, must check each pair
@@ -320,7 +382,7 @@ impl<T: SparseSetIndex> FilteredAccessSet<T> {
320
382
conflicts. into_iter ( ) . collect ( )
321
383
}
322
384
323
- /// Returns a vector of elements that this set and `other ` cannot access at the same time.
385
+ /// Returns a vector of elements that this set and `filtered_access ` cannot access at the same time.
324
386
pub fn get_conflicts_single ( & self , filtered_access : & FilteredAccess < T > ) -> Vec < T > {
325
387
// if the unfiltered access is incompatible, must check each pair
326
388
let mut conflicts = HashSet :: new ( ) ;
0 commit comments