mirror of
https://github.com/bevyengine/bevy
synced 2024-11-22 12:43:34 +00:00
Expose query accesses (#11700)
# Objective It would be useful to be able to inspect a `QueryState`'s accesses so we can detect when the data it accesses changes without having to iterate it. However there are two things preventing this: * These accesses are unnecessarily encapsulated. * `Has<T>` indirectly accesses `T`, but does not register it. ## Solution * Expose accesses and matches used by `QueryState`. * Add the notion of "archetypal" accesses, which are not accessed directly, but whose presence in an archetype affects a query result. --------- Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
This commit is contained in:
parent
33676112da
commit
2e2f89869b
3 changed files with 79 additions and 2 deletions
|
@ -59,6 +59,8 @@ pub struct Access<T: SparseSetIndex> {
|
|||
/// Is `true` if this has mutable access to all elements in the collection.
|
||||
/// If this is true, then `reads_all` must also be true.
|
||||
writes_all: bool,
|
||||
// Elements that are not accessed, but whose presence in an archetype affect query results.
|
||||
archetypal: FixedBitSet,
|
||||
marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
|
@ -90,6 +92,7 @@ impl<T: SparseSetIndex> Access<T> {
|
|||
writes_all: false,
|
||||
reads_and_writes: FixedBitSet::new(),
|
||||
writes: FixedBitSet::new(),
|
||||
archetypal: FixedBitSet::new(),
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
@ -116,6 +119,19 @@ impl<T: SparseSetIndex> Access<T> {
|
|||
self.writes.insert(index.sparse_set_index());
|
||||
}
|
||||
|
||||
/// Adds an archetypal (indirect) access to the element given by `index`.
|
||||
///
|
||||
/// This is for elements whose values are not accessed (and thus will never cause conflicts),
|
||||
/// but whose presence in an archetype may affect query results.
|
||||
///
|
||||
/// Currently, this is only used for [`Has<T>`].
|
||||
///
|
||||
/// [`Has<T>`]: crate::query::Has
|
||||
pub fn add_archetypal(&mut self, index: T) {
|
||||
self.archetypal.grow(index.sparse_set_index() + 1);
|
||||
self.archetypal.insert(index.sparse_set_index());
|
||||
}
|
||||
|
||||
/// Returns `true` if this can access the element given by `index`.
|
||||
pub fn has_read(&self, index: T) -> bool {
|
||||
self.reads_all || self.reads_and_writes.contains(index.sparse_set_index())
|
||||
|
@ -136,6 +152,18 @@ impl<T: SparseSetIndex> Access<T> {
|
|||
self.writes_all || !self.writes.is_clear()
|
||||
}
|
||||
|
||||
/// Returns true if this has an archetypal (indirect) access to the element given by `index`.
|
||||
///
|
||||
/// This is an element whose value is not accessed (and thus will never cause conflicts),
|
||||
/// but whose presence in an archetype may affect query results.
|
||||
///
|
||||
/// Currently, this is only used for [`Has<T>`].
|
||||
///
|
||||
/// [`Has<T>`]: crate::query::Has
|
||||
pub fn has_archetypal(&self, index: T) -> bool {
|
||||
self.archetypal.contains(index.sparse_set_index())
|
||||
}
|
||||
|
||||
/// Sets this as having access to all indexed elements (i.e. `&World`).
|
||||
pub fn read_all(&mut self) {
|
||||
self.reads_all = true;
|
||||
|
@ -272,6 +300,18 @@ impl<T: SparseSetIndex> Access<T> {
|
|||
pub fn writes(&self) -> impl Iterator<Item = T> + '_ {
|
||||
self.writes.ones().map(T::get_sparse_set_index)
|
||||
}
|
||||
|
||||
/// Returns the indices of the elements that this has an archetypal access to.
|
||||
///
|
||||
/// These are elements whose values are not accessed (and thus will never cause conflicts),
|
||||
/// but whose presence in an archetype may affect query results.
|
||||
///
|
||||
/// Currently, this is only used for [`Has<T>`].
|
||||
///
|
||||
/// [`Has<T>`]: crate::query::Has
|
||||
pub fn archetypal(&self) -> impl Iterator<Item = T> + '_ {
|
||||
self.archetypal.ones().map(T::get_sparse_set_index)
|
||||
}
|
||||
}
|
||||
|
||||
/// An [`Access`] that has been filtered to include and exclude certain combinations of elements.
|
||||
|
@ -469,6 +509,20 @@ impl<T: SparseSetIndex> FilteredAccess<T> {
|
|||
pub fn is_subset(&self, other: &FilteredAccess<T>) -> bool {
|
||||
self.required.is_subset(&other.required) && self.access().is_subset(other.access())
|
||||
}
|
||||
|
||||
/// Returns the indices of the elements that this access filters for.
|
||||
pub fn with_filters(&self) -> impl Iterator<Item = T> + '_ {
|
||||
self.filter_sets
|
||||
.iter()
|
||||
.flat_map(|f| f.with.ones().map(T::get_sparse_set_index))
|
||||
}
|
||||
|
||||
/// Returns the indices of the elements that this access filters out.
|
||||
pub fn without_filters(&self) -> impl Iterator<Item = T> + '_ {
|
||||
self.filter_sets
|
||||
.iter()
|
||||
.flat_map(|f| f.without.ones().map(T::get_sparse_set_index))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Eq, PartialEq)]
|
||||
|
|
|
@ -1403,8 +1403,11 @@ unsafe impl<T: Component> WorldQuery for Has<T> {
|
|||
*fetch
|
||||
}
|
||||
|
||||
fn update_component_access(_state: &Self::State, _access: &mut FilteredAccess<ComponentId>) {
|
||||
// Do nothing as presence of `Has<T>` never affects whether two queries are disjoint
|
||||
fn update_component_access(
|
||||
&component_id: &Self::State,
|
||||
access: &mut FilteredAccess<ComponentId>,
|
||||
) {
|
||||
access.access_mut().add_archetypal(component_id);
|
||||
}
|
||||
|
||||
fn init_state(world: &mut World) -> ComponentId {
|
||||
|
|
|
@ -95,6 +95,26 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
|||
) -> &QueryState<NewD, NewF> {
|
||||
&*(self as *const QueryState<D, F> as *const QueryState<NewD, NewF>)
|
||||
}
|
||||
|
||||
/// Returns the archetype components accessed by this query.
|
||||
pub fn archetype_component_access(&self) -> &Access<ArchetypeComponentId> {
|
||||
&self.archetype_component_access
|
||||
}
|
||||
|
||||
/// Returns the components accessed by this query.
|
||||
pub fn component_access(&self) -> &FilteredAccess<ComponentId> {
|
||||
&self.component_access
|
||||
}
|
||||
|
||||
/// Returns the tables matched by this query.
|
||||
pub fn matched_tables(&self) -> &[TableId] {
|
||||
&self.matched_table_ids
|
||||
}
|
||||
|
||||
/// Returns the archetypes matched by this query.
|
||||
pub fn matched_archetypes(&self) -> &[ArchetypeId] {
|
||||
&self.matched_archetype_ids
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
|
|
Loading…
Reference in a new issue