From 29f2beb475c9e247ca95d11727390c3d48cff1ff Mon Sep 17 00:00:00 2001 From: Joseph <21144246+JoJoJet@users.noreply.github.com> Date: Sun, 4 Feb 2024 10:09:37 -0800 Subject: [PATCH 01/10] expose QueryState accesses and matches --- crates/bevy_ecs/src/query/state.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/crates/bevy_ecs/src/query/state.rs b/crates/bevy_ecs/src/query/state.rs index 666549d52a6f3..70794527c8449 100644 --- a/crates/bevy_ecs/src/query/state.rs +++ b/crates/bevy_ecs/src/query/state.rs @@ -95,6 +95,26 @@ impl QueryState { ) -> &QueryState { &*(self as *const QueryState as *const QueryState) } + + /// Returns the archetype components accessed by this query. + pub fn archetype_component_access(&self) -> &Access { + &self.archetype_component_access + } + + /// Returns the components accessed by this query. + pub fn component_access(&self) -> &FilteredAccess { + &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 QueryState { From dfc4c398dc234dcbc3b2c4de7350d3fdbd7ff557 Mon Sep 17 00:00:00 2001 From: Joseph <21144246+JoJoJet@users.noreply.github.com> Date: Sun, 4 Feb 2024 10:11:56 -0800 Subject: [PATCH 02/10] expose with and without --- crates/bevy_ecs/src/query/access.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/crates/bevy_ecs/src/query/access.rs b/crates/bevy_ecs/src/query/access.rs index d7253f073ed7f..8a3907a0433b2 100644 --- a/crates/bevy_ecs/src/query/access.rs +++ b/crates/bevy_ecs/src/query/access.rs @@ -469,6 +469,20 @@ impl FilteredAccess { pub fn is_subset(&self, other: &FilteredAccess) -> bool { self.required.is_subset(&other.required) && self.access().is_subset(other.access()) } + + /// Returns the components this access filters for. + pub fn get_with(&self) -> impl Iterator + '_ { + self.filter_sets + .iter() + .flat_map(|f| f.with.ones().map(T::get_sparse_set_index)) + } + + /// Returns the components this access filters out. + pub fn get_without(&self) -> impl Iterator + '_ { + self.filter_sets + .iter() + .flat_map(|f| f.without.ones().map(T::get_sparse_set_index)) + } } #[derive(Clone, Eq, PartialEq)] From 6565640604973c2dd52e4897ce28252a8895727e Mon Sep 17 00:00:00 2001 From: Joseph <21144246+JoJoJet@users.noreply.github.com> Date: Sun, 4 Feb 2024 10:15:55 -0800 Subject: [PATCH 03/10] add archetypal accesses --- crates/bevy_ecs/src/query/access.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/crates/bevy_ecs/src/query/access.rs b/crates/bevy_ecs/src/query/access.rs index 8a3907a0433b2..6124230432ab1 100644 --- a/crates/bevy_ecs/src/query/access.rs +++ b/crates/bevy_ecs/src/query/access.rs @@ -59,6 +59,8 @@ pub struct Access { /// 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, } @@ -90,6 +92,7 @@ impl Access { writes_all: false, reads_and_writes: FixedBitSet::new(), writes: FixedBitSet::new(), + archetypal: FixedBitSet::new(), marker: PhantomData, } } @@ -116,6 +119,12 @@ impl Access { self.writes.insert(index.sparse_set_index()); } + /// Adds an archetypal (inderect) access to the element given by `index`. + 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 +145,14 @@ impl Access { 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 that is not accessed (and thus will never lead to conflicts), + /// but whose presence in an archetype affects a query result. + 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 +289,14 @@ impl Access { pub fn writes(&self) -> impl Iterator + '_ { self.writes.ones().map(T::get_sparse_set_index) } + + /// Returns the indices of the elements that this has an archetypal access to. + /// + /// Archetypal accesses will never lead to conflicts, but the presence of the data + /// they refer to affects query results + pub fn archetypal(&self) -> impl Iterator + '_ { + self.archetypal.ones().map(T::get_sparse_set_index) + } } /// An [`Access`] that has been filtered to include and exclude certain combinations of elements. From baa3eea68bab10acf3749235e2a78f5894ac4298 Mon Sep 17 00:00:00 2001 From: Joseph <21144246+JoJoJet@users.noreply.github.com> Date: Sun, 4 Feb 2024 10:24:36 -0800 Subject: [PATCH 04/10] cargo fmt --- crates/bevy_ecs/src/query/access.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/bevy_ecs/src/query/access.rs b/crates/bevy_ecs/src/query/access.rs index 6124230432ab1..dcd532df54596 100644 --- a/crates/bevy_ecs/src/query/access.rs +++ b/crates/bevy_ecs/src/query/access.rs @@ -146,7 +146,7 @@ impl Access { } /// Returns true if this has an archetypal (indirect) access to the element given by `index`. - /// + /// /// This is an element that is not accessed (and thus will never lead to conflicts), /// but whose presence in an archetype affects a query result. pub fn has_archetypal(&self, index: T) -> bool { @@ -291,7 +291,7 @@ impl Access { } /// Returns the indices of the elements that this has an archetypal access to. - /// + /// /// Archetypal accesses will never lead to conflicts, but the presence of the data /// they refer to affects query results pub fn archetypal(&self) -> impl Iterator + '_ { From 8e3ec35dfa8dd584478adbeaa3503cea3b51b454 Mon Sep 17 00:00:00 2001 From: Joseph <21144246+JoJoJet@users.noreply.github.com> Date: Sun, 4 Feb 2024 12:33:19 -0800 Subject: [PATCH 05/10] naming and docs --- crates/bevy_ecs/src/query/access.rs | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/crates/bevy_ecs/src/query/access.rs b/crates/bevy_ecs/src/query/access.rs index dcd532df54596..d7669c1f9fa5c 100644 --- a/crates/bevy_ecs/src/query/access.rs +++ b/crates/bevy_ecs/src/query/access.rs @@ -119,7 +119,10 @@ impl Access { self.writes.insert(index.sparse_set_index()); } - /// Adds an archetypal (inderect) access to the element given by `index`. + /// Adds an archetypal (indirect) access to the element given by `index`. + /// + /// This is for elements that are not accessed (and thus will never cause to 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()); @@ -147,8 +150,8 @@ impl Access { /// Returns true if this has an archetypal (indirect) access to the element given by `index`. /// - /// This is an element that is not accessed (and thus will never lead to conflicts), - /// but whose presence in an archetype affects a query result. + /// This is an element that 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()) } @@ -292,8 +295,8 @@ impl Access { /// Returns the indices of the elements that this has an archetypal access to. /// - /// Archetypal accesses will never lead to conflicts, but the presence of the data - /// they refer to affects query results + /// These are elements that are not access (and thus will never cause conflicts), + /// but whose presence in an archetype may affect query results. pub fn archetypal(&self) -> impl Iterator + '_ { self.archetypal.ones().map(T::get_sparse_set_index) } @@ -495,15 +498,15 @@ impl FilteredAccess { self.required.is_subset(&other.required) && self.access().is_subset(other.access()) } - /// Returns the components this access filters for. - pub fn get_with(&self) -> impl Iterator + '_ { + /// Returns the indices of the elements that this access filters for. + pub fn with_filters(&self) -> impl Iterator + '_ { self.filter_sets .iter() .flat_map(|f| f.with.ones().map(T::get_sparse_set_index)) } - /// Returns the components this access filters out. - pub fn get_without(&self) -> impl Iterator + '_ { + /// Returns the indices of the elements that this access filters out. + pub fn without_filters(&self) -> impl Iterator + '_ { self.filter_sets .iter() .flat_map(|f| f.without.ones().map(T::get_sparse_set_index)) From c470368ba6cc5235c49664213461a7210b036275 Mon Sep 17 00:00:00 2001 From: Joseph <21144246+JoJoJet@users.noreply.github.com> Date: Sun, 4 Feb 2024 12:34:25 -0800 Subject: [PATCH 06/10] remove leftover word --- crates/bevy_ecs/src/query/access.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_ecs/src/query/access.rs b/crates/bevy_ecs/src/query/access.rs index d7669c1f9fa5c..2748b464ec61b 100644 --- a/crates/bevy_ecs/src/query/access.rs +++ b/crates/bevy_ecs/src/query/access.rs @@ -121,7 +121,7 @@ impl Access { /// Adds an archetypal (indirect) access to the element given by `index`. /// - /// This is for elements that are not accessed (and thus will never cause to conflicts), + /// This is for elements that 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); From a05a168d9bd6fb24bf9d0ce2ca35a672949dc8de Mon Sep 17 00:00:00 2001 From: Joseph <21144246+JoJoJet@users.noreply.github.com> Date: Sun, 4 Feb 2024 12:42:43 -0800 Subject: [PATCH 07/10] past participle --- crates/bevy_ecs/src/query/access.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_ecs/src/query/access.rs b/crates/bevy_ecs/src/query/access.rs index 2748b464ec61b..82ba4c542d7ca 100644 --- a/crates/bevy_ecs/src/query/access.rs +++ b/crates/bevy_ecs/src/query/access.rs @@ -295,7 +295,7 @@ impl Access { /// Returns the indices of the elements that this has an archetypal access to. /// - /// These are elements that are not access (and thus will never cause conflicts), + /// These are elements that 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 + '_ { self.archetypal.ones().map(T::get_sparse_set_index) From 0f31b8bdb644b0a02fc73992b98dfdce29cfac47 Mon Sep 17 00:00:00 2001 From: Joseph <21144246+JoJoJet@users.noreply.github.com> Date: Sun, 4 Feb 2024 15:07:38 -0800 Subject: [PATCH 08/10] Apply suggestions from code review Co-authored-by: Alice Cecile --- crates/bevy_ecs/src/query/access.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/bevy_ecs/src/query/access.rs b/crates/bevy_ecs/src/query/access.rs index 82ba4c542d7ca..1e25e8885204b 100644 --- a/crates/bevy_ecs/src/query/access.rs +++ b/crates/bevy_ecs/src/query/access.rs @@ -121,7 +121,7 @@ impl Access { /// Adds an archetypal (indirect) access to the element given by `index`. /// - /// This is for elements that are not accessed (and thus will never cause conflicts), + /// 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); @@ -150,7 +150,7 @@ impl Access { /// Returns true if this has an archetypal (indirect) access to the element given by `index`. /// - /// This is an element that is not accessed (and thus will never cause conflicts), + /// 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()) @@ -295,7 +295,7 @@ impl Access { /// Returns the indices of the elements that this has an archetypal access to. /// - /// These are elements that are not accessed (and thus will never cause conflicts), + /// 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 + '_ { self.archetypal.ones().map(T::get_sparse_set_index) From a4aec41109404fe4d0b2a7e35a3232fdf3f037c6 Mon Sep 17 00:00:00 2001 From: Joseph <21144246+JoJoJet@users.noreply.github.com> Date: Tue, 6 Feb 2024 19:49:31 -0800 Subject: [PATCH 09/10] register Has accesses --- crates/bevy_ecs/src/query/fetch.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/bevy_ecs/src/query/fetch.rs b/crates/bevy_ecs/src/query/fetch.rs index 5e83637d33019..5713dd4f13b43 100644 --- a/crates/bevy_ecs/src/query/fetch.rs +++ b/crates/bevy_ecs/src/query/fetch.rs @@ -1403,8 +1403,8 @@ unsafe impl WorldQuery for Has { *fetch } - fn update_component_access(_state: &Self::State, _access: &mut FilteredAccess) { - // Do nothing as presence of `Has` never affects whether two queries are disjoint + fn update_component_access(&component_id: &Self::State, access: &mut FilteredAccess) { + access.access_mut().add_archetypal(component_id); } fn init_state(world: &mut World) -> ComponentId { From 2629b2f7f871cf5cb60ee3941b2cc9c8f2d2c678 Mon Sep 17 00:00:00 2001 From: Joseph <21144246+JoJoJet@users.noreply.github.com> Date: Tue, 6 Feb 2024 19:51:35 -0800 Subject: [PATCH 10/10] clarify consumers --- crates/bevy_ecs/src/query/access.rs | 12 ++++++++++++ crates/bevy_ecs/src/query/fetch.rs | 5 ++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/crates/bevy_ecs/src/query/access.rs b/crates/bevy_ecs/src/query/access.rs index 1e25e8885204b..848309be77ecc 100644 --- a/crates/bevy_ecs/src/query/access.rs +++ b/crates/bevy_ecs/src/query/access.rs @@ -123,6 +123,10 @@ impl Access { /// /// 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`]. + /// + /// [`Has`]: 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()); @@ -152,6 +156,10 @@ impl Access { /// /// 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`]. + /// + /// [`Has`]: crate::query::Has pub fn has_archetypal(&self, index: T) -> bool { self.archetypal.contains(index.sparse_set_index()) } @@ -297,6 +305,10 @@ impl Access { /// /// 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`]. + /// + /// [`Has`]: crate::query::Has pub fn archetypal(&self) -> impl Iterator + '_ { self.archetypal.ones().map(T::get_sparse_set_index) } diff --git a/crates/bevy_ecs/src/query/fetch.rs b/crates/bevy_ecs/src/query/fetch.rs index 5713dd4f13b43..27f329c7b7103 100644 --- a/crates/bevy_ecs/src/query/fetch.rs +++ b/crates/bevy_ecs/src/query/fetch.rs @@ -1403,7 +1403,10 @@ unsafe impl WorldQuery for Has { *fetch } - fn update_component_access(&component_id: &Self::State, access: &mut FilteredAccess) { + fn update_component_access( + &component_id: &Self::State, + access: &mut FilteredAccess, + ) { access.access_mut().add_archetypal(component_id); }