Expose more data from FilteredAccess#23384
Conversation
…able as `pub`. Make `archetypal` available as a full `ComponentIdSet`, which is technically a breaking change.
release-content/migration-guides/Access-archetypal-return-type.md
Outdated
Show resolved
Hide resolved
alice-i-cecile
left a comment
There was a problem hiding this comment.
I much prefer the semantic newtype over ComponentIdSet: this would be worth doing on its own.
This information is fine to expose, and this is a good way to do so.
I would be happy if there were tests for ComponentIdSet, but I won't block on it :)
Yeah, I wouldn't have thought to do it without the motivation of exposing it more publicly, but once I thought of it I liked it even internally!
Oh, fine, I guess if I'm going to claim that this will let us change the implementation, then I need to actually back it up by having tests :). I'll try to add some on Wednesday! |
Freyja-moth
left a comment
There was a problem hiding this comment.
Can't see anything wrong and the newtype is appreciated
# 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 (bevyengine#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 bevyengine#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 bevyengine#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 <[email protected]>
Objective
Expose more data from
FilteredAccessto allow third-party crates to inspect queries. In particular, exposerequiredandfilter_sets, which will allow third-party implementations of query observers (#20817) to determine what component observers they will need.Solution
Add
pubmethods to exposerequiredandfilter_sets, makeAccessFilterspub, and add methods to exposewithandwithout.Add a
ComponentIdSettype that wrapsFixedBitSet. This allows us to expose the efficient set operations likeunion_withthat would not be available if we returned a simpleIterator<Item = ComponentId>. And not exposing theFixedBitSetdirectly avoids forcing users to manually convert betweenusizeandComponentId, and will let us change the implementation of the set (as in #18955) or representation ofComponentIdwithout 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: