From e0c92845858c4e27e21f780055159ccdc01ba4c8 Mon Sep 17 00:00:00 2001 From: Nathan Fenner Date: Fri, 29 Nov 2024 20:26:53 -0500 Subject: [PATCH 1/9] all `.include_entity()` helper on query iterators --- crates/bevy_ecs/src/query/fetch.rs | 6 ++ crates/bevy_ecs/src/query/iter.rs | 35 +++++++ crates/bevy_ecs/src/query/world_query.rs | 123 +++++++++++++++++++++++ 3 files changed, 164 insertions(+) diff --git a/crates/bevy_ecs/src/query/fetch.rs b/crates/bevy_ecs/src/query/fetch.rs index 08e06d03f4..01e3c0f435 100644 --- a/crates/bevy_ecs/src/query/fetch.rs +++ b/crates/bevy_ecs/src/query/fetch.rs @@ -305,6 +305,10 @@ pub unsafe trait QueryData: WorldQuery { ) -> Self::Item<'w>; } +unsafe impl QueryData for crate::query::IncludeEntity { + type ReadOnly = crate::query::IncludeEntity; +} + /// A [`QueryData`] that is read only. /// /// # Safety @@ -312,6 +316,8 @@ pub unsafe trait QueryData: WorldQuery { /// This must only be implemented for read-only [`QueryData`]'s. pub unsafe trait ReadOnlyQueryData: QueryData {} +unsafe impl ReadOnlyQueryData for crate::query::IncludeEntity {} + /// The item type returned when a [`WorldQuery`] is iterated over pub type QueryItem<'w, Q> = ::Item<'w>; /// The read-only variant of the item type returned when a [`QueryData`] is iterated over immutably diff --git a/crates/bevy_ecs/src/query/iter.rs b/crates/bevy_ecs/src/query/iter.rs index 172062b3a7..39d7332e96 100644 --- a/crates/bevy_ecs/src/query/iter.rs +++ b/crates/bevy_ecs/src/query/iter.rs @@ -875,6 +875,41 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIter<'w, 's, D, F> { ) } } + + /// Transforms the iterator output to include the `Entity` which is being iterated over. + /// + /// # Example + /// + /// ``` + /// use bevy_ecs::prelude::*; + /// #[derive(Component)] + /// struct ExampleComponent; + /// + /// fn example_system(query: Query<&ExampleComponent>) { + /// for (entity, component) in query.iter().include_entity() { + /// println!("entity {:?}", entity); + /// } + /// } + /// ``` + /// + pub fn include_entity(self) -> QueryIter<'w, 's, crate::query::IncludeEntity, F> { + QueryIter { + world: self.world, + tables: self.tables, + archetypes: self.archetypes, + query_state: unsafe { self.query_state.as_transmuted_state() }, + cursor: QueryIterationCursor { + is_dense: self.cursor.is_dense, + storage_id_iter: self.cursor.storage_id_iter, + table_entities: self.cursor.table_entities, + archetype_entities: self.cursor.archetype_entities, + fetch: self.cursor.fetch, + filter: self.cursor.filter, + current_len: self.cursor.current_len, + current_row: self.cursor.current_row, + }, + } + } } impl<'w, 's, D: QueryData, F: QueryFilter> Iterator for QueryIter<'w, 's, D, F> { diff --git a/crates/bevy_ecs/src/query/world_query.rs b/crates/bevy_ecs/src/query/world_query.rs index da147770e0..49db04623f 100644 --- a/crates/bevy_ecs/src/query/world_query.rs +++ b/crates/bevy_ecs/src/query/world_query.rs @@ -132,6 +132,129 @@ pub unsafe trait WorldQuery { ) -> bool; } +/// A wrapper type which includes the entity in the selected query data, +/// but which has the same underlying state as `D`. +/// +/// Most applications should use `(Entity, D)` instead; but unlike `(Entity, D)`, +/// it is guaranteed that `IncludeEntity` has the same `WorldQuery::State as `D`. +pub struct IncludeEntity(pub D); + +unsafe impl WorldQuery for IncludeEntity { + /// The item is the same as `D`, but also includes the entity. + type Item<'a> = (Entity, D::Item<'a>); + + /// The same underlying state is used for `IncludeEntity` as `D` itself. + type Fetch<'a> = D::Fetch<'a>; + + /// The same underlying state is used for `IncludeEntity` as `D` itself. + type State = D::State; + + /// This function manually implements subtyping for the query items. + /// The non-`Entity` query is shrunk exactly how `D` specifies. + fn shrink<'wlong: 'wshort, 'wshort>(item: Self::Item<'wlong>) -> Self::Item<'wshort> { + (item.0, D::shrink(item.1)) + } + + /// This function manually implements subtyping for the query items. + /// The query is shrunk exactly how `D` specifies. + fn shrink_fetch<'wlong: 'wshort, 'wshort>(fetch: Self::Fetch<'wlong>) -> Self::Fetch<'wshort> { + D::shrink_fetch(fetch) + } + + /// Creates a new instance of this fetch. + unsafe fn init_fetch<'w>( + world: UnsafeWorldCell<'w>, + state: &Self::State, + last_run: Tick, + this_run: Tick, + ) -> Self::Fetch<'w> { + D::init_fetch(world, state, last_run, this_run) + } + + const IS_DENSE: bool = D::IS_DENSE; + + /// # Safety + /// + /// - `archetype` and `tables` must be from the same [`World`] that [`WorldQuery::init_state`] was called on. + /// - `table` must correspond to `archetype`. + /// - `state` must be the [`State`](Self::State) that `fetch` was initialized with. + unsafe fn set_archetype<'w>( + fetch: &mut Self::Fetch<'w>, + state: &Self::State, + archetype: &'w Archetype, + table: &'w Table, + ) { + D::set_archetype(fetch, state, archetype, table); + } + + /// Adjusts internal state to account for the next [`Table`]. This will always be called on tables + /// that match this [`WorldQuery`]. + /// + /// # Safety + /// + /// - `table` must be from the same [`World`] that [`WorldQuery::init_state`] was called on. + /// - `state` must be the [`State`](Self::State) that `fetch` was initialized with. + unsafe fn set_table<'w>(fetch: &mut Self::Fetch<'w>, state: &Self::State, table: &'w Table) { + D::set_table(fetch, state, table); + } + + /// Sets available accesses for implementors with dynamic access such as [`FilteredEntityRef`](crate::world::FilteredEntityRef) + /// or [`FilteredEntityMut`](crate::world::FilteredEntityMut). + /// + /// Called when constructing a [`QueryLens`](crate::system::QueryLens) or calling [`QueryState::from_builder`](super::QueryState::from_builder) + fn set_access(state: &mut Self::State, access: &FilteredAccess) { + D::set_access(state, access); + } + + /// Fetch [`Self::Item`](`WorldQuery::Item`) for either the given `entity` in the current [`Table`], + /// or for the given `entity` in the current [`Archetype`]. This must always be called after + /// [`WorldQuery::set_table`] with a `table_row` in the range of the current [`Table`] or after + /// [`WorldQuery::set_archetype`] with a `entity` in the current archetype. + /// + /// # Safety + /// + /// Must always be called _after_ [`WorldQuery::set_table`] or [`WorldQuery::set_archetype`]. `entity` and + /// `table_row` must be in the range of the current table and archetype. + unsafe fn fetch<'w>( + fetch: &mut Self::Fetch<'w>, + entity: Entity, + table_row: TableRow, + ) -> Self::Item<'w> { + (entity, D::fetch(fetch, entity, table_row)) + } + + /// Adds any component accesses used by this [`WorldQuery`] to `access`. + /// + /// Used to check which queries are disjoint and can run in parallel + // This does not have a default body of `{}` because 99% of cases need to add accesses + // and forgetting to do so would be unsound. + fn update_component_access(state: &Self::State, access: &mut FilteredAccess) { + D::update_component_access(state, access); + } + + /// Creates and initializes a [`State`](WorldQuery::State) for this [`WorldQuery`] type. + fn init_state(world: &mut World) -> Self::State { + D::init_state(world) + } + + /// Attempts to initialize a [`State`](WorldQuery::State) for this [`WorldQuery`] type using read-only + /// access to [`Components`]. + fn get_state(components: &Components) -> Option { + D::get_state(components) + } + + /// Returns `true` if this query matches a set of components. Otherwise, returns `false`. + /// + /// Used to check which [`Archetype`]s can be skipped by the query + /// (if none of the [`Component`](crate::component::Component)s match) + fn matches_component_set( + state: &Self::State, + set_contains_id: &impl Fn(ComponentId) -> bool, + ) -> bool { + D::matches_component_set(state, set_contains_id) + } +} + macro_rules! impl_tuple_world_query { ($(#[$meta:meta])* $(($name: ident, $state: ident)),*) => { From bf8f76113f551ba2b6c07904d94c2142d632ec36 Mon Sep 17 00:00:00 2001 From: Nathan Fenner Date: Sun, 26 Jan 2025 21:04:48 -0800 Subject: [PATCH 2/9] fix comment formatting --- crates/bevy_ecs/src/query/fetch.rs | 13 +++++++++++++ crates/bevy_ecs/src/query/iter.rs | 9 ++++++++- crates/bevy_ecs/src/query/world_query.rs | 21 +++++++++++++++------ 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/crates/bevy_ecs/src/query/fetch.rs b/crates/bevy_ecs/src/query/fetch.rs index 01e3c0f435..28294a3db0 100644 --- a/crates/bevy_ecs/src/query/fetch.rs +++ b/crates/bevy_ecs/src/query/fetch.rs @@ -305,6 +305,12 @@ pub unsafe trait QueryData: WorldQuery { ) -> Self::Item<'w>; } +/// SAFETY: +/// +/// The `IncludeEntity` wrapper type has no additional state over the +/// underlying query type `D`. Its access is identical to the access of +/// `D`, except that the `Entity` being queried is also included in the +/// output. unsafe impl QueryData for crate::query::IncludeEntity { type ReadOnly = crate::query::IncludeEntity; } @@ -316,6 +322,13 @@ unsafe impl QueryData for crate::query::IncludeEntity { /// This must only be implemented for read-only [`QueryData`]'s. pub unsafe trait ReadOnlyQueryData: QueryData {} +/// SAFETY: +/// +/// The underlying state and access of `IncludeEntity` is identical to `D` itself, +/// except that the iterated `Entity` is also included in the output. +/// +/// Including the `Entity` in the output does not make any additional kind of mutation +/// possible. unsafe impl ReadOnlyQueryData for crate::query::IncludeEntity {} /// The item type returned when a [`WorldQuery`] is iterated over diff --git a/crates/bevy_ecs/src/query/iter.rs b/crates/bevy_ecs/src/query/iter.rs index 39d7332e96..1835370219 100644 --- a/crates/bevy_ecs/src/query/iter.rs +++ b/crates/bevy_ecs/src/query/iter.rs @@ -893,11 +893,18 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIter<'w, 's, D, F> { /// ``` /// pub fn include_entity(self) -> QueryIter<'w, 's, crate::query::IncludeEntity, F> { + let query_state: &QueryState, F> = + // SAFETY: `IncludeEntity` and `D` have identical access and query the same archetypes, + // since the internal state is not affected in any way by the `IncludeEntity` wrapper. + unsafe { + self.query_state.as_transmuted_state() + }; QueryIter { world: self.world, tables: self.tables, archetypes: self.archetypes, - query_state: unsafe { self.query_state.as_transmuted_state() }, + + query_state, cursor: QueryIterationCursor { is_dense: self.cursor.is_dense, storage_id_iter: self.cursor.storage_id_iter, diff --git a/crates/bevy_ecs/src/query/world_query.rs b/crates/bevy_ecs/src/query/world_query.rs index 49db04623f..83c960194b 100644 --- a/crates/bevy_ecs/src/query/world_query.rs +++ b/crates/bevy_ecs/src/query/world_query.rs @@ -132,13 +132,23 @@ pub unsafe trait WorldQuery { ) -> bool; } -/// A wrapper type which includes the entity in the selected query data, -/// but which has the same underlying state as `D`. +/// A wrapper type around a data query `D` which will return the queried [`Entity`] +/// alongside the results from `D`. /// -/// Most applications should use `(Entity, D)` instead; but unlike `(Entity, D)`, -/// it is guaranteed that `IncludeEntity` has the same `WorldQuery::State as `D`. +/// This convenience wrapper can be used by calling [`QueryIter::include_entity`] on +/// an iterator returned from `[Query::iter()]` or `[Query::iter_mut()]`. +/// +/// Unlike `(Entity, D)`, the type `IncludeEntity` is guaranteed to have identical +/// internal query state to `D` itself. pub struct IncludeEntity(pub D); +/// SAFETY: +/// +/// `IncludeEntity` has the exact same internal state and query behavior as `D` itself, +/// and inherits all of its safety properties from this fact. +/// +/// The only difference is that the `Entity` (which is tracked by all queries internally) is +/// also included in the output `Item`. unsafe impl WorldQuery for IncludeEntity { /// The item is the same as `D`, but also includes the entity. type Item<'a> = (Entity, D::Item<'a>); @@ -150,7 +160,7 @@ unsafe impl WorldQuery for IncludeEntity { type State = D::State; /// This function manually implements subtyping for the query items. - /// The non-`Entity` query is shrunk exactly how `D` specifies. + /// The non-`Entity` part of the query is shrunk exactly how `D` specifies. fn shrink<'wlong: 'wshort, 'wshort>(item: Self::Item<'wlong>) -> Self::Item<'wshort> { (item.0, D::shrink(item.1)) } @@ -161,7 +171,6 @@ unsafe impl WorldQuery for IncludeEntity { D::shrink_fetch(fetch) } - /// Creates a new instance of this fetch. unsafe fn init_fetch<'w>( world: UnsafeWorldCell<'w>, state: &Self::State, From 1bc84b39888ad95289bd219a28d1d1168e71e5b9 Mon Sep 17 00:00:00 2001 From: Nathan Fenner Date: Sun, 26 Jan 2025 21:10:35 -0800 Subject: [PATCH 3/9] fix safety comment formatting --- crates/bevy_ecs/src/query/iter.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/crates/bevy_ecs/src/query/iter.rs b/crates/bevy_ecs/src/query/iter.rs index 1835370219..0d541f647b 100644 --- a/crates/bevy_ecs/src/query/iter.rs +++ b/crates/bevy_ecs/src/query/iter.rs @@ -893,12 +893,9 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIter<'w, 's, D, F> { /// ``` /// pub fn include_entity(self) -> QueryIter<'w, 's, crate::query::IncludeEntity, F> { - let query_state: &QueryState, F> = // SAFETY: `IncludeEntity` and `D` have identical access and query the same archetypes, // since the internal state is not affected in any way by the `IncludeEntity` wrapper. - unsafe { - self.query_state.as_transmuted_state() - }; + let query_state = unsafe { self.query_state.as_transmuted_state() }; QueryIter { world: self.world, tables: self.tables, From aa2306b9d5829200968b84c51a8c14a6a860292b Mon Sep 17 00:00:00 2001 From: Nathan Fenner Date: Sun, 26 Jan 2025 21:46:37 -0800 Subject: [PATCH 4/9] fix reference to QueryIter in doc comment --- crates/bevy_ecs/src/query/world_query.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_ecs/src/query/world_query.rs b/crates/bevy_ecs/src/query/world_query.rs index 83c960194b..1a49db3c37 100644 --- a/crates/bevy_ecs/src/query/world_query.rs +++ b/crates/bevy_ecs/src/query/world_query.rs @@ -135,7 +135,7 @@ pub unsafe trait WorldQuery { /// A wrapper type around a data query `D` which will return the queried [`Entity`] /// alongside the results from `D`. /// -/// This convenience wrapper can be used by calling [`QueryIter::include_entity`] on +/// This convenience wrapper can be used by calling [`super::iter::QueryIter::include_entity`] on /// an iterator returned from `[Query::iter()]` or `[Query::iter_mut()]`. /// /// Unlike `(Entity, D)`, the type `IncludeEntity` is guaranteed to have identical From d5dcc84dc1ff442b8c8c250173733891d34e458a Mon Sep 17 00:00:00 2001 From: Nathan Fenner Date: Sun, 2 Mar 2025 21:39:35 -0800 Subject: [PATCH 5/9] add test for include_entity --- crates/bevy_ecs/src/query/iter.rs | 102 ++++++++++++++++++++++++++++-- 1 file changed, 97 insertions(+), 5 deletions(-) diff --git a/crates/bevy_ecs/src/query/iter.rs b/crates/bevy_ecs/src/query/iter.rs index 0d541f647b..6db4704b79 100644 --- a/crates/bevy_ecs/src/query/iter.rs +++ b/crates/bevy_ecs/src/query/iter.rs @@ -883,11 +883,17 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIter<'w, 's, D, F> { /// ``` /// use bevy_ecs::prelude::*; /// #[derive(Component)] - /// struct ExampleComponent; + /// struct Health(f32); /// - /// fn example_system(query: Query<&ExampleComponent>) { - /// for (entity, component) in query.iter().include_entity() { - /// println!("entity {:?}", entity); + /// #[derive(Component)] + /// struct Damage(f32); + /// + /// fn example_system(query: Query<(&mut Health, &Damage)>) { + /// for (entity, (health, damage)) in query.iter().include_entity() { + /// if damage.0 > 0.0 { + /// health.0 -= damage.0; + /// println!("entity {:?} took damage", entity); + /// } /// } /// } /// ``` @@ -2629,7 +2635,7 @@ mod tests { use std::println; use crate::component::Component; - use crate::entity::Entity; + use crate::entity::{self, Entity}; use crate::prelude::World; #[derive(Component, Debug, PartialEq, PartialOrd, Clone, Copy)] @@ -2975,4 +2981,90 @@ mod tests { while query.fetch_next().is_some() {} } } + + #[test] + fn query_iter_include_entity() { + let mut world = World::new(); + world.spawn_batch([A(0.), A(1.), A(2.), A(3.), A(4.)]); + world.spawn_batch([ + (A(0.), Sparse(100)), + (A(1.), Sparse(101)), + (A(2.), Sparse(102)), + (A(3.), Sparse(103)), + (A(4.), Sparse(104)), + ]); + + { + // Read-only + let mut query_entity_a = world.query::<(Entity, &A)>(); + let iter_plain = query_entity_a + .iter(&world) + .map(|(entity, a)| (entity, *a)) + .collect::>(); + + let mut query_a = world.query::<&A>(); + let iter_include_entity = query_a + .iter(&world) + .include_entity() + .map(|(entity, a)| (entity, *a)) + .collect::>(); + + assert_eq!(iter_plain, iter_include_entity); + } + + { + // Mut + let mut query_entity_a = world.query::<(Entity, &mut A)>(); + let iter_plain = query_entity_a + .iter_mut(&mut world) + .map(|(entity, a)| (entity, *a)) + .collect::>(); + + let mut query_a = world.query::<&mut A>(); + let iter_include_entity = query_a + .iter_mut(&mut world) + .include_entity() + .map(|(entity, a)| (entity, *a)) + .collect::>(); + + assert_eq!(iter_plain, iter_include_entity); + } + + { + // With filter + let mut query_entity_a = + world.query_filtered::<(Entity, &A), crate::query::With>(); + let iter_plain = query_entity_a + .iter(&world) + .map(|(entity, a)| (entity, *a)) + .collect::>(); + + let mut query_a = world.query_filtered::<&A, crate::query::With>(); + let iter_include_entity = query_a + .iter(&world) + .include_entity() + .map(|(entity, a)| (entity, *a)) + .collect::>(); + + assert_eq!(iter_plain, iter_include_entity); + } + + { + // Multiple components in a query + let mut query_entity_a = world.query::<(Entity, &A, &Sparse)>(); + let iter_plain = query_entity_a + .iter(&world) + .map(|(entity, a, sparse)| (entity, *a, *sparse)) + .collect::>(); + + let mut query_a = world.query::<(&A, &Sparse)>(); + let iter_include_entity = query_a + .iter(&world) + .include_entity() + .map(|(entity, (a, sparse))| (entity, *a, *sparse)) + .collect::>(); + + assert_eq!(iter_plain, iter_include_entity); + } + } } From e7feb3a5a5324813639886095be900a8b0f831e8 Mon Sep 17 00:00:00 2001 From: Nathan Fenner Date: Sun, 2 Mar 2025 21:58:55 -0800 Subject: [PATCH 6/9] update to match new trait hierarchy --- crates/bevy_ecs/src/query/fetch.rs | 25 +++++++++++++++++++++++ crates/bevy_ecs/src/query/iter.rs | 2 +- crates/bevy_ecs/src/query/world_query.rs | 26 ------------------------ 3 files changed, 26 insertions(+), 27 deletions(-) diff --git a/crates/bevy_ecs/src/query/fetch.rs b/crates/bevy_ecs/src/query/fetch.rs index 28294a3db0..168af62600 100644 --- a/crates/bevy_ecs/src/query/fetch.rs +++ b/crates/bevy_ecs/src/query/fetch.rs @@ -313,6 +313,31 @@ pub unsafe trait QueryData: WorldQuery { /// output. unsafe impl QueryData for crate::query::IncludeEntity { type ReadOnly = crate::query::IncludeEntity; + /// The item is the same as `D`, but also includes the entity. + type Item<'a> = (Entity, D::Item<'a>); + + /// This function manually implements subtyping for the query items. + /// The non-`Entity` part of the query is shrunk exactly how `D` specifies. + fn shrink<'wlong: 'wshort, 'wshort>(item: Self::Item<'wlong>) -> Self::Item<'wshort> { + (item.0, D::shrink(item.1)) + } + + /// Fetch [`Self::Item`](`WorldQuery::Item`) for either the given `entity` in the current [`Table`], + /// or for the given `entity` in the current [`Archetype`]. This must always be called after + /// [`WorldQuery::set_table`] with a `table_row` in the range of the current [`Table`] or after + /// [`WorldQuery::set_archetype`] with a `entity` in the current archetype. + /// + /// # Safety + /// + /// Must always be called _after_ [`WorldQuery::set_table`] or [`WorldQuery::set_archetype`]. `entity` and + /// `table_row` must be in the range of the current table and archetype. + unsafe fn fetch<'w>( + fetch: &mut Self::Fetch<'w>, + entity: Entity, + table_row: TableRow, + ) -> Self::Item<'w> { + (entity, D::fetch(fetch, entity, table_row)) + } } /// A [`QueryData`] that is read only. diff --git a/crates/bevy_ecs/src/query/iter.rs b/crates/bevy_ecs/src/query/iter.rs index 6db4704b79..bdc5551839 100644 --- a/crates/bevy_ecs/src/query/iter.rs +++ b/crates/bevy_ecs/src/query/iter.rs @@ -2635,7 +2635,7 @@ mod tests { use std::println; use crate::component::Component; - use crate::entity::{self, Entity}; + use crate::entity::Entity; use crate::prelude::World; #[derive(Component, Debug, PartialEq, PartialOrd, Clone, Copy)] diff --git a/crates/bevy_ecs/src/query/world_query.rs b/crates/bevy_ecs/src/query/world_query.rs index 1a49db3c37..8d0c2e6337 100644 --- a/crates/bevy_ecs/src/query/world_query.rs +++ b/crates/bevy_ecs/src/query/world_query.rs @@ -150,21 +150,12 @@ pub struct IncludeEntity(pub D); /// The only difference is that the `Entity` (which is tracked by all queries internally) is /// also included in the output `Item`. unsafe impl WorldQuery for IncludeEntity { - /// The item is the same as `D`, but also includes the entity. - type Item<'a> = (Entity, D::Item<'a>); - /// The same underlying state is used for `IncludeEntity` as `D` itself. type Fetch<'a> = D::Fetch<'a>; /// The same underlying state is used for `IncludeEntity` as `D` itself. type State = D::State; - /// This function manually implements subtyping for the query items. - /// The non-`Entity` part of the query is shrunk exactly how `D` specifies. - fn shrink<'wlong: 'wshort, 'wshort>(item: Self::Item<'wlong>) -> Self::Item<'wshort> { - (item.0, D::shrink(item.1)) - } - /// This function manually implements subtyping for the query items. /// The query is shrunk exactly how `D` specifies. fn shrink_fetch<'wlong: 'wshort, 'wshort>(fetch: Self::Fetch<'wlong>) -> Self::Fetch<'wshort> { @@ -215,23 +206,6 @@ unsafe impl WorldQuery for IncludeEntity { D::set_access(state, access); } - /// Fetch [`Self::Item`](`WorldQuery::Item`) for either the given `entity` in the current [`Table`], - /// or for the given `entity` in the current [`Archetype`]. This must always be called after - /// [`WorldQuery::set_table`] with a `table_row` in the range of the current [`Table`] or after - /// [`WorldQuery::set_archetype`] with a `entity` in the current archetype. - /// - /// # Safety - /// - /// Must always be called _after_ [`WorldQuery::set_table`] or [`WorldQuery::set_archetype`]. `entity` and - /// `table_row` must be in the range of the current table and archetype. - unsafe fn fetch<'w>( - fetch: &mut Self::Fetch<'w>, - entity: Entity, - table_row: TableRow, - ) -> Self::Item<'w> { - (entity, D::fetch(fetch, entity, table_row)) - } - /// Adds any component accesses used by this [`WorldQuery`] to `access`. /// /// Used to check which queries are disjoint and can run in parallel From b18df09adfbfd17b010c7b61cc704e02b2516479 Mon Sep 17 00:00:00 2001 From: Nathan Fenner Date: Sun, 2 Mar 2025 22:30:30 -0800 Subject: [PATCH 7/9] fix example --- crates/bevy_ecs/src/query/iter.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/bevy_ecs/src/query/iter.rs b/crates/bevy_ecs/src/query/iter.rs index bdc5551839..cf4b227338 100644 --- a/crates/bevy_ecs/src/query/iter.rs +++ b/crates/bevy_ecs/src/query/iter.rs @@ -888,8 +888,8 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIter<'w, 's, D, F> { /// #[derive(Component)] /// struct Damage(f32); /// - /// fn example_system(query: Query<(&mut Health, &Damage)>) { - /// for (entity, (health, damage)) in query.iter().include_entity() { + /// fn example_system(mut query: Query<(&mut Health, &Damage)>) { + /// for (entity, (mut health, damage)) in query.iter_mut().include_entity() { /// if damage.0 > 0.0 { /// health.0 -= damage.0; /// println!("entity {:?} took damage", entity); From 22142c9334d0be4c381dfeb87d747ed3de0c47a5 Mon Sep 17 00:00:00 2001 From: Nathan Fenner Date: Sun, 2 Mar 2025 22:56:31 -0800 Subject: [PATCH 8/9] doctest references --- crates/bevy_ecs/src/query/fetch.rs | 2 +- crates/bevy_ecs/src/query/world_query.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/bevy_ecs/src/query/fetch.rs b/crates/bevy_ecs/src/query/fetch.rs index 168af62600..8a1548b44f 100644 --- a/crates/bevy_ecs/src/query/fetch.rs +++ b/crates/bevy_ecs/src/query/fetch.rs @@ -322,7 +322,7 @@ unsafe impl QueryData for crate::query::IncludeEntity { (item.0, D::shrink(item.1)) } - /// Fetch [`Self::Item`](`WorldQuery::Item`) for either the given `entity` in the current [`Table`], + /// Fetch [`Self::Item`](`QueryData::Item`) for either the given `entity` in the current [`Table`], /// or for the given `entity` in the current [`Archetype`]. This must always be called after /// [`WorldQuery::set_table`] with a `table_row` in the range of the current [`Table`] or after /// [`WorldQuery::set_archetype`] with a `entity` in the current archetype. diff --git a/crates/bevy_ecs/src/query/world_query.rs b/crates/bevy_ecs/src/query/world_query.rs index 8d0c2e6337..a0ee371b39 100644 --- a/crates/bevy_ecs/src/query/world_query.rs +++ b/crates/bevy_ecs/src/query/world_query.rs @@ -132,7 +132,7 @@ pub unsafe trait WorldQuery { ) -> bool; } -/// A wrapper type around a data query `D` which will return the queried [`Entity`] +/// A wrapper type around a data query `D` which will return the queried [`crate::entity::Entity`] /// alongside the results from `D`. /// /// This convenience wrapper can be used by calling [`super::iter::QueryIter::include_entity`] on From de8212b5ed78dd26904fd4f7ffa4a343f03acd7a Mon Sep 17 00:00:00 2001 From: Nathan Fenner Date: Tue, 4 Mar 2025 14:19:37 -0800 Subject: [PATCH 9/9] update include_entity doc with better example --- crates/bevy_ecs/src/query/iter.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/crates/bevy_ecs/src/query/iter.rs b/crates/bevy_ecs/src/query/iter.rs index cf4b227338..1ee24b6fc9 100644 --- a/crates/bevy_ecs/src/query/iter.rs +++ b/crates/bevy_ecs/src/query/iter.rs @@ -888,11 +888,16 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIter<'w, 's, D, F> { /// #[derive(Component)] /// struct Damage(f32); /// - /// fn example_system(mut query: Query<(&mut Health, &Damage)>) { - /// for (entity, (mut health, damage)) in query.iter_mut().include_entity() { - /// if damage.0 > 0.0 { - /// health.0 -= damage.0; - /// println!("entity {:?} took damage", entity); + /// fn apply_damage_system(mut query: Query<(&mut Health, &Damage)>) { + /// // Iterate over the input query: + /// for (mut health, damage) in query.iter_mut() { + /// health.0 -= damage.0; + /// } + /// + /// // Iterate again, this time including the entity: + /// for (entity, (health, damage)) in query.iter().include_entity() { + /// if health.0 <= 0.0 { + /// println!("entity {:?} has been reduce to 0 health by {} damage", entity, damage.0); /// } /// } /// }