@@ -13,16 +13,20 @@ pub struct Access<T: SparseSetIndex> {
1313 reads_and_writes : FixedBitSet ,
1414 /// The exclusively-accessed elements.
1515 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.
1717 /// This field is a performance optimization for `&World` (also harder to mess up for soundness).
1818 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 ,
1922 marker : PhantomData < T > ,
2023}
2124
2225impl < T : SparseSetIndex > Default for Access < T > {
2326 fn default ( ) -> Self {
2427 Self {
2528 reads_all : false ,
29+ writes_all : false ,
2630 reads_and_writes : Default :: default ( ) ,
2731 writes : Default :: default ( ) ,
2832 marker : PhantomData ,
@@ -64,7 +68,11 @@ impl<T: SparseSetIndex> Access<T> {
6468
6569 /// Returns `true` if this can exclusively access the element given by `index`.
6670 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+ }
6876 }
6977
7078 /// Sets this as having access to all indexed elements (i.e. `&World`).
@@ -77,16 +85,29 @@ impl<T: SparseSetIndex> Access<T> {
7785 self . reads_all
7886 }
7987
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+
8099 /// Removes all accesses.
81100 pub fn clear ( & mut self ) {
82101 self . reads_all = false ;
102+ self . writes_all = false ;
83103 self . reads_and_writes . clear ( ) ;
84104 self . writes . clear ( ) ;
85105 }
86106
87107 /// Adds all access from `other`.
88108 pub fn extend ( & mut self , other : & Access < T > ) {
89109 self . reads_all = self . reads_all || other. reads_all ;
110+ self . writes_all = self . writes_all || other. writes_all ;
90111 self . reads_and_writes . union_with ( & other. reads_and_writes ) ;
91112 self . writes . union_with ( & other. writes ) ;
92113 }
@@ -96,6 +117,12 @@ impl<T: SparseSetIndex> Access<T> {
96117 /// `Access` instances are incompatible if one can write
97118 /// an element that the other can read or write.
98119 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+
99126 // Only systems that do not write data are compatible with systems that operate on `&World`.
100127 if self . reads_all {
101128 return other. writes . count_ones ( ..) == 0 ;
@@ -112,15 +139,31 @@ impl<T: SparseSetIndex> Access<T> {
112139 /// Returns a vector of elements that the access and `other` cannot access at the same time.
113140 pub fn get_conflicts ( & self , other : & Access < T > ) -> Vec < T > {
114141 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 ( ) ) ;
117145 }
118146
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+ }
121165 }
122- conflicts. extend ( self . writes . intersection ( & other. reads_and_writes ) ) ;
123- conflicts. extend ( self . reads_and_writes . intersection ( & other. writes ) ) ;
166+
124167 conflicts
125168 . ones ( )
126169 . map ( SparseSetIndex :: get_sparse_set_index)
@@ -266,6 +309,11 @@ impl<T: SparseSetIndex> FilteredAccess<T> {
266309 pub fn read_all ( & mut self ) {
267310 self . access . read_all ( ) ;
268311 }
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+ }
269317}
270318
271319/// A collection of [`FilteredAccess`] instances.
@@ -306,6 +354,20 @@ impl<T: SparseSetIndex> FilteredAccessSet<T> {
306354 true
307355 }
308356
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+
309371 /// Returns a vector of elements that this set and `other` cannot access at the same time.
310372 pub fn get_conflicts ( & self , other : & FilteredAccessSet < T > ) -> Vec < T > {
311373 // if the unfiltered access is incompatible, must check each pair
@@ -320,7 +382,7 @@ impl<T: SparseSetIndex> FilteredAccessSet<T> {
320382 conflicts. into_iter ( ) . collect ( )
321383 }
322384
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.
324386 pub fn get_conflicts_single ( & self , filtered_access : & FilteredAccess < T > ) -> Vec < T > {
325387 // if the unfiltered access is incompatible, must check each pair
326388 let mut conflicts = HashSet :: new ( ) ;
0 commit comments