bevy_ecs/query/
access.rs

1use crate::storage::SparseSetIndex;
2use bevy_utils::HashSet;
3use core::fmt;
4use fixedbitset::FixedBitSet;
5use std::marker::PhantomData;
6
7/// A wrapper struct to make Debug representations of [`FixedBitSet`] easier
8/// to read, when used to store [`SparseSetIndex`].
9///
10/// Instead of the raw integer representation of the `FixedBitSet`, the list of
11/// `T` valid for [`SparseSetIndex`] is shown.
12///
13/// Normal `FixedBitSet` `Debug` output:
14/// ```text
15/// read_and_writes: FixedBitSet { data: [ 160 ], length: 8 }
16/// ```
17///
18/// Which, unless you are a computer, doesn't help much understand what's in
19/// the set. With `FormattedBitSet`, we convert the present set entries into
20/// what they stand for, it is much clearer what is going on:
21/// ```text
22/// read_and_writes: [ ComponentId(5), ComponentId(7) ]
23/// ```
24struct FormattedBitSet<'a, T: SparseSetIndex> {
25    bit_set: &'a FixedBitSet,
26    _marker: PhantomData<T>,
27}
28
29impl<'a, T: SparseSetIndex> FormattedBitSet<'a, T> {
30    fn new(bit_set: &'a FixedBitSet) -> Self {
31        Self {
32            bit_set,
33            _marker: PhantomData,
34        }
35    }
36}
37
38impl<'a, T: SparseSetIndex + fmt::Debug> fmt::Debug for FormattedBitSet<'a, T> {
39    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40        f.debug_list()
41            .entries(self.bit_set.ones().map(T::get_sparse_set_index))
42            .finish()
43    }
44}
45
46/// Tracks read and write access to specific elements in a collection.
47///
48/// Used internally to ensure soundness during system initialization and execution.
49/// See the [`is_compatible`](Access::is_compatible) and [`get_conflicts`](Access::get_conflicts) functions.
50#[derive(Clone, Eq, PartialEq)]
51pub struct Access<T: SparseSetIndex> {
52    /// All accessed elements.
53    reads_and_writes: FixedBitSet,
54    /// The exclusively-accessed elements.
55    writes: FixedBitSet,
56    /// Is `true` if this has access to all elements in the collection.
57    /// This field is a performance optimization for `&World` (also harder to mess up for soundness).
58    reads_all: bool,
59    /// Is `true` if this has mutable access to all elements in the collection.
60    /// If this is true, then `reads_all` must also be true.
61    writes_all: bool,
62    // Elements that are not accessed, but whose presence in an archetype affect query results.
63    archetypal: FixedBitSet,
64    marker: PhantomData<T>,
65}
66
67impl<T: SparseSetIndex + fmt::Debug> fmt::Debug for Access<T> {
68    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
69        f.debug_struct("Access")
70            .field(
71                "read_and_writes",
72                &FormattedBitSet::<T>::new(&self.reads_and_writes),
73            )
74            .field("writes", &FormattedBitSet::<T>::new(&self.writes))
75            .field("reads_all", &self.reads_all)
76            .field("writes_all", &self.writes_all)
77            .field("archetypal", &FormattedBitSet::<T>::new(&self.archetypal))
78            .finish()
79    }
80}
81
82impl<T: SparseSetIndex> Default for Access<T> {
83    fn default() -> Self {
84        Self::new()
85    }
86}
87
88impl<T: SparseSetIndex> Access<T> {
89    /// Creates an empty [`Access`] collection.
90    pub const fn new() -> Self {
91        Self {
92            reads_all: false,
93            writes_all: false,
94            reads_and_writes: FixedBitSet::new(),
95            writes: FixedBitSet::new(),
96            archetypal: FixedBitSet::new(),
97            marker: PhantomData,
98        }
99    }
100
101    /// Adds access to the element given by `index`.
102    pub fn add_read(&mut self, index: T) {
103        self.reads_and_writes
104            .grow_and_insert(index.sparse_set_index());
105    }
106
107    /// Adds exclusive access to the element given by `index`.
108    pub fn add_write(&mut self, index: T) {
109        self.reads_and_writes
110            .grow_and_insert(index.sparse_set_index());
111        self.writes.grow_and_insert(index.sparse_set_index());
112    }
113
114    /// Adds an archetypal (indirect) access to the element given by `index`.
115    ///
116    /// This is for elements whose values are not accessed (and thus will never cause conflicts),
117    /// but whose presence in an archetype may affect query results.
118    ///
119    /// Currently, this is only used for [`Has<T>`].
120    ///
121    /// [`Has<T>`]: crate::query::Has
122    pub fn add_archetypal(&mut self, index: T) {
123        self.archetypal.grow_and_insert(index.sparse_set_index());
124    }
125
126    /// Returns `true` if this can access the element given by `index`.
127    pub fn has_read(&self, index: T) -> bool {
128        self.reads_all || self.reads_and_writes.contains(index.sparse_set_index())
129    }
130
131    /// Returns `true` if this can access anything.
132    pub fn has_any_read(&self) -> bool {
133        self.reads_all || !self.reads_and_writes.is_clear()
134    }
135
136    /// Returns `true` if this can exclusively access the element given by `index`.
137    pub fn has_write(&self, index: T) -> bool {
138        self.writes_all || self.writes.contains(index.sparse_set_index())
139    }
140
141    /// Returns `true` if this accesses anything mutably.
142    pub fn has_any_write(&self) -> bool {
143        self.writes_all || !self.writes.is_clear()
144    }
145
146    /// Returns true if this has an archetypal (indirect) access to the element given by `index`.
147    ///
148    /// This is an element whose value is not accessed (and thus will never cause conflicts),
149    /// but whose presence in an archetype may affect query results.
150    ///
151    /// Currently, this is only used for [`Has<T>`].
152    ///
153    /// [`Has<T>`]: crate::query::Has
154    pub fn has_archetypal(&self, index: T) -> bool {
155        self.archetypal.contains(index.sparse_set_index())
156    }
157
158    /// Sets this as having access to all indexed elements (i.e. `&World`).
159    pub fn read_all(&mut self) {
160        self.reads_all = true;
161    }
162
163    /// Sets this as having mutable access to all indexed elements (i.e. `EntityMut`).
164    pub fn write_all(&mut self) {
165        self.reads_all = true;
166        self.writes_all = true;
167    }
168
169    /// Returns `true` if this has access to all indexed elements (i.e. `&World`).
170    pub fn has_read_all(&self) -> bool {
171        self.reads_all
172    }
173
174    /// Returns `true` if this has write access to all indexed elements (i.e. `EntityMut`).
175    pub fn has_write_all(&self) -> bool {
176        self.writes_all
177    }
178
179    /// Removes all writes.
180    pub fn clear_writes(&mut self) {
181        self.writes_all = false;
182        self.writes.clear();
183    }
184
185    /// Removes all accesses.
186    pub fn clear(&mut self) {
187        self.reads_all = false;
188        self.writes_all = false;
189        self.reads_and_writes.clear();
190        self.writes.clear();
191    }
192
193    /// Adds all access from `other`.
194    pub fn extend(&mut self, other: &Access<T>) {
195        self.reads_all = self.reads_all || other.reads_all;
196        self.writes_all = self.writes_all || other.writes_all;
197        self.reads_and_writes.union_with(&other.reads_and_writes);
198        self.writes.union_with(&other.writes);
199    }
200
201    /// Returns `true` if the access and `other` can be active at the same time.
202    ///
203    /// [`Access`] instances are incompatible if one can write
204    /// an element that the other can read or write.
205    pub fn is_compatible(&self, other: &Access<T>) -> bool {
206        if self.writes_all {
207            return !other.has_any_read();
208        }
209
210        if other.writes_all {
211            return !self.has_any_read();
212        }
213
214        if self.reads_all {
215            return !other.has_any_write();
216        }
217
218        if other.reads_all {
219            return !self.has_any_write();
220        }
221
222        self.writes.is_disjoint(&other.reads_and_writes)
223            && other.writes.is_disjoint(&self.reads_and_writes)
224    }
225
226    /// Returns `true` if the set is a subset of another, i.e. `other` contains
227    /// at least all the values in `self`.
228    pub fn is_subset(&self, other: &Access<T>) -> bool {
229        if self.writes_all {
230            return other.writes_all;
231        }
232
233        if other.writes_all {
234            return true;
235        }
236
237        if self.reads_all {
238            return other.reads_all;
239        }
240
241        if other.reads_all {
242            return self.writes.is_subset(&other.writes);
243        }
244
245        self.reads_and_writes.is_subset(&other.reads_and_writes)
246            && self.writes.is_subset(&other.writes)
247    }
248
249    /// Returns a vector of elements that the access and `other` cannot access at the same time.
250    pub fn get_conflicts(&self, other: &Access<T>) -> Vec<T> {
251        let mut conflicts = FixedBitSet::default();
252        if self.reads_all {
253            // QUESTION: How to handle `other.writes_all`?
254            conflicts.extend(other.writes.ones());
255        }
256
257        if other.reads_all {
258            // QUESTION: How to handle `self.writes_all`.
259            conflicts.extend(self.writes.ones());
260        }
261
262        if self.writes_all {
263            conflicts.extend(other.reads_and_writes.ones());
264        }
265
266        if other.writes_all {
267            conflicts.extend(self.reads_and_writes.ones());
268        }
269
270        conflicts.extend(self.writes.intersection(&other.reads_and_writes));
271        conflicts.extend(self.reads_and_writes.intersection(&other.writes));
272        conflicts
273            .ones()
274            .map(SparseSetIndex::get_sparse_set_index)
275            .collect()
276    }
277
278    /// Returns the indices of the elements this has access to.
279    pub fn reads_and_writes(&self) -> impl Iterator<Item = T> + '_ {
280        self.reads_and_writes.ones().map(T::get_sparse_set_index)
281    }
282
283    /// Returns the indices of the elements this has non-exclusive access to.
284    pub fn reads(&self) -> impl Iterator<Item = T> + '_ {
285        self.reads_and_writes
286            .difference(&self.writes)
287            .map(T::get_sparse_set_index)
288    }
289
290    /// Returns the indices of the elements this has exclusive access to.
291    pub fn writes(&self) -> impl Iterator<Item = T> + '_ {
292        self.writes.ones().map(T::get_sparse_set_index)
293    }
294
295    /// Returns the indices of the elements that this has an archetypal access to.
296    ///
297    /// These are elements whose values are not accessed (and thus will never cause conflicts),
298    /// but whose presence in an archetype may affect query results.
299    ///
300    /// Currently, this is only used for [`Has<T>`].
301    ///
302    /// [`Has<T>`]: crate::query::Has
303    pub fn archetypal(&self) -> impl Iterator<Item = T> + '_ {
304        self.archetypal.ones().map(T::get_sparse_set_index)
305    }
306}
307
308/// An [`Access`] that has been filtered to include and exclude certain combinations of elements.
309///
310/// Used internally to statically check if queries are disjoint.
311///
312/// Subtle: a `read` or `write` in `access` should not be considered to imply a
313/// `with` access.
314///
315/// For example consider `Query<Option<&T>>` this only has a `read` of `T` as doing
316/// otherwise would allow for queries to be considered disjoint when they shouldn't:
317/// - `Query<(&mut T, Option<&U>)>` read/write `T`, read `U`, with `U`
318/// - `Query<&mut T, Without<U>>` read/write `T`, without `U`
319/// from this we could reasonably conclude that the queries are disjoint but they aren't.
320///
321/// In order to solve this the actual access that `Query<(&mut T, Option<&U>)>` has
322/// is read/write `T`, read `U`. It must still have a read `U` access otherwise the following
323/// queries would be incorrectly considered disjoint:
324/// - `Query<&mut T>`  read/write `T`
325/// - `Query<Option<&T>>` accesses nothing
326///
327/// See comments the [`WorldQuery`](super::WorldQuery) impls of [`AnyOf`](super::AnyOf)/`Option`/[`Or`](super::Or) for more information.
328#[derive(Debug, Clone, Eq, PartialEq)]
329pub struct FilteredAccess<T: SparseSetIndex> {
330    pub(crate) access: Access<T>,
331    pub(crate) required: FixedBitSet,
332    // An array of filter sets to express `With` or `Without` clauses in disjunctive normal form, for example: `Or<(With<A>, With<B>)>`.
333    // Filters like `(With<A>, Or<(With<B>, Without<C>)>` are expanded into `Or<((With<A>, With<B>), (With<A>, Without<C>))>`.
334    pub(crate) filter_sets: Vec<AccessFilters<T>>,
335}
336
337impl<T: SparseSetIndex> Default for FilteredAccess<T> {
338    fn default() -> Self {
339        Self {
340            access: Access::default(),
341            required: FixedBitSet::default(),
342            filter_sets: vec![AccessFilters::default()],
343        }
344    }
345}
346
347impl<T: SparseSetIndex> From<FilteredAccess<T>> for FilteredAccessSet<T> {
348    fn from(filtered_access: FilteredAccess<T>) -> Self {
349        let mut base = FilteredAccessSet::<T>::default();
350        base.add(filtered_access);
351        base
352    }
353}
354
355impl<T: SparseSetIndex> FilteredAccess<T> {
356    /// Returns a reference to the underlying unfiltered access.
357    #[inline]
358    pub fn access(&self) -> &Access<T> {
359        &self.access
360    }
361
362    /// Returns a mutable reference to the underlying unfiltered access.
363    #[inline]
364    pub fn access_mut(&mut self) -> &mut Access<T> {
365        &mut self.access
366    }
367
368    /// Adds access to the element given by `index`.
369    pub fn add_read(&mut self, index: T) {
370        self.access.add_read(index.clone());
371        self.add_required(index.clone());
372        self.and_with(index);
373    }
374
375    /// Adds exclusive access to the element given by `index`.
376    pub fn add_write(&mut self, index: T) {
377        self.access.add_write(index.clone());
378        self.add_required(index.clone());
379        self.and_with(index);
380    }
381
382    fn add_required(&mut self, index: T) {
383        self.required.grow_and_insert(index.sparse_set_index());
384    }
385
386    /// Adds a `With` filter: corresponds to a conjunction (AND) operation.
387    ///
388    /// Suppose we begin with `Or<(With<A>, With<B>)>`, which is represented by an array of two `AccessFilter` instances.
389    /// Adding `AND With<C>` via this method transforms it into the equivalent of  `Or<((With<A>, With<C>), (With<B>, With<C>))>`.
390    pub fn and_with(&mut self, index: T) {
391        for filter in &mut self.filter_sets {
392            filter.with.grow_and_insert(index.sparse_set_index());
393        }
394    }
395
396    /// Adds a `Without` filter: corresponds to a conjunction (AND) operation.
397    ///
398    /// Suppose we begin with `Or<(With<A>, With<B>)>`, which is represented by an array of two `AccessFilter` instances.
399    /// Adding `AND Without<C>` via this method transforms it into the equivalent of  `Or<((With<A>, Without<C>), (With<B>, Without<C>))>`.
400    pub fn and_without(&mut self, index: T) {
401        for filter in &mut self.filter_sets {
402            filter.without.grow_and_insert(index.sparse_set_index());
403        }
404    }
405
406    /// Appends an array of filters: corresponds to a disjunction (OR) operation.
407    ///
408    /// As the underlying array of filters represents a disjunction,
409    /// where each element (`AccessFilters`) represents a conjunction,
410    /// we can simply append to the array.
411    pub fn append_or(&mut self, other: &FilteredAccess<T>) {
412        self.filter_sets.append(&mut other.filter_sets.clone());
413    }
414
415    /// Adds all of the accesses from `other` to `self`.
416    pub fn extend_access(&mut self, other: &FilteredAccess<T>) {
417        self.access.extend(&other.access);
418    }
419
420    /// Returns `true` if this and `other` can be active at the same time.
421    pub fn is_compatible(&self, other: &FilteredAccess<T>) -> bool {
422        if self.access.is_compatible(&other.access) {
423            return true;
424        }
425
426        // If the access instances are incompatible, we want to check that whether filters can
427        // guarantee that queries are disjoint.
428        // Since the `filter_sets` array represents a Disjunctive Normal Form formula ("ORs of ANDs"),
429        // we need to make sure that each filter set (ANDs) rule out every filter set from the `other` instance.
430        //
431        // For example, `Query<&mut C, Or<(With<A>, Without<B>)>>` is compatible `Query<&mut C, (With<B>, Without<A>)>`,
432        // but `Query<&mut C, Or<(Without<A>, Without<B>)>>` isn't compatible with `Query<&mut C, Or<(With<A>, With<B>)>>`.
433        self.filter_sets.iter().all(|filter| {
434            other
435                .filter_sets
436                .iter()
437                .all(|other_filter| filter.is_ruled_out_by(other_filter))
438        })
439    }
440
441    /// Returns a vector of elements that this and `other` cannot access at the same time.
442    pub fn get_conflicts(&self, other: &FilteredAccess<T>) -> Vec<T> {
443        if !self.is_compatible(other) {
444            // filters are disjoint, so we can just look at the unfiltered intersection
445            return self.access.get_conflicts(&other.access);
446        }
447        Vec::new()
448    }
449
450    /// Adds all access and filters from `other`.
451    ///
452    /// Corresponds to a conjunction operation (AND) for filters.
453    ///
454    /// Extending `Or<(With<A>, Without<B>)>` with `Or<(With<C>, Without<D>)>` will result in
455    /// `Or<((With<A>, With<C>), (With<A>, Without<D>), (Without<B>, With<C>), (Without<B>, Without<D>))>`.
456    pub fn extend(&mut self, other: &FilteredAccess<T>) {
457        self.access.extend(&other.access);
458        self.required.union_with(&other.required);
459
460        // We can avoid allocating a new array of bitsets if `other` contains just a single set of filters:
461        // in this case we can short-circuit by performing an in-place union for each bitset.
462        if other.filter_sets.len() == 1 {
463            for filter in &mut self.filter_sets {
464                filter.with.union_with(&other.filter_sets[0].with);
465                filter.without.union_with(&other.filter_sets[0].without);
466            }
467            return;
468        }
469
470        let mut new_filters = Vec::with_capacity(self.filter_sets.len() * other.filter_sets.len());
471        for filter in &self.filter_sets {
472            for other_filter in &other.filter_sets {
473                let mut new_filter = filter.clone();
474                new_filter.with.union_with(&other_filter.with);
475                new_filter.without.union_with(&other_filter.without);
476                new_filters.push(new_filter);
477            }
478        }
479        self.filter_sets = new_filters;
480    }
481
482    /// Sets the underlying unfiltered access as having access to all indexed elements.
483    pub fn read_all(&mut self) {
484        self.access.read_all();
485    }
486
487    /// Sets the underlying unfiltered access as having mutable access to all indexed elements.
488    pub fn write_all(&mut self) {
489        self.access.write_all();
490    }
491
492    /// Returns `true` if the set is a subset of another, i.e. `other` contains
493    /// at least all the values in `self`.
494    pub fn is_subset(&self, other: &FilteredAccess<T>) -> bool {
495        self.required.is_subset(&other.required) && self.access().is_subset(other.access())
496    }
497
498    /// Returns the indices of the elements that this access filters for.
499    pub fn with_filters(&self) -> impl Iterator<Item = T> + '_ {
500        self.filter_sets
501            .iter()
502            .flat_map(|f| f.with.ones().map(T::get_sparse_set_index))
503    }
504
505    /// Returns the indices of the elements that this access filters out.
506    pub fn without_filters(&self) -> impl Iterator<Item = T> + '_ {
507        self.filter_sets
508            .iter()
509            .flat_map(|f| f.without.ones().map(T::get_sparse_set_index))
510    }
511}
512
513#[derive(Clone, Eq, PartialEq)]
514pub(crate) struct AccessFilters<T> {
515    pub(crate) with: FixedBitSet,
516    pub(crate) without: FixedBitSet,
517    _index_type: PhantomData<T>,
518}
519
520impl<T: SparseSetIndex + fmt::Debug> fmt::Debug for AccessFilters<T> {
521    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
522        f.debug_struct("AccessFilters")
523            .field("with", &FormattedBitSet::<T>::new(&self.with))
524            .field("without", &FormattedBitSet::<T>::new(&self.without))
525            .finish()
526    }
527}
528
529impl<T: SparseSetIndex> Default for AccessFilters<T> {
530    fn default() -> Self {
531        Self {
532            with: FixedBitSet::default(),
533            without: FixedBitSet::default(),
534            _index_type: PhantomData,
535        }
536    }
537}
538
539impl<T: SparseSetIndex> AccessFilters<T> {
540    fn is_ruled_out_by(&self, other: &Self) -> bool {
541        // Although not technically complete, we don't consider the case when `AccessFilters`'s
542        // `without` bitset contradicts its own `with` bitset (e.g. `(With<A>, Without<A>)`).
543        // Such query would be considered compatible with any other query, but as it's almost
544        // always an error, we ignore this case instead of treating such query as compatible
545        // with others.
546        !self.with.is_disjoint(&other.without) || !self.without.is_disjoint(&other.with)
547    }
548}
549
550/// A collection of [`FilteredAccess`] instances.
551///
552/// Used internally to statically check if systems have conflicting access.
553///
554/// It stores multiple sets of accesses.
555/// - A "combined" set, which is the access of all filters in this set combined.
556/// - The set of access of each individual filters in this set.
557#[derive(Debug, Clone)]
558pub struct FilteredAccessSet<T: SparseSetIndex> {
559    combined_access: Access<T>,
560    filtered_accesses: Vec<FilteredAccess<T>>,
561}
562
563impl<T: SparseSetIndex> FilteredAccessSet<T> {
564    /// Returns a reference to the unfiltered access of the entire set.
565    #[inline]
566    pub fn combined_access(&self) -> &Access<T> {
567        &self.combined_access
568    }
569
570    /// Returns `true` if this and `other` can be active at the same time.
571    ///
572    /// Access conflict resolution happen in two steps:
573    /// 1. A "coarse" check, if there is no mutual unfiltered conflict between
574    ///    `self` and `other`, we already know that the two access sets are
575    ///    compatible.
576    /// 2. A "fine grained" check, it kicks in when the "coarse" check fails.
577    ///    the two access sets might still be compatible if some of the accesses
578    ///    are restricted with the [`With`](super::With) or [`Without`](super::Without) filters so that access is
579    ///    mutually exclusive. The fine grained phase iterates over all filters in
580    ///    the `self` set and compares it to all the filters in the `other` set,
581    ///    making sure they are all mutually compatible.
582    pub fn is_compatible(&self, other: &FilteredAccessSet<T>) -> bool {
583        if self.combined_access.is_compatible(other.combined_access()) {
584            return true;
585        }
586        for filtered in &self.filtered_accesses {
587            for other_filtered in &other.filtered_accesses {
588                if !filtered.is_compatible(other_filtered) {
589                    return false;
590                }
591            }
592        }
593        true
594    }
595
596    /// Returns a vector of elements that this set and `other` cannot access at the same time.
597    pub fn get_conflicts(&self, other: &FilteredAccessSet<T>) -> Vec<T> {
598        // if the unfiltered access is incompatible, must check each pair
599        let mut conflicts = HashSet::new();
600        if !self.combined_access.is_compatible(other.combined_access()) {
601            for filtered in &self.filtered_accesses {
602                for other_filtered in &other.filtered_accesses {
603                    conflicts.extend(filtered.get_conflicts(other_filtered).into_iter());
604                }
605            }
606        }
607        conflicts.into_iter().collect()
608    }
609
610    /// Returns a vector of elements that this set and `other` cannot access at the same time.
611    pub fn get_conflicts_single(&self, filtered_access: &FilteredAccess<T>) -> Vec<T> {
612        // if the unfiltered access is incompatible, must check each pair
613        let mut conflicts = HashSet::new();
614        if !self.combined_access.is_compatible(filtered_access.access()) {
615            for filtered in &self.filtered_accesses {
616                conflicts.extend(filtered.get_conflicts(filtered_access).into_iter());
617            }
618        }
619        conflicts.into_iter().collect()
620    }
621
622    /// Adds the filtered access to the set.
623    pub fn add(&mut self, filtered_access: FilteredAccess<T>) {
624        self.combined_access.extend(&filtered_access.access);
625        self.filtered_accesses.push(filtered_access);
626    }
627
628    /// Adds a read access without filters to the set.
629    pub(crate) fn add_unfiltered_read(&mut self, index: T) {
630        let mut filter = FilteredAccess::default();
631        filter.add_read(index);
632        self.add(filter);
633    }
634
635    /// Adds a write access without filters to the set.
636    pub(crate) fn add_unfiltered_write(&mut self, index: T) {
637        let mut filter = FilteredAccess::default();
638        filter.add_write(index);
639        self.add(filter);
640    }
641
642    /// Adds all of the accesses from the passed set to `self`.
643    pub fn extend(&mut self, filtered_access_set: FilteredAccessSet<T>) {
644        self.combined_access
645            .extend(&filtered_access_set.combined_access);
646        self.filtered_accesses
647            .extend(filtered_access_set.filtered_accesses);
648    }
649
650    /// Marks the set as reading all possible indices of type T.
651    pub fn read_all(&mut self) {
652        self.combined_access.read_all();
653    }
654
655    /// Marks the set as writing all T.
656    pub fn write_all(&mut self) {
657        self.combined_access.write_all();
658    }
659
660    /// Removes all accesses stored in this set.
661    pub fn clear(&mut self) {
662        self.combined_access.clear();
663        self.filtered_accesses.clear();
664    }
665}
666
667impl<T: SparseSetIndex> Default for FilteredAccessSet<T> {
668    fn default() -> Self {
669        Self {
670            combined_access: Default::default(),
671            filtered_accesses: Vec::new(),
672        }
673    }
674}
675
676#[cfg(test)]
677mod tests {
678    use crate::query::access::AccessFilters;
679    use crate::query::{Access, FilteredAccess, FilteredAccessSet};
680    use fixedbitset::FixedBitSet;
681    use std::marker::PhantomData;
682
683    #[test]
684    fn read_all_access_conflicts() {
685        // read_all / single write
686        let mut access_a = Access::<usize>::default();
687        access_a.add_write(0);
688
689        let mut access_b = Access::<usize>::default();
690        access_b.read_all();
691
692        assert!(!access_b.is_compatible(&access_a));
693
694        // read_all / read_all
695        let mut access_a = Access::<usize>::default();
696        access_a.read_all();
697
698        let mut access_b = Access::<usize>::default();
699        access_b.read_all();
700
701        assert!(access_b.is_compatible(&access_a));
702    }
703
704    #[test]
705    fn access_get_conflicts() {
706        let mut access_a = Access::<usize>::default();
707        access_a.add_read(0);
708        access_a.add_read(1);
709
710        let mut access_b = Access::<usize>::default();
711        access_b.add_read(0);
712        access_b.add_write(1);
713
714        assert_eq!(access_a.get_conflicts(&access_b), vec![1]);
715
716        let mut access_c = Access::<usize>::default();
717        access_c.add_write(0);
718        access_c.add_write(1);
719
720        assert_eq!(access_a.get_conflicts(&access_c), vec![0, 1]);
721        assert_eq!(access_b.get_conflicts(&access_c), vec![0, 1]);
722
723        let mut access_d = Access::<usize>::default();
724        access_d.add_read(0);
725
726        assert_eq!(access_d.get_conflicts(&access_a), vec![]);
727        assert_eq!(access_d.get_conflicts(&access_b), vec![]);
728        assert_eq!(access_d.get_conflicts(&access_c), vec![0]);
729    }
730
731    #[test]
732    fn filtered_combined_access() {
733        let mut access_a = FilteredAccessSet::<usize>::default();
734        access_a.add_unfiltered_read(1);
735
736        let mut filter_b = FilteredAccess::<usize>::default();
737        filter_b.add_write(1);
738
739        let conflicts = access_a.get_conflicts_single(&filter_b);
740        assert_eq!(
741            &conflicts,
742            &[1_usize],
743            "access_a: {access_a:?}, filter_b: {filter_b:?}"
744        );
745    }
746
747    #[test]
748    fn filtered_access_extend() {
749        let mut access_a = FilteredAccess::<usize>::default();
750        access_a.add_read(0);
751        access_a.add_read(1);
752        access_a.and_with(2);
753
754        let mut access_b = FilteredAccess::<usize>::default();
755        access_b.add_read(0);
756        access_b.add_write(3);
757        access_b.and_without(4);
758
759        access_a.extend(&access_b);
760
761        let mut expected = FilteredAccess::<usize>::default();
762        expected.add_read(0);
763        expected.add_read(1);
764        expected.and_with(2);
765        expected.add_write(3);
766        expected.and_without(4);
767
768        assert!(access_a.eq(&expected));
769    }
770
771    #[test]
772    fn filtered_access_extend_or() {
773        let mut access_a = FilteredAccess::<usize>::default();
774        // Exclusive access to `(&mut A, &mut B)`.
775        access_a.add_write(0);
776        access_a.add_write(1);
777
778        // Filter by `With<C>`.
779        let mut access_b = FilteredAccess::<usize>::default();
780        access_b.and_with(2);
781
782        // Filter by `(With<D>, Without<E>)`.
783        let mut access_c = FilteredAccess::<usize>::default();
784        access_c.and_with(3);
785        access_c.and_without(4);
786
787        // Turns `access_b` into `Or<(With<C>, (With<D>, Without<D>))>`.
788        access_b.append_or(&access_c);
789        // Applies the filters to the initial query, which corresponds to the FilteredAccess'
790        // representation of `Query<(&mut A, &mut B), Or<(With<C>, (With<D>, Without<E>))>>`.
791        access_a.extend(&access_b);
792
793        // Construct the expected `FilteredAccess` struct.
794        // The intention here is to test that exclusive access implied by `add_write`
795        // forms correct normalized access structs when extended with `Or` filters.
796        let mut expected = FilteredAccess::<usize>::default();
797        expected.add_write(0);
798        expected.add_write(1);
799        // The resulted access is expected to represent `Or<((With<A>, With<B>, With<C>), (With<A>, With<B>, With<D>, Without<E>))>`.
800        expected.filter_sets = vec![
801            AccessFilters {
802                with: FixedBitSet::with_capacity_and_blocks(3, [0b111]),
803                without: FixedBitSet::default(),
804                _index_type: PhantomData,
805            },
806            AccessFilters {
807                with: FixedBitSet::with_capacity_and_blocks(4, [0b1011]),
808                without: FixedBitSet::with_capacity_and_blocks(5, [0b10000]),
809                _index_type: PhantomData,
810            },
811        ];
812
813        assert_eq!(access_a, expected);
814    }
815}