Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose query accesses #11700

Merged
merged 10 commits into from
Feb 10, 2024
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions crates/bevy_ecs/src/query/access.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
JoJoJet marked this conversation as resolved.
Show resolved Hide resolved
marker: PhantomData<T>,
}

Expand Down Expand Up @@ -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,
}
}
Expand All @@ -116,6 +119,15 @@ 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.
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())
Expand All @@ -136,6 +148,14 @@ 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.
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;
Expand Down Expand Up @@ -272,6 +292,14 @@ 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.
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.
Expand Down Expand Up @@ -469,6 +497,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)]
Expand Down
20 changes: 20 additions & 0 deletions crates/bevy_ecs/src/query/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
alice-i-cecile marked this conversation as resolved.
Show resolved Hide resolved
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> {
Expand Down
Loading