Commit 9b91b56
Expose more data from
# Objective
Expose more data from `FilteredAccess` to allow third-party crates to
inspect queries. In particular, expose `required` and `filter_sets`,
which will allow third-party implementations of query observers (#20817)
to determine what component observers they will need.
## Solution
Add `pub` methods to expose `required` and `filter_sets`, make
`AccessFilters` `pub`, and add methods to expose `with` and `without`.
Add a `ComponentIdSet` type that wraps `FixedBitSet`. This allows us to
expose the efficient set operations like `union_with` that would not be
available if we returned a simple `Iterator<Item = ComponentId>`. And
not exposing the `FixedBitSet` directly avoids forcing users to manually
convert between `usize` and `ComponentId`, and will let us change the
implementation of the set (as in #18955) or representation of
`ComponentId` without changing the public API. It also simplifies the
internals a bit!
## Showcase
Here is how to calculate the component observers required for a query
observer in an implementation of #20817 using these APIs:
```rust
fn components_for_observers(
access: &FilteredAccess,
) -> (&ComponentIdSet, ComponentIdSet, ComponentIdSet) {
// We need `insert` observers for any component we read,
// since the value has changed.
// Unbounded access (`EntityRef`) is not supported,
// since we cannot add observers to all possible components.
let insert = access
.access()
.try_reads_and_writes()
.expect("Query observers do not support unbounded access");
// We need `add` observers for any component with archetypal access,
// since `Has` may have changed,
let mut add = access.access().archetypal().clone();
// and any component with `With` filters,
// since the query may start matching,
for filter_set in access.filter_sets() {
add.union_with(&filter_set.with());
}
// but not for any component already covered by `insert` observers
add.difference_with(insert);
// We need `remove` observers for any component we read or write,
// since `Option<&T>` may have changed,
let mut remove = insert.clone();
// and for any component with archetypal access,
// since `Has` may have changed,
remove.union_with(access.access().archetypal());
// and any component with `Without` filters,
// since the query may start matching,
for filter_set in access.filter_sets() {
add.union_with(&filter_set.without());
}
// but not for any required component,
// since it is guaranteed not to match after they are removed
// (otherwise every `&T` would add a `remove` observer!)
remove.difference_with(access.required());
(insert, add, remove)
}
```
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>FilteredAccess (#23384)1 parent 1aea391 commit 9b91b56
4 files changed
Lines changed: 462 additions & 195 deletions
File tree
- crates/bevy_ecs/src
- query
- schedule
- release-content/migration-guides
0 commit comments