From 80aa08ad9a5bd592ec4ee544cf28fb9d7636fb0b Mon Sep 17 00:00:00 2001 From: Chris Russell <8494645+chescock@users.noreply.github.com> Date: Wed, 18 Jun 2025 16:52:11 -0400 Subject: [PATCH 01/10] Remove `copy_unsafe()` and instead use a `get_unchecked_inner()` method for `get_inner()`. --- crates/bevy_ecs/src/system/query.rs | 38 ++++++++++++++--------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/crates/bevy_ecs/src/system/query.rs b/crates/bevy_ecs/src/system/query.rs index 6e44301b18cb1..69fdd4ee5bdaa 100644 --- a/crates/bevy_ecs/src/system/query.rs +++ b/crates/bevy_ecs/src/system/query.rs @@ -619,24 +619,6 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { /// /// - [`reborrow`](Self::reborrow) for the safe versions. pub unsafe fn reborrow_unsafe(&self) -> Query<'_, 's, D, F> { - // SAFETY: - // - This is memory safe because the caller ensures that there are no conflicting references. - // - The world matches because it was the same one used to construct self. - unsafe { self.copy_unsafe() } - } - - /// Returns a new `Query` copying the access from this one. - /// The current query will still be usable while the new one exists, but must not be used in a way that violates aliasing. - /// - /// # Safety - /// - /// This function makes it possible to violate Rust's aliasing guarantees. - /// You must make sure this call does not result in a mutable or shared reference to a component with a mutable reference. - /// - /// # See also - /// - /// - [`reborrow_unsafe`](Self::reborrow_unsafe) for a safer version that constrains the returned `'w` lifetime to the length of the borrow. - unsafe fn copy_unsafe(&self) -> Query<'w, 's, D, F> { // SAFETY: // - This is memory safe because the caller ensures that there are no conflicting references. // - The world matches because it was the same one used to construct self. @@ -1537,6 +1519,24 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { /// - [`get_mut`](Self::get_mut) to get the item using a mutable borrow of the [`Query`]. #[inline] pub fn get_inner(self, entity: Entity) -> Result, QueryEntityError> { + // SAFETY: This query has access to this item, + // and we consume the query so it is never used again. + unsafe { self.get_unchecked_inner(entity) } + } + + /// Returns the query item for the given [`Entity`]. + /// + /// This is similar to [`Self::get_unchecked`], but returns results with the actual "inner" world lifetime. + /// + /// # Safety + /// + /// This function makes it possible to violate Rust's aliasing guarantees. + /// You must make sure this call does not result in multiple mutable references to the same component. + #[inline] + unsafe fn get_unchecked_inner( + &self, + entity: Entity, + ) -> Result, QueryEntityError> { // SAFETY: system runs without conflicts with other systems. // same-system queries have runtime borrow checks when they conflict unsafe { @@ -1831,7 +1831,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { for (value, entity) in core::iter::zip(&mut values, entities) { // SAFETY: The caller asserts that the results don't alias - let item = unsafe { self.copy_unsafe() }.get_inner(entity)?; + let item = unsafe { self.get_unchecked_inner(entity)? }; *value = MaybeUninit::new(item); } From 435bdd58a03b283517afd7c21149d75deb70c973 Mon Sep 17 00:00:00 2001 From: Chris Russell <8494645+chescock@users.noreply.github.com> Date: Wed, 18 Jun 2025 16:52:41 -0400 Subject: [PATCH 02/10] Group `_inner` methods together. --- crates/bevy_ecs/src/system/query.rs | 957 ++++++++++++++-------------- 1 file changed, 479 insertions(+), 478 deletions(-) diff --git a/crates/bevy_ecs/src/system/query.rs b/crates/bevy_ecs/src/system/query.rs index 69fdd4ee5bdaa..bac0b3ec5a8ed 100644 --- a/crates/bevy_ecs/src/system/query.rs +++ b/crates/bevy_ecs/src/system/query.rs @@ -560,23 +560,6 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { unsafe { Query::new(self.world, new_state, self.last_run, self.this_run) } } - /// Returns another `Query` from this that fetches the read-only version of the query items. - /// - /// For example, `Query<(&mut D1, &D2, &mut D3), With>` will become `Query<(&D1, &D2, &D3), With>`. - /// This can be useful when working around the borrow checker, - /// or reusing functionality between systems via functions that accept query types. - /// - /// # See also - /// - /// [`as_readonly`](Self::as_readonly) for a version that borrows the `Query` instead of consuming it. - pub fn into_readonly(self) -> Query<'w, 's, D::ReadOnly, F> { - let new_state = self.state.as_readonly(); - // SAFETY: - // - This is memory safe because it turns the query immutable. - // - The world matches because it was the same one used to construct self. - unsafe { Query::new(self.world, new_state, self.last_run, self.this_run) } - } - /// Returns a new `Query` reborrowing the access from this one. The current query will be unusable /// while the new one exists. /// @@ -747,36 +730,6 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { self.reborrow().iter_combinations_inner() } - /// Returns a [`QueryCombinationIter`] over all combinations of `K` query items without repetition. - /// This consumes the [`Query`] to return results with the actual "inner" world lifetime. - /// - /// This iterator is always guaranteed to return results from each unique pair of matching entities. - /// Iteration order is not guaranteed. - /// - /// # Example - /// - /// ``` - /// # use bevy_ecs::prelude::*; - /// # #[derive(Component)] - /// # struct ComponentA; - /// fn some_system(query: Query<&mut ComponentA>) { - /// let mut combinations = query.iter_combinations_inner(); - /// while let Some([mut a1, mut a2]) = combinations.fetch_next() { - /// // mutably access components data - /// } - /// } - /// ``` - /// - /// # See also - /// - /// - [`iter_combinations`](Self::iter_combinations) for read-only query item combinations. - /// - [`iter_combinations_mut`](Self::iter_combinations_mut) for mutable query item combinations. - #[inline] - pub fn iter_combinations_inner(self) -> QueryCombinationIter<'w, 's, D, F, K> { - // SAFETY: `self.world` has permission to access the required components. - unsafe { QueryCombinationIter::new(self.world, self.state, self.last_run, self.this_run) } - } - /// Returns an [`Iterator`] over the read-only query items generated from an [`Entity`] list. /// /// Items are returned in the order of the list of entities, and may not be unique if the input @@ -867,33 +820,6 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { self.reborrow().iter_many_inner(entities) } - /// Returns an iterator over the query items generated from an [`Entity`] list. - /// This consumes the [`Query`] to return results with the actual "inner" world lifetime. - /// - /// Items are returned in the order of the list of entities, and may not be unique if the input - /// doesn't guarantee uniqueness. Entities that don't match the query are skipped. - /// - /// # See also - /// - /// - [`iter_many`](Self::iter_many) to get read-only query items. - /// - [`iter_many_mut`](Self::iter_many_mut) to get mutable query items. - #[inline] - pub fn iter_many_inner>( - self, - entities: EntityList, - ) -> QueryManyIter<'w, 's, D, F, EntityList::IntoIter> { - // SAFETY: `self.world` has permission to access the required components. - unsafe { - QueryManyIter::new( - self.world, - self.state, - entities, - self.last_run, - self.this_run, - ) - } - } - /// Returns an [`Iterator`] over the unique read-only query items generated from an [`EntitySet`]. /// /// Items are returned in the order of the list of entities. Entities that don't match the query are skipped. @@ -1005,70 +931,6 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { self.reborrow().iter_many_unique_inner(entities) } - /// Returns an iterator over the unique query items generated from an [`EntitySet`]. - /// This consumes the [`Query`] to return results with the actual "inner" world lifetime. - /// - /// Items are returned in the order of the list of entities. Entities that don't match the query are skipped. - /// - /// # Examples - /// - /// ``` - /// # use bevy_ecs::{prelude::*, entity::{EntitySet, UniqueEntityIter}}; - /// # use core::slice; - /// #[derive(Component)] - /// struct Counter { - /// value: i32 - /// } - /// - /// // `Friends` ensures that it only lists unique entities. - /// #[derive(Component)] - /// struct Friends { - /// unique_list: Vec, - /// } - /// - /// impl<'a> IntoIterator for &'a Friends { - /// type Item = &'a Entity; - /// type IntoIter = UniqueEntityIter>; - /// - /// fn into_iter(self) -> Self::IntoIter { - /// // SAFETY: `Friends` ensures that it unique_list contains only unique entities. - /// unsafe { UniqueEntityIter::from_iterator_unchecked(self.unique_list.iter()) } - /// } - /// } - /// - /// fn system( - /// friends_query: Query<&Friends>, - /// mut counter_query: Query<&mut Counter>, - /// ) { - /// let friends = friends_query.single().unwrap(); - /// for mut counter in counter_query.iter_many_unique_inner(friends) { - /// println!("Friend's counter: {:?}", counter.value); - /// counter.value += 1; - /// } - /// } - /// # bevy_ecs::system::assert_is_system(system); - /// ``` - /// # See also - /// - /// - [`iter_many_unique`](Self::iter_many_unique) to get read-only query items. - /// - [`iter_many_unique_mut`](Self::iter_many_unique_mut) to get mutable query items. - #[inline] - pub fn iter_many_unique_inner( - self, - entities: EntityList, - ) -> QueryManyUniqueIter<'w, 's, D, F, EntityList::IntoIter> { - // SAFETY: `self.world` has permission to access the required components. - unsafe { - QueryManyUniqueIter::new( - self.world, - self.state, - entities, - self.last_run, - self.this_run, - ) - } - } - /// Returns an [`Iterator`] over the query items. /// /// This iterator is always guaranteed to return results from each matching entity once and only once. @@ -1208,43 +1070,6 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { self.reborrow().par_iter_inner() } - /// Returns a parallel iterator over the query results for the given [`World`](crate::world::World). - /// This consumes the [`Query`] to return results with the actual "inner" world lifetime. - /// - /// This parallel iterator is always guaranteed to return results from each matching entity once and - /// only once. Iteration order and thread assignment is not guaranteed. - /// - /// If the `multithreaded` feature is disabled, iterating with this operates identically to [`Iterator::for_each`] - /// on [`QueryIter`]. - /// - /// # Example - /// - /// Here, the `gravity_system` updates the `Velocity` component of every entity that contains it: - /// - /// ``` - /// # use bevy_ecs::prelude::*; - /// # - /// # #[derive(Component)] - /// # struct Velocity { x: f32, y: f32, z: f32 } - /// fn gravity_system(query: Query<&mut Velocity>) { - /// const DELTA: f32 = 1.0 / 60.0; - /// query.par_iter_inner().for_each(|mut velocity| { - /// velocity.y -= 9.8 * DELTA; - /// }); - /// } - /// # bevy_ecs::system::assert_is_system(gravity_system); - /// ``` - #[inline] - pub fn par_iter_inner(self) -> QueryParIter<'w, 's, D, F> { - QueryParIter { - world: self.world, - state: self.state, - last_run: self.last_run, - this_run: self.this_run, - batching_strategy: BatchingStrategy::new(), - } - } - /// Returns a parallel iterator over the read-only query items generated from an [`Entity`] list. /// /// Entities that don't match the query are skipped. Iteration order and thread assignment is not guaranteed. @@ -1507,181 +1332,85 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { self.reborrow().get_inner(entity) } - /// Returns the query item for the given [`Entity`]. - /// This consumes the [`Query`] to return results with the actual "inner" world lifetime. + /// Returns the query items for the given array of [`Entity`]. /// - /// In case of a nonexisting entity or mismatched component, a [`QueryEntityError`] is returned instead. + /// The returned query items are in the same order as the input. + /// In case of a nonexisting entity, duplicate entities or mismatched component, a [`QueryEntityError`] is returned instead. /// - /// This is always guaranteed to run in `O(1)` time. + /// # Examples + /// + /// ``` + /// use bevy_ecs::prelude::*; + /// use bevy_ecs::query::QueryEntityError; + /// + /// #[derive(Component, PartialEq, Debug)] + /// struct A(usize); + /// + /// let mut world = World::new(); /// + /// let entities: Vec = (0..3).map(|i| world.spawn(A(i)).id()).collect(); + /// let entities: [Entity; 3] = entities.try_into().unwrap(); + /// + /// world.spawn(A(73)); + /// let wrong_entity = Entity::from_raw_u32(57).unwrap(); + /// let invalid_entity = world.spawn_empty().id(); + /// + /// + /// let mut query_state = world.query::<&mut A>(); + /// let mut query = query_state.query_mut(&mut world); + /// + /// let mut mutable_component_values = query.get_many_mut(entities).unwrap(); + /// + /// for mut a in &mut mutable_component_values { + /// a.0 += 5; + /// } + /// + /// let component_values = query.get_many(entities).unwrap(); + /// + /// assert_eq!(component_values, [&A(5), &A(6), &A(7)]); + /// + /// assert_eq!( + /// match query + /// .get_many_mut([wrong_entity]) + /// .unwrap_err() + /// { + /// QueryEntityError::EntityDoesNotExist(error) => error.entity, + /// _ => panic!(), + /// }, + /// wrong_entity + /// ); + /// assert_eq!( + /// match query + /// .get_many_mut([invalid_entity]) + /// .unwrap_err() + /// { + /// QueryEntityError::QueryDoesNotMatch(entity, _) => entity, + /// _ => panic!(), + /// }, + /// invalid_entity + /// ); + /// assert_eq!( + /// query + /// .get_many_mut([entities[0], entities[0]]) + /// .unwrap_err(), + /// QueryEntityError::AliasedMutability(entities[0]) + /// ); + /// ``` /// # See also /// - /// - [`get_mut`](Self::get_mut) to get the item using a mutable borrow of the [`Query`]. + /// - [`get_many`](Self::get_many) to get read-only query items without checking for duplicate entities. #[inline] - pub fn get_inner(self, entity: Entity) -> Result, QueryEntityError> { - // SAFETY: This query has access to this item, - // and we consume the query so it is never used again. - unsafe { self.get_unchecked_inner(entity) } + pub fn get_many_mut( + &mut self, + entities: [Entity; N], + ) -> Result<[D::Item<'_, 's>; N], QueryEntityError> { + self.reborrow().get_many_mut_inner(entities) } - /// Returns the query item for the given [`Entity`]. + /// Returns the query items for the given [`UniqueEntityArray`]. /// - /// This is similar to [`Self::get_unchecked`], but returns results with the actual "inner" world lifetime. - /// - /// # Safety - /// - /// This function makes it possible to violate Rust's aliasing guarantees. - /// You must make sure this call does not result in multiple mutable references to the same component. - #[inline] - unsafe fn get_unchecked_inner( - &self, - entity: Entity, - ) -> Result, QueryEntityError> { - // SAFETY: system runs without conflicts with other systems. - // same-system queries have runtime borrow checks when they conflict - unsafe { - let location = self - .world - .entities() - .get(entity) - .ok_or(EntityDoesNotExistError::new(entity, self.world.entities()))?; - if !self - .state - .matched_archetypes - .contains(location.archetype_id.index()) - { - return Err(QueryEntityError::QueryDoesNotMatch( - entity, - location.archetype_id, - )); - } - let archetype = self - .world - .archetypes() - .get(location.archetype_id) - .debug_checked_unwrap(); - let mut fetch = D::init_fetch( - self.world, - &self.state.fetch_state, - self.last_run, - self.this_run, - ); - let mut filter = F::init_fetch( - self.world, - &self.state.filter_state, - self.last_run, - self.this_run, - ); - - let table = self - .world - .storages() - .tables - .get(location.table_id) - .debug_checked_unwrap(); - D::set_archetype(&mut fetch, &self.state.fetch_state, archetype, table); - F::set_archetype(&mut filter, &self.state.filter_state, archetype, table); - - if F::filter_fetch( - &self.state.filter_state, - &mut filter, - entity, - location.table_row, - ) { - Ok(D::fetch( - &self.state.fetch_state, - &mut fetch, - entity, - location.table_row, - )) - } else { - Err(QueryEntityError::QueryDoesNotMatch( - entity, - location.archetype_id, - )) - } - } - } - - /// Returns the query items for the given array of [`Entity`]. - /// - /// The returned query items are in the same order as the input. - /// In case of a nonexisting entity, duplicate entities or mismatched component, a [`QueryEntityError`] is returned instead. - /// - /// # Examples - /// - /// ``` - /// use bevy_ecs::prelude::*; - /// use bevy_ecs::query::QueryEntityError; - /// - /// #[derive(Component, PartialEq, Debug)] - /// struct A(usize); - /// - /// let mut world = World::new(); - /// - /// let entities: Vec = (0..3).map(|i| world.spawn(A(i)).id()).collect(); - /// let entities: [Entity; 3] = entities.try_into().unwrap(); - /// - /// world.spawn(A(73)); - /// let wrong_entity = Entity::from_raw_u32(57).unwrap(); - /// let invalid_entity = world.spawn_empty().id(); - /// - /// - /// let mut query_state = world.query::<&mut A>(); - /// let mut query = query_state.query_mut(&mut world); - /// - /// let mut mutable_component_values = query.get_many_mut(entities).unwrap(); - /// - /// for mut a in &mut mutable_component_values { - /// a.0 += 5; - /// } - /// - /// let component_values = query.get_many(entities).unwrap(); - /// - /// assert_eq!(component_values, [&A(5), &A(6), &A(7)]); - /// - /// assert_eq!( - /// match query - /// .get_many_mut([wrong_entity]) - /// .unwrap_err() - /// { - /// QueryEntityError::EntityDoesNotExist(error) => error.entity, - /// _ => panic!(), - /// }, - /// wrong_entity - /// ); - /// assert_eq!( - /// match query - /// .get_many_mut([invalid_entity]) - /// .unwrap_err() - /// { - /// QueryEntityError::QueryDoesNotMatch(entity, _) => entity, - /// _ => panic!(), - /// }, - /// invalid_entity - /// ); - /// assert_eq!( - /// query - /// .get_many_mut([entities[0], entities[0]]) - /// .unwrap_err(), - /// QueryEntityError::AliasedMutability(entities[0]) - /// ); - /// ``` - /// # See also - /// - /// - [`get_many`](Self::get_many) to get read-only query items without checking for duplicate entities. - #[inline] - pub fn get_many_mut( - &mut self, - entities: [Entity; N], - ) -> Result<[D::Item<'_, 's>; N], QueryEntityError> { - self.reborrow().get_many_mut_inner(entities) - } - - /// Returns the query items for the given [`UniqueEntityArray`]. - /// - /// The returned query items are in the same order as the input. - /// In case of a nonexisting entity or mismatched component, a [`QueryEntityError`] is returned instead. + /// The returned query items are in the same order as the input. + /// In case of a nonexisting entity or mismatched component, a [`QueryEntityError`] is returned instead. /// /// # Examples /// @@ -1745,100 +1474,6 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { ) -> Result<[D::Item<'_, 's>; N], QueryEntityError> { self.reborrow().get_many_unique_inner(entities) } - - /// Returns the query items for the given array of [`Entity`]. - /// This consumes the [`Query`] to return results with the actual "inner" world lifetime. - /// - /// The returned query items are in the same order as the input. - /// In case of a nonexisting entity, duplicate entities or mismatched component, a [`QueryEntityError`] is returned instead. - /// - /// # See also - /// - /// - [`get_many`](Self::get_many) to get read-only query items without checking for duplicate entities. - /// - [`get_many_mut`](Self::get_many_mut) to get items using a mutable reference. - /// - [`get_many_inner`](Self::get_many_mut_inner) to get read-only query items with the actual "inner" world lifetime. - #[inline] - pub fn get_many_mut_inner( - self, - entities: [Entity; N], - ) -> Result<[D::Item<'w, 's>; N], QueryEntityError> { - // Verify that all entities are unique - for i in 0..N { - for j in 0..i { - if entities[i] == entities[j] { - return Err(QueryEntityError::AliasedMutability(entities[i])); - } - } - } - // SAFETY: All entities are unique, so the results don't alias. - unsafe { self.get_many_impl(entities) } - } - - /// Returns the query items for the given array of [`Entity`]. - /// This consumes the [`Query`] to return results with the actual "inner" world lifetime. - /// - /// The returned query items are in the same order as the input. - /// In case of a nonexisting entity or mismatched component, a [`QueryEntityError`] is returned instead. - /// - /// # See also - /// - /// - [`get_many`](Self::get_many) to get read-only query items without checking for duplicate entities. - /// - [`get_many_mut`](Self::get_many_mut) to get items using a mutable reference. - /// - [`get_many_mut_inner`](Self::get_many_mut_inner) to get mutable query items with the actual "inner" world lifetime. - #[inline] - pub fn get_many_inner( - self, - entities: [Entity; N], - ) -> Result<[D::Item<'w, 's>; N], QueryEntityError> - where - D: ReadOnlyQueryData, - { - // SAFETY: The query results are read-only, so they don't conflict if there are duplicate entities. - unsafe { self.get_many_impl(entities) } - } - - /// Returns the query items for the given [`UniqueEntityArray`]. - /// This consumes the [`Query`] to return results with the actual "inner" world lifetime. - /// - /// The returned query items are in the same order as the input. - /// In case of a nonexisting entity, duplicate entities or mismatched component, a [`QueryEntityError`] is returned instead. - /// - /// # See also - /// - /// - [`get_many_unique`](Self::get_many_unique) to get read-only query items without checking for duplicate entities. - /// - [`get_many_unique_mut`](Self::get_many_unique_mut) to get items using a mutable reference. - #[inline] - pub fn get_many_unique_inner( - self, - entities: UniqueEntityArray, - ) -> Result<[D::Item<'w, 's>; N], QueryEntityError> { - // SAFETY: All entities are unique, so the results don't alias. - unsafe { self.get_many_impl(entities.into_inner()) } - } - - /// Returns the query items for the given array of [`Entity`]. - /// This consumes the [`Query`] to return results with the actual "inner" world lifetime. - /// - /// # Safety - /// - /// The caller must ensure that the query data returned for the entities does not conflict, - /// either because they are all unique or because the data is read-only. - unsafe fn get_many_impl( - self, - entities: [Entity; N], - ) -> Result<[D::Item<'w, 's>; N], QueryEntityError> { - let mut values = [(); N].map(|_| MaybeUninit::uninit()); - - for (value, entity) in core::iter::zip(&mut values, entities) { - // SAFETY: The caller asserts that the results don't alias - let item = unsafe { self.get_unchecked_inner(entity)? }; - *value = MaybeUninit::new(item); - } - - // SAFETY: Each value has been fully initialized. - Ok(values.map(|x| unsafe { x.assume_init() })) - } - /// Returns the query item for the given [`Entity`]. /// /// In case of a nonexisting entity or mismatched component, a [`QueryEntityError`] is returned instead. @@ -1926,49 +1561,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { self.reborrow().single_inner() } - /// Returns a single query item when there is exactly one entity matching the query. - /// This consumes the [`Query`] to return results with the actual "inner" world lifetime. - /// - /// If the number of query items is not exactly one, a [`QuerySingleError`] is returned instead. - /// - /// # Example - /// - /// ``` - /// # use bevy_ecs::prelude::*; - /// # - /// # #[derive(Component)] - /// # struct Player; - /// # #[derive(Component)] - /// # struct Health(u32); - /// # - /// fn regenerate_player_health_system(query: Query<&mut Health, With>) { - /// let mut health = query.single_inner().expect("Error: Could not find a single player."); - /// health.0 += 1; - /// } - /// # bevy_ecs::system::assert_is_system(regenerate_player_health_system); - /// ``` - /// - /// # See also - /// - /// - [`single`](Self::single) to get the read-only query item. - /// - [`single_mut`](Self::single_mut) to get the mutable query item. - /// - [`single_inner`](Self::single_inner) for the panicking version. - #[inline] - pub fn single_inner(self) -> Result, QuerySingleError> { - let mut query = self.into_iter(); - let first = query.next(); - let extra = query.next().is_some(); - - match (first, extra) { - (Some(r), false) => Ok(r), - (None, _) => Err(QuerySingleError::NoEntities(DebugName::type_name::())), - (Some(_), _) => Err(QuerySingleError::MultipleEntities(DebugName::type_name::< - Self, - >())), - } - } - - /// Returns `true` if there are no query items. + /// Returns `true` if there are no query items. /// /// This is equivalent to `self.iter().next().is_none()`, and thus the worst case runtime will be `O(n)` /// where `n` is the number of *potential* matches. This can be notably expensive for queries that rely @@ -2465,6 +2058,414 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { } } +impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { + /// Returns another `Query` from this that fetches the read-only version of the query items. + /// + /// For example, `Query<(&mut D1, &D2, &mut D3), With>` will become `Query<(&D1, &D2, &D3), With>`. + /// This can be useful when working around the borrow checker, + /// or reusing functionality between systems via functions that accept query types. + /// + /// # See also + /// + /// [`as_readonly`](Self::as_readonly) for a version that borrows the `Query` instead of consuming it. + pub fn into_readonly(self) -> Query<'w, 's, D::ReadOnly, F> { + let new_state = self.state.as_readonly(); + // SAFETY: + // - This is memory safe because it turns the query immutable. + // - The world matches because it was the same one used to construct self. + unsafe { Query::new(self.world, new_state, self.last_run, self.this_run) } + } + + /// Returns a [`QueryCombinationIter`] over all combinations of `K` query items without repetition. + /// This consumes the [`Query`] to return results with the actual "inner" world lifetime. + /// + /// This iterator is always guaranteed to return results from each unique pair of matching entities. + /// Iteration order is not guaranteed. + /// + /// # Example + /// + /// ``` + /// # use bevy_ecs::prelude::*; + /// # #[derive(Component)] + /// # struct ComponentA; + /// fn some_system(query: Query<&mut ComponentA>) { + /// let mut combinations = query.iter_combinations_inner(); + /// while let Some([mut a1, mut a2]) = combinations.fetch_next() { + /// // mutably access components data + /// } + /// } + /// ``` + /// + /// # See also + /// + /// - [`iter_combinations`](Self::iter_combinations) for read-only query item combinations. + /// - [`iter_combinations_mut`](Self::iter_combinations_mut) for mutable query item combinations. + #[inline] + pub fn iter_combinations_inner(self) -> QueryCombinationIter<'w, 's, D, F, K> { + // SAFETY: `self.world` has permission to access the required components. + unsafe { QueryCombinationIter::new(self.world, self.state, self.last_run, self.this_run) } + } + + /// Returns an iterator over the query items generated from an [`Entity`] list. + /// This consumes the [`Query`] to return results with the actual "inner" world lifetime. + /// + /// Items are returned in the order of the list of entities, and may not be unique if the input + /// doesn't guarantee uniqueness. Entities that don't match the query are skipped. + /// + /// # See also + /// + /// - [`iter_many`](Self::iter_many) to get read-only query items. + /// - [`iter_many_mut`](Self::iter_many_mut) to get mutable query items. + #[inline] + pub fn iter_many_inner>( + self, + entities: EntityList, + ) -> QueryManyIter<'w, 's, D, F, EntityList::IntoIter> { + // SAFETY: `self.world` has permission to access the required components. + unsafe { + QueryManyIter::new( + self.world, + self.state, + entities, + self.last_run, + self.this_run, + ) + } + } + + /// Returns an iterator over the unique query items generated from an [`EntitySet`]. + /// This consumes the [`Query`] to return results with the actual "inner" world lifetime. + /// + /// Items are returned in the order of the list of entities. Entities that don't match the query are skipped. + /// + /// # Examples + /// + /// ``` + /// # use bevy_ecs::{prelude::*, entity::{EntitySet, UniqueEntityIter}}; + /// # use core::slice; + /// #[derive(Component)] + /// struct Counter { + /// value: i32 + /// } + /// + /// // `Friends` ensures that it only lists unique entities. + /// #[derive(Component)] + /// struct Friends { + /// unique_list: Vec, + /// } + /// + /// impl<'a> IntoIterator for &'a Friends { + /// type Item = &'a Entity; + /// type IntoIter = UniqueEntityIter>; + /// + /// fn into_iter(self) -> Self::IntoIter { + /// // SAFETY: `Friends` ensures that it unique_list contains only unique entities. + /// unsafe { UniqueEntityIter::from_iterator_unchecked(self.unique_list.iter()) } + /// } + /// } + /// + /// fn system( + /// friends_query: Query<&Friends>, + /// mut counter_query: Query<&mut Counter>, + /// ) { + /// let friends = friends_query.single().unwrap(); + /// for mut counter in counter_query.iter_many_unique_inner(friends) { + /// println!("Friend's counter: {:?}", counter.value); + /// counter.value += 1; + /// } + /// } + /// # bevy_ecs::system::assert_is_system(system); + /// ``` + /// # See also + /// + /// - [`iter_many_unique`](Self::iter_many_unique) to get read-only query items. + /// - [`iter_many_unique_mut`](Self::iter_many_unique_mut) to get mutable query items. + #[inline] + pub fn iter_many_unique_inner( + self, + entities: EntityList, + ) -> QueryManyUniqueIter<'w, 's, D, F, EntityList::IntoIter> { + // SAFETY: `self.world` has permission to access the required components. + unsafe { + QueryManyUniqueIter::new( + self.world, + self.state, + entities, + self.last_run, + self.this_run, + ) + } + } + + /// Returns a parallel iterator over the query results for the given [`World`](crate::world::World). + /// This consumes the [`Query`] to return results with the actual "inner" world lifetime. + /// + /// This parallel iterator is always guaranteed to return results from each matching entity once and + /// only once. Iteration order and thread assignment is not guaranteed. + /// + /// If the `multithreaded` feature is disabled, iterating with this operates identically to [`Iterator::for_each`] + /// on [`QueryIter`]. + /// + /// # Example + /// + /// Here, the `gravity_system` updates the `Velocity` component of every entity that contains it: + /// + /// ``` + /// # use bevy_ecs::prelude::*; + /// # + /// # #[derive(Component)] + /// # struct Velocity { x: f32, y: f32, z: f32 } + /// fn gravity_system(query: Query<&mut Velocity>) { + /// const DELTA: f32 = 1.0 / 60.0; + /// query.par_iter_inner().for_each(|mut velocity| { + /// velocity.y -= 9.8 * DELTA; + /// }); + /// } + /// # bevy_ecs::system::assert_is_system(gravity_system); + /// ``` + #[inline] + pub fn par_iter_inner(self) -> QueryParIter<'w, 's, D, F> { + QueryParIter { + world: self.world, + state: self.state, + last_run: self.last_run, + this_run: self.this_run, + batching_strategy: BatchingStrategy::new(), + } + } + + /// Returns the query item for the given [`Entity`]. + /// This consumes the [`Query`] to return results with the actual "inner" world lifetime. + /// + /// In case of a nonexisting entity or mismatched component, a [`QueryEntityError`] is returned instead. + /// + /// This is always guaranteed to run in `O(1)` time. + /// + /// # See also + /// + /// - [`get_mut`](Self::get_mut) to get the item using a mutable borrow of the [`Query`]. + #[inline] + pub fn get_inner(self, entity: Entity) -> Result, QueryEntityError> { + // SAFETY: This query has access to this item, + // and we consume the query so it is never used again. + unsafe { self.get_unchecked_inner(entity) } + } + + /// Returns the query item for the given [`Entity`]. + /// + /// This is similar to [`Self::get_unchecked`], but returns results with the actual "inner" world lifetime. + /// + /// # Safety + /// + /// This function makes it possible to violate Rust's aliasing guarantees. + /// You must make sure this call does not result in multiple mutable references to the same component. + #[inline] + unsafe fn get_unchecked_inner( + &self, + entity: Entity, + ) -> Result, QueryEntityError> { + // SAFETY: system runs without conflicts with other systems. + // same-system queries have runtime borrow checks when they conflict + unsafe { + let location = self + .world + .entities() + .get(entity) + .ok_or(EntityDoesNotExistError::new(entity, self.world.entities()))?; + if !self + .state + .matched_archetypes + .contains(location.archetype_id.index()) + { + return Err(QueryEntityError::QueryDoesNotMatch( + entity, + location.archetype_id, + )); + } + let archetype = self + .world + .archetypes() + .get(location.archetype_id) + .debug_checked_unwrap(); + let mut fetch = D::init_fetch( + self.world, + &self.state.fetch_state, + self.last_run, + self.this_run, + ); + let mut filter = F::init_fetch( + self.world, + &self.state.filter_state, + self.last_run, + self.this_run, + ); + + let table = self + .world + .storages() + .tables + .get(location.table_id) + .debug_checked_unwrap(); + D::set_archetype(&mut fetch, &self.state.fetch_state, archetype, table); + F::set_archetype(&mut filter, &self.state.filter_state, archetype, table); + + if F::filter_fetch( + &self.state.filter_state, + &mut filter, + entity, + location.table_row, + ) { + Ok(D::fetch( + &self.state.fetch_state, + &mut fetch, + entity, + location.table_row, + )) + } else { + Err(QueryEntityError::QueryDoesNotMatch( + entity, + location.archetype_id, + )) + } + } + } + + /// Returns the query items for the given array of [`Entity`]. + /// This consumes the [`Query`] to return results with the actual "inner" world lifetime. + /// + /// The returned query items are in the same order as the input. + /// In case of a nonexisting entity, duplicate entities or mismatched component, a [`QueryEntityError`] is returned instead. + /// + /// # See also + /// + /// - [`get_many`](Self::get_many) to get read-only query items without checking for duplicate entities. + /// - [`get_many_mut`](Self::get_many_mut) to get items using a mutable reference. + /// - [`get_many_inner`](Self::get_many_mut_inner) to get read-only query items with the actual "inner" world lifetime. + #[inline] + pub fn get_many_mut_inner( + self, + entities: [Entity; N], + ) -> Result<[D::Item<'w, 's>; N], QueryEntityError> { + // Verify that all entities are unique + for i in 0..N { + for j in 0..i { + if entities[i] == entities[j] { + return Err(QueryEntityError::AliasedMutability(entities[i])); + } + } + } + // SAFETY: All entities are unique, so the results don't alias. + unsafe { self.get_many_impl(entities) } + } + + /// Returns the query items for the given array of [`Entity`]. + /// This consumes the [`Query`] to return results with the actual "inner" world lifetime. + /// + /// The returned query items are in the same order as the input. + /// In case of a nonexisting entity or mismatched component, a [`QueryEntityError`] is returned instead. + /// + /// # See also + /// + /// - [`get_many`](Self::get_many) to get read-only query items without checking for duplicate entities. + /// - [`get_many_mut`](Self::get_many_mut) to get items using a mutable reference. + /// - [`get_many_mut_inner`](Self::get_many_mut_inner) to get mutable query items with the actual "inner" world lifetime. + #[inline] + pub fn get_many_inner( + self, + entities: [Entity; N], + ) -> Result<[D::Item<'w, 's>; N], QueryEntityError> + where + D: ReadOnlyQueryData, + { + // SAFETY: The query results are read-only, so they don't conflict if there are duplicate entities. + unsafe { self.get_many_impl(entities) } + } + + /// Returns the query items for the given [`UniqueEntityArray`]. + /// This consumes the [`Query`] to return results with the actual "inner" world lifetime. + /// + /// The returned query items are in the same order as the input. + /// In case of a nonexisting entity, duplicate entities or mismatched component, a [`QueryEntityError`] is returned instead. + /// + /// # See also + /// + /// - [`get_many_unique`](Self::get_many_unique) to get read-only query items without checking for duplicate entities. + /// - [`get_many_unique_mut`](Self::get_many_unique_mut) to get items using a mutable reference. + #[inline] + pub fn get_many_unique_inner( + self, + entities: UniqueEntityArray, + ) -> Result<[D::Item<'w, 's>; N], QueryEntityError> { + // SAFETY: All entities are unique, so the results don't alias. + unsafe { self.get_many_impl(entities.into_inner()) } + } + + /// Returns the query items for the given array of [`Entity`]. + /// This consumes the [`Query`] to return results with the actual "inner" world lifetime. + /// + /// # Safety + /// + /// The caller must ensure that the query data returned for the entities does not conflict, + /// either because they are all unique or because the data is read-only. + unsafe fn get_many_impl( + self, + entities: [Entity; N], + ) -> Result<[D::Item<'w, 's>; N], QueryEntityError> { + let mut values = [(); N].map(|_| MaybeUninit::uninit()); + + for (value, entity) in core::iter::zip(&mut values, entities) { + // SAFETY: The caller asserts that the results don't alias + let item = unsafe { self.get_unchecked_inner(entity)? }; + *value = MaybeUninit::new(item); + } + + // SAFETY: Each value has been fully initialized. + Ok(values.map(|x| unsafe { x.assume_init() })) + } + + /// Returns a single query item when there is exactly one entity matching the query. + /// This consumes the [`Query`] to return results with the actual "inner" world lifetime. + /// + /// If the number of query items is not exactly one, a [`QuerySingleError`] is returned instead. + /// + /// # Example + /// + /// ``` + /// # use bevy_ecs::prelude::*; + /// # + /// # #[derive(Component)] + /// # struct Player; + /// # #[derive(Component)] + /// # struct Health(u32); + /// # + /// fn regenerate_player_health_system(query: Query<&mut Health, With>) { + /// let mut health = query.single_inner().expect("Error: Could not find a single player."); + /// health.0 += 1; + /// } + /// # bevy_ecs::system::assert_is_system(regenerate_player_health_system); + /// ``` + /// + /// # See also + /// + /// - [`single`](Self::single) to get the read-only query item. + /// - [`single_mut`](Self::single_mut) to get the mutable query item. + /// - [`single_inner`](Self::single_inner) for the panicking version. + #[inline] + pub fn single_inner(self) -> Result, QuerySingleError> { + let mut query = self.into_iter(); + let first = query.next(); + let extra = query.next().is_some(); + + match (first, extra) { + (Some(r), false) => Ok(r), + (None, _) => Err(QuerySingleError::NoEntities(DebugName::type_name::())), + (Some(_), _) => Err(QuerySingleError::MultipleEntities(DebugName::type_name::< + Self, + >())), + } + } +} + impl<'w, 's, D: QueryData, F: QueryFilter> IntoIterator for Query<'w, 's, D, F> { type Item = D::Item<'w, 's>; type IntoIter = QueryIter<'w, 's, D, F>; From fa787b2ae4582ceadf838e0275a734b3aa31b8e4 Mon Sep 17 00:00:00 2001 From: Chris Russell <8494645+chescock@users.noreply.github.com> Date: Wed, 18 Jun 2025 16:43:55 -0400 Subject: [PATCH 03/10] Make Query generic over the State type so it can use either owned or borrowed state. --- .../src/relationship/relationship_query.rs | 166 ++++++++++++------ crates/bevy_ecs/src/system/query.rs | 104 ++++++----- 2 files changed, 175 insertions(+), 95 deletions(-) diff --git a/crates/bevy_ecs/src/relationship/relationship_query.rs b/crates/bevy_ecs/src/relationship/relationship_query.rs index a7acea7de0732..d6827b4c94688 100644 --- a/crates/bevy_ecs/src/relationship/relationship_query.rs +++ b/crates/bevy_ecs/src/relationship/relationship_query.rs @@ -1,6 +1,8 @@ +use core::ops::Deref; + use crate::{ entity::Entity, - query::{QueryData, QueryFilter}, + query::{QueryData, QueryFilter, QueryState}, relationship::{Relationship, RelationshipTarget}, system::Query, }; @@ -9,24 +11,26 @@ use smallvec::SmallVec; use super::SourceIter; -impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { +impl<'w, 's, D: QueryData, F: QueryFilter, S: Deref>> + Query<'w, 's, D, F, S> +{ /// If the given `entity` contains the `R` [`Relationship`] component, returns the /// target entity of that relationship. pub fn related(&'w self, entity: Entity) -> Option where - ::ReadOnly: QueryData = &'w R>, + D::ReadOnly: QueryData = &'w R>, { self.get(entity).map(R::get).ok() } /// If the given `entity` contains the `S` [`RelationshipTarget`] component, returns the /// source entities stored on that component. - pub fn relationship_sources( + pub fn relationship_sources( &'w self, entity: Entity, ) -> impl Iterator + 'w where - ::ReadOnly: QueryData = &'w S>, + D::ReadOnly: QueryData = &'w R>, { self.get(entity) .into_iter() @@ -42,7 +46,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { /// If your relationship is not a tree (like Bevy's hierarchy), be sure to stop if you encounter a duplicate entity. pub fn root_ancestor(&'w self, entity: Entity) -> Entity where - ::ReadOnly: QueryData = &'w R>, + D::ReadOnly: QueryData = &'w R>, { // Recursively search up the tree until we're out of parents match self.get(entity) { @@ -57,13 +61,13 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { /// /// For relationship graphs that contain loops, this could loop infinitely. /// If your relationship is not a tree (like Bevy's hierarchy), be sure to stop if you encounter a duplicate entity. - pub fn iter_leaves( + pub fn iter_leaves( &'w self, entity: Entity, - ) -> impl Iterator + use<'w, 's, S, D, F> + ) -> impl Iterator + use<'w, 's, D, F, S, R> where - ::ReadOnly: QueryData = &'w S>, - SourceIter<'w, S>: DoubleEndedIterator, + D::ReadOnly: QueryData = &'w R>, + SourceIter<'w, R>: DoubleEndedIterator, { self.iter_descendants_depth_first(entity).filter(|entity| { self.get(*entity) @@ -80,7 +84,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { entity: Entity, ) -> impl Iterator + 'w where - D::ReadOnly: QueryData = (Option<&'w R>, Option<&'w R::RelationshipTarget>)>, + D::ReadOnly: QueryData = (Option<&'w R>, Option<&'w R::RelationshipTarget>)>, { self.get(entity) .ok() @@ -98,12 +102,12 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { /// /// For relationship graphs that contain loops, this could loop infinitely. /// If your relationship is not a tree (like Bevy's hierarchy), be sure to stop if you encounter a duplicate entity. - pub fn iter_descendants( + pub fn iter_descendants( &'w self, entity: Entity, - ) -> DescendantIter<'w, 's, D, F, S> + ) -> DescendantIter<'w, 's, D, F, S, R> where - D::ReadOnly: QueryData = &'w S>, + D::ReadOnly: QueryData = &'w R>, { DescendantIter::new(self, entity) } @@ -115,13 +119,13 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { /// /// For relationship graphs that contain loops, this could loop infinitely. /// If your relationship is not a tree (like Bevy's hierarchy), be sure to stop if you encounter a duplicate entity. - pub fn iter_descendants_depth_first( + pub fn iter_descendants_depth_first( &'w self, entity: Entity, - ) -> DescendantDepthFirstIter<'w, 's, D, F, S> + ) -> DescendantDepthFirstIter<'w, 's, D, F, S, R> where - D::ReadOnly: QueryData = &'w S>, - SourceIter<'w, S>: DoubleEndedIterator, + D::ReadOnly: QueryData = &'w R>, + SourceIter<'w, R>: DoubleEndedIterator, { DescendantDepthFirstIter::new(self, entity) } @@ -135,9 +139,9 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { pub fn iter_ancestors( &'w self, entity: Entity, - ) -> AncestorIter<'w, 's, D, F, R> + ) -> AncestorIter<'w, 's, D, F, S, R> where - D::ReadOnly: QueryData = &'w R>, + D::ReadOnly: QueryData = &'w R>, { AncestorIter::new(self, entity) } @@ -146,20 +150,33 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { /// An [`Iterator`] of [`Entity`]s over the descendants of an [`Entity`]. /// /// Traverses the hierarchy breadth-first. -pub struct DescendantIter<'w, 's, D: QueryData, F: QueryFilter, S: RelationshipTarget> -where - D::ReadOnly: QueryData = &'w S>, +pub struct DescendantIter< + 'w, + 's, + D: QueryData, + F: QueryFilter, + S: Deref>, + R: RelationshipTarget, +> where + D::ReadOnly: QueryData = &'w R>, { - children_query: &'w Query<'w, 's, D, F>, + children_query: &'w Query<'w, 's, D, F, S>, vecdeque: VecDeque, } -impl<'w, 's, D: QueryData, F: QueryFilter, S: RelationshipTarget> DescendantIter<'w, 's, D, F, S> +impl< + 'w, + 's, + D: QueryData, + F: QueryFilter, + S: Deref>, + R: RelationshipTarget, + > DescendantIter<'w, 's, D, F, S, R> where - D::ReadOnly: QueryData = &'w S>, + D::ReadOnly: QueryData = &'w R>, { /// Returns a new [`DescendantIter`]. - pub fn new(children_query: &'w Query<'w, 's, D, F>, entity: Entity) -> Self { + pub fn new(children_query: &'w Query<'w, 's, D, F, S>, entity: Entity) -> Self { DescendantIter { children_query, vecdeque: children_query @@ -171,10 +188,16 @@ where } } -impl<'w, 's, D: QueryData, F: QueryFilter, S: RelationshipTarget> Iterator - for DescendantIter<'w, 's, D, F, S> +impl< + 'w, + 's, + D: QueryData, + F: QueryFilter, + S: Deref>, + R: RelationshipTarget, + > Iterator for DescendantIter<'w, 's, D, F, S, R> where - D::ReadOnly: QueryData = &'w S>, + D::ReadOnly: QueryData = &'w R>, { type Item = Entity; @@ -192,22 +215,34 @@ where /// An [`Iterator`] of [`Entity`]s over the descendants of an [`Entity`]. /// /// Traverses the hierarchy depth-first. -pub struct DescendantDepthFirstIter<'w, 's, D: QueryData, F: QueryFilter, S: RelationshipTarget> -where - D::ReadOnly: QueryData = &'w S>, +pub struct DescendantDepthFirstIter< + 'w, + 's, + D: QueryData, + F: QueryFilter, + S: Deref>, + R: RelationshipTarget, +> where + D::ReadOnly: QueryData = &'w R>, { - children_query: &'w Query<'w, 's, D, F>, + children_query: &'w Query<'w, 's, D, F, S>, stack: SmallVec<[Entity; 8]>, } -impl<'w, 's, D: QueryData, F: QueryFilter, S: RelationshipTarget> - DescendantDepthFirstIter<'w, 's, D, F, S> +impl< + 'w, + 's, + D: QueryData, + F: QueryFilter, + S: Deref>, + R: RelationshipTarget, + > DescendantDepthFirstIter<'w, 's, D, F, S, R> where - D::ReadOnly: QueryData = &'w S>, - SourceIter<'w, S>: DoubleEndedIterator, + D::ReadOnly: QueryData = &'w R>, + SourceIter<'w, R>: DoubleEndedIterator, { /// Returns a new [`DescendantDepthFirstIter`]. - pub fn new(children_query: &'w Query<'w, 's, D, F>, entity: Entity) -> Self { + pub fn new(children_query: &'w Query<'w, 's, D, F, S>, entity: Entity) -> Self { DescendantDepthFirstIter { children_query, stack: children_query @@ -217,11 +252,17 @@ where } } -impl<'w, 's, D: QueryData, F: QueryFilter, S: RelationshipTarget> Iterator - for DescendantDepthFirstIter<'w, 's, D, F, S> +impl< + 'w, + 's, + D: QueryData, + F: QueryFilter, + S: Deref>, + R: RelationshipTarget, + > Iterator for DescendantDepthFirstIter<'w, 's, D, F, S, R> where - D::ReadOnly: QueryData = &'w S>, - SourceIter<'w, S>: DoubleEndedIterator, + D::ReadOnly: QueryData = &'w R>, + SourceIter<'w, R>: DoubleEndedIterator, { type Item = Entity; @@ -237,20 +278,33 @@ where } /// An [`Iterator`] of [`Entity`]s over the ancestors of an [`Entity`]. -pub struct AncestorIter<'w, 's, D: QueryData, F: QueryFilter, R: Relationship> -where - D::ReadOnly: QueryData = &'w R>, +pub struct AncestorIter< + 'w, + 's, + D: QueryData, + F: QueryFilter, + S: Deref>, + R: Relationship, +> where + D::ReadOnly: QueryData = &'w R>, { - parent_query: &'w Query<'w, 's, D, F>, + parent_query: &'w Query<'w, 's, D, F, S>, next: Option, } -impl<'w, 's, D: QueryData, F: QueryFilter, R: Relationship> AncestorIter<'w, 's, D, F, R> +impl< + 'w, + 's, + D: QueryData, + F: QueryFilter, + S: Deref>, + R: Relationship, + > AncestorIter<'w, 's, D, F, S, R> where - D::ReadOnly: QueryData = &'w R>, + D::ReadOnly: QueryData = &'w R>, { /// Returns a new [`AncestorIter`]. - pub fn new(parent_query: &'w Query<'w, 's, D, F>, entity: Entity) -> Self { + pub fn new(parent_query: &'w Query<'w, 's, D, F, S>, entity: Entity) -> Self { AncestorIter { parent_query, next: Some(entity), @@ -258,10 +312,16 @@ where } } -impl<'w, 's, D: QueryData, F: QueryFilter, R: Relationship> Iterator - for AncestorIter<'w, 's, D, F, R> +impl< + 'w, + 's, + D: QueryData, + F: QueryFilter, + S: Deref>, + R: Relationship, + > Iterator for AncestorIter<'w, 's, D, F, S, R> where - D::ReadOnly: QueryData = &'w R>, + D::ReadOnly: QueryData = &'w R>, { type Item = Entity; diff --git a/crates/bevy_ecs/src/system/query.rs b/crates/bevy_ecs/src/system/query.rs index bac0b3ec5a8ed..8635ca8aa8573 100644 --- a/crates/bevy_ecs/src/system/query.rs +++ b/crates/bevy_ecs/src/system/query.rs @@ -482,12 +482,23 @@ use core::{ /// ``` /// /// [autovectorization]: https://en.wikipedia.org/wiki/Automatic_vectorization -pub struct Query<'world, 'state, D: QueryData, F: QueryFilter = ()> { +pub struct Query< + 'world, + // Note that `'state` is only used in the default type for `S`. + // That's necessary to make `Query` be a valid `SystemParam`. + 'state, + D: QueryData, + F: QueryFilter = (), + S: Deref> = &'state QueryState, +> { // SAFETY: Must have access to the components registered in `state`. world: UnsafeWorldCell<'world>, - state: &'state QueryState, + state: S, last_run: Tick, this_run: Tick, + // Note that `&'state QueryState` won't work because + // `QueryLens` uses `'static`, but `D` and `F` might not be `'static`. + marker: PhantomData<(&'state (), fn() -> QueryState)>, } impl Clone for Query<'_, '_, D, F> { @@ -510,7 +521,9 @@ impl core::fmt::Debug for Query<'_, '_, D, F> { } } -impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { +impl<'w, 's, D: QueryData, F: QueryFilter, S: Deref>> + Query<'w, 's, D, F, S> +{ /// Creates a new query. /// /// # Safety @@ -521,7 +534,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { #[inline] pub(crate) unsafe fn new( world: UnsafeWorldCell<'w>, - state: &'s QueryState, + state: S, last_run: Tick, this_run: Tick, ) -> Self { @@ -530,6 +543,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { state, last_run, this_run, + marker: PhantomData, } } @@ -542,14 +556,14 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { /// # See also /// /// [`into_readonly`](Self::into_readonly) for a version that consumes the `Query` to return one with the full `'world` lifetime. - pub fn as_readonly(&self) -> Query<'_, 's, D::ReadOnly, F> { + pub fn as_readonly(&self) -> Query<'_, '_, D::ReadOnly, F> { // SAFETY: The reborrowed query is converted to read-only, so it cannot perform mutable access, // and the original query is held with a shared borrow, so it cannot perform mutable access either. unsafe { self.reborrow_unsafe() }.into_readonly() } /// Returns another `Query` from this does not return any data, which can be faster. - fn as_nop(&self) -> Query<'_, 's, NopWorldQuery, F> { + fn as_nop(&self) -> Query<'_, '_, NopWorldQuery, F> { let new_state = self.state.as_nop(); // SAFETY: // - The reborrowed query is converted to read-only, so it cannot perform mutable access, @@ -584,7 +598,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { /// } /// } /// ``` - pub fn reborrow(&mut self) -> Query<'_, 's, D, F> { + pub fn reborrow(&mut self) -> Query<'_, '_, D, F> { // SAFETY: this query is exclusively borrowed while the new one exists, so // no overlapping access can occur. unsafe { self.reborrow_unsafe() } @@ -601,11 +615,11 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { /// # See also /// /// - [`reborrow`](Self::reborrow) for the safe versions. - pub unsafe fn reborrow_unsafe(&self) -> Query<'_, 's, D, F> { + pub unsafe fn reborrow_unsafe(&self) -> Query<'_, '_, D, F> { // SAFETY: // - This is memory safe because the caller ensures that there are no conflicting references. // - The world matches because it was the same one used to construct self. - unsafe { Query::new(self.world, self.state, self.last_run, self.this_run) } + unsafe { Query::new(self.world, &self.state, self.last_run, self.this_run) } } /// Returns an [`Iterator`] over the read-only query items. @@ -635,7 +649,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { /// /// [`iter_mut`](Self::iter_mut) for mutable query items. #[inline] - pub fn iter(&self) -> QueryIter<'_, 's, D::ReadOnly, F> { + pub fn iter(&self) -> QueryIter<'_, '_, D::ReadOnly, F> { self.as_readonly().into_iter() } @@ -666,7 +680,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { /// /// [`iter`](Self::iter) for read-only query items. #[inline] - pub fn iter_mut(&mut self) -> QueryIter<'_, 's, D, F> { + pub fn iter_mut(&mut self) -> QueryIter<'_, '_, D, F> { self.reborrow().into_iter() } @@ -696,7 +710,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { #[inline] pub fn iter_combinations( &self, - ) -> QueryCombinationIter<'_, 's, D::ReadOnly, F, K> { + ) -> QueryCombinationIter<'_, '_, D::ReadOnly, F, K> { self.as_readonly().iter_combinations_inner() } @@ -726,7 +740,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { #[inline] pub fn iter_combinations_mut( &mut self, - ) -> QueryCombinationIter<'_, 's, D, F, K> { + ) -> QueryCombinationIter<'_, '_, D, F, K> { self.reborrow().iter_combinations_inner() } @@ -771,7 +785,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { pub fn iter_many>( &self, entities: EntityList, - ) -> QueryManyIter<'_, 's, D::ReadOnly, F, EntityList::IntoIter> { + ) -> QueryManyIter<'_, '_, D::ReadOnly, F, EntityList::IntoIter> { self.as_readonly().iter_many_inner(entities) } @@ -816,7 +830,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { pub fn iter_many_mut>( &mut self, entities: EntityList, - ) -> QueryManyIter<'_, 's, D, F, EntityList::IntoIter> { + ) -> QueryManyIter<'_, '_, D, F, EntityList::IntoIter> { self.reborrow().iter_many_inner(entities) } @@ -872,7 +886,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { pub fn iter_many_unique( &self, entities: EntityList, - ) -> QueryManyUniqueIter<'_, 's, D::ReadOnly, F, EntityList::IntoIter> { + ) -> QueryManyUniqueIter<'_, '_, D::ReadOnly, F, EntityList::IntoIter> { self.as_readonly().iter_many_unique_inner(entities) } @@ -927,7 +941,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { pub fn iter_many_unique_mut( &mut self, entities: EntityList, - ) -> QueryManyUniqueIter<'_, 's, D, F, EntityList::IntoIter> { + ) -> QueryManyUniqueIter<'_, '_, D, F, EntityList::IntoIter> { self.reborrow().iter_many_unique_inner(entities) } @@ -945,7 +959,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { /// /// - [`iter`](Self::iter) and [`iter_mut`](Self::iter_mut) for the safe versions. #[inline] - pub unsafe fn iter_unsafe(&self) -> QueryIter<'_, 's, D, F> { + pub unsafe fn iter_unsafe(&self) -> QueryIter<'_, '_, D, F> { // SAFETY: The caller promises that this will not result in multiple mutable references. unsafe { self.reborrow_unsafe() }.into_iter() } @@ -966,7 +980,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { #[inline] pub unsafe fn iter_combinations_unsafe( &self, - ) -> QueryCombinationIter<'_, 's, D, F, K> { + ) -> QueryCombinationIter<'_, '_, D, F, K> { // SAFETY: The caller promises that this will not result in multiple mutable references. unsafe { self.reborrow_unsafe() }.iter_combinations_inner() } @@ -988,7 +1002,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { pub unsafe fn iter_many_unsafe>( &self, entities: EntityList, - ) -> QueryManyIter<'_, 's, D, F, EntityList::IntoIter> { + ) -> QueryManyIter<'_, '_, D, F, EntityList::IntoIter> { // SAFETY: The caller promises that this will not result in multiple mutable references. unsafe { self.reborrow_unsafe() }.iter_many_inner(entities) } @@ -1010,7 +1024,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { pub unsafe fn iter_many_unique_unsafe( &self, entities: EntityList, - ) -> QueryManyUniqueIter<'_, 's, D, F, EntityList::IntoIter> { + ) -> QueryManyUniqueIter<'_, '_, D, F, EntityList::IntoIter> { // SAFETY: The caller promises that this will not result in multiple mutable references. unsafe { self.reborrow_unsafe() }.iter_many_unique_inner(entities) } @@ -1031,7 +1045,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { /// [`par_iter_mut`]: Self::par_iter_mut /// [`World`]: crate::world::World #[inline] - pub fn par_iter(&self) -> QueryParIter<'_, 's, D::ReadOnly, F> { + pub fn par_iter(&self) -> QueryParIter<'_, '_, D::ReadOnly, F> { self.as_readonly().par_iter_inner() } @@ -1066,7 +1080,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { /// [`par_iter`]: Self::par_iter /// [`World`]: crate::world::World #[inline] - pub fn par_iter_mut(&mut self) -> QueryParIter<'_, 's, D, F> { + pub fn par_iter_mut(&mut self) -> QueryParIter<'_, '_, D, F> { self.reborrow().par_iter_inner() } @@ -1089,7 +1103,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { pub fn par_iter_many>( &self, entities: EntityList, - ) -> QueryParManyIter<'_, 's, D::ReadOnly, F, EntityList::Item> { + ) -> QueryParManyIter<'_, '_, D::ReadOnly, F, EntityList::Item> { QueryParManyIter { world: self.world, state: self.state.as_readonly(), @@ -1118,7 +1132,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { pub fn par_iter_many_unique>( &self, entities: EntityList, - ) -> QueryParManyUniqueIter<'_, 's, D::ReadOnly, F, EntityList::Item> { + ) -> QueryParManyUniqueIter<'_, '_, D::ReadOnly, F, EntityList::Item> { QueryParManyUniqueIter { world: self.world, state: self.state.as_readonly(), @@ -1147,10 +1161,10 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { pub fn par_iter_many_unique_mut>( &mut self, entities: EntityList, - ) -> QueryParManyUniqueIter<'_, 's, D, F, EntityList::Item> { + ) -> QueryParManyUniqueIter<'_, '_, D, F, EntityList::Item> { QueryParManyUniqueIter { world: self.world, - state: self.state, + state: &self.state, entity_list: entities.into_iter().collect(), last_run: self.last_run, this_run: self.this_run, @@ -1192,7 +1206,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { /// /// - [`get_mut`](Self::get_mut) to get a mutable query item. #[inline] - pub fn get(&self, entity: Entity) -> Result, QueryEntityError> { + pub fn get(&self, entity: Entity) -> Result, QueryEntityError> { self.as_readonly().get_inner(entity) } @@ -1243,7 +1257,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { pub fn get_many( &self, entities: [Entity; N], - ) -> Result<[ROQueryItem<'_, 's, D>; N], QueryEntityError> { + ) -> Result<[ROQueryItem<'_, '_, D>; N], QueryEntityError> { // Note that we call a separate `*_inner` method from `get_many_mut` // because we don't need to check for duplicates. self.as_readonly().get_many_inner(entities) @@ -1294,7 +1308,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { pub fn get_many_unique( &self, entities: UniqueEntityArray, - ) -> Result<[ROQueryItem<'_, 's, D>; N], QueryEntityError> { + ) -> Result<[ROQueryItem<'_, '_, D>; N], QueryEntityError> { self.as_readonly().get_many_unique_inner(entities) } @@ -1328,7 +1342,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { /// /// - [`get`](Self::get) to get a read-only query item. #[inline] - pub fn get_mut(&mut self, entity: Entity) -> Result, QueryEntityError> { + pub fn get_mut(&mut self, entity: Entity) -> Result, QueryEntityError> { self.reborrow().get_inner(entity) } @@ -1403,7 +1417,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { pub fn get_many_mut( &mut self, entities: [Entity; N], - ) -> Result<[D::Item<'_, 's>; N], QueryEntityError> { + ) -> Result<[D::Item<'_, '_>; N], QueryEntityError> { self.reborrow().get_many_mut_inner(entities) } @@ -1471,7 +1485,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { pub fn get_many_unique_mut( &mut self, entities: UniqueEntityArray, - ) -> Result<[D::Item<'_, 's>; N], QueryEntityError> { + ) -> Result<[D::Item<'_, '_>; N], QueryEntityError> { self.reborrow().get_many_unique_inner(entities) } /// Returns the query item for the given [`Entity`]. @@ -1492,7 +1506,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { pub unsafe fn get_unchecked( &self, entity: Entity, - ) -> Result, QueryEntityError> { + ) -> Result, QueryEntityError> { // SAFETY: The caller promises that this will not result in multiple mutable references. unsafe { self.reborrow_unsafe() }.get_inner(entity) } @@ -1528,7 +1542,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { /// /// - [`single_mut`](Self::single_mut) to get the mutable query item. #[inline] - pub fn single(&self) -> Result, QuerySingleError> { + pub fn single(&self) -> Result, QuerySingleError> { self.as_readonly().single_inner() } @@ -1557,7 +1571,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { /// /// - [`single`](Self::single) to get the read-only query item. #[inline] - pub fn single_mut(&mut self) -> Result, QuerySingleError> { + pub fn single_mut(&mut self) -> Result, QuerySingleError> { self.reborrow().single_inner() } @@ -2479,18 +2493,22 @@ impl<'w, 's, D: QueryData, F: QueryFilter> IntoIterator for Query<'w, 's, D, F> } } -impl<'w, 's, D: QueryData, F: QueryFilter> IntoIterator for &'w Query<'_, 's, D, F> { - type Item = ROQueryItem<'w, 's, D>; - type IntoIter = QueryIter<'w, 's, D::ReadOnly, F>; +impl<'w, D: QueryData, F: QueryFilter, S: Deref>> IntoIterator + for &'w Query<'_, '_, D, F, S> +{ + type Item = ROQueryItem<'w, 'w, D>; + type IntoIter = QueryIter<'w, 'w, D::ReadOnly, F>; fn into_iter(self) -> Self::IntoIter { self.iter() } } -impl<'w, 's, D: QueryData, F: QueryFilter> IntoIterator for &'w mut Query<'_, 's, D, F> { - type Item = D::Item<'w, 's>; - type IntoIter = QueryIter<'w, 's, D, F>; +impl<'w, D: QueryData, F: QueryFilter, S: Deref>> IntoIterator + for &'w mut Query<'_, '_, D, F, S> +{ + type Item = D::Item<'w, 'w>; + type IntoIter = QueryIter<'w, 'w, D, F>; fn into_iter(self) -> Self::IntoIter { self.iter_mut() @@ -2545,6 +2563,7 @@ impl<'w, Q: QueryData, F: QueryFilter> QueryLens<'w, Q, F> { state: &self.state, last_run: self.last_run, this_run: self.this_run, + marker: PhantomData, } } } @@ -2559,6 +2578,7 @@ impl<'w, Q: ReadOnlyQueryData, F: QueryFilter> QueryLens<'w, Q, F> { state: &self.state, last_run: self.last_run, this_run: self.this_run, + marker: PhantomData, } } } From 1f7241ac16a83d13567db0a217739e79c66912ba Mon Sep 17 00:00:00 2001 From: Chris Russell <8494645+chescock@users.noreply.github.com> Date: Wed, 18 Jun 2025 16:40:54 -0400 Subject: [PATCH 04/10] Make QueryLens a type alias. --- crates/bevy_ecs/src/query/state.rs | 4 +- crates/bevy_ecs/src/system/query.rs | 54 ++++++++----------- .../combine_query_and_query_lens.md | 20 +++++++ 3 files changed, 44 insertions(+), 34 deletions(-) create mode 100644 release-content/migration-guides/combine_query_and_query_lens.md diff --git a/crates/bevy_ecs/src/query/state.rs b/crates/bevy_ecs/src/query/state.rs index 00d8b6f97085b..9cd8d911907ec 100644 --- a/crates/bevy_ecs/src/query/state.rs +++ b/crates/bevy_ecs/src/query/state.rs @@ -2020,7 +2020,7 @@ mod tests { .run_system_once(|query: Query<&mut A>| { let mut readonly = query.as_readonly(); let mut lens: QueryLens<&mut A> = readonly.transmute_lens(); - bad(lens.query(), query.as_readonly()); + bad(lens.reborrow(), query.as_readonly()); }) .unwrap(); } @@ -2146,7 +2146,7 @@ mod tests { .run_system_once(|query_a: Query<&mut A>, mut query_b: Query<&mut B>| { let mut readonly = query_a.as_readonly(); let mut lens: QueryLens<(&mut A, &mut B)> = readonly.join(&mut query_b); - bad(lens.query(), query_a.as_readonly()); + bad(lens.reborrow(), query_a.as_readonly()); }) .unwrap(); } diff --git a/crates/bevy_ecs/src/system/query.rs b/crates/bevy_ecs/src/system/query.rs index 8635ca8aa8573..c13fdc21cf4be 100644 --- a/crates/bevy_ecs/src/system/query.rs +++ b/crates/bevy_ecs/src/system/query.rs @@ -11,6 +11,7 @@ use crate::{ }, world::unsafe_world_cell::UnsafeWorldCell, }; +use alloc::boxed::Box; use core::{ marker::PhantomData, mem::MaybeUninit, @@ -1717,7 +1718,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter, S: Deref>> /// # world.spawn((A(10), B(5))); /// # /// fn reusable_function(lens: &mut QueryLens<&A>) { - /// assert_eq!(lens.query().single().unwrap().0, 10); + /// assert_eq!(lens.single().unwrap().0, 10); /// } /// /// // We can use the function in a system that takes the exact query. @@ -1846,7 +1847,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter, S: Deref>> /// # world.spawn((A(10), B(5))); /// # /// fn reusable_function(mut lens: QueryLens<&A>) { - /// assert_eq!(lens.query().single().unwrap().0, 10); + /// assert_eq!(lens.single().unwrap().0, 10); /// } /// /// // We can use the function in a system that takes the exact query. @@ -1909,12 +1910,10 @@ impl<'w, 's, D: QueryData, F: QueryFilter, S: Deref>> self, ) -> QueryLens<'w, NewD, NewF> { let state = self.state.transmute_filtered::(self.world); - QueryLens { - world: self.world, - state, - last_run: self.last_run, - this_run: self.this_run, - } + // SAFETY: + // - This is memory safe because the original query had compatible access and was consumed. + // - The world matches because it was the same one used to construct self. + unsafe { Query::new(self.world, Box::new(state), self.last_run, self.this_run) } } /// Gets a [`QueryLens`] with the same accesses as the existing query @@ -1963,12 +1962,12 @@ impl<'w, 's, D: QueryData, F: QueryFilter, S: Deref>> /// mut enemies: Query<&Enemy> /// ) { /// let mut players_transforms: QueryLens<(&Transform, &Player)> = transforms.join(&mut players); - /// for (transform, player) in &players_transforms.query() { + /// for (transform, player) in &players_transforms { /// // do something with a and b /// } /// /// let mut enemies_transforms: QueryLens<(&Transform, &Enemy)> = transforms.join(&mut enemies); - /// for (transform, enemy) in &enemies_transforms.query() { + /// for (transform, enemy) in &enemies_transforms { /// // do something with a and b /// } /// } @@ -2063,12 +2062,10 @@ impl<'w, 's, D: QueryData, F: QueryFilter, S: Deref>> let state = self .state .join_filtered::(self.world, other.state); - QueryLens { - world: self.world, - state, - last_run: self.last_run, - this_run: self.this_run, - } + // SAFETY: + // - This is memory safe because the original query had compatible access and was consumed. + // - The world matches because it was the same one used to construct self. + unsafe { Query::new(self.world, Box::new(state), self.last_run, self.this_run) } } } @@ -2545,26 +2542,19 @@ impl<'w, 's, D: ReadOnlyQueryData, F: QueryFilter> Query<'w, 's, D, F> { } } -/// Type returned from [`Query::transmute_lens`] containing the new [`QueryState`]. +/// A [`Query`] with an owned [`QueryState`]. /// -/// Call [`query`](QueryLens::query) or [`into`](Into::into) to construct the resulting [`Query`] -pub struct QueryLens<'w, Q: QueryData, F: QueryFilter = ()> { - world: UnsafeWorldCell<'w>, - state: QueryState, - last_run: Tick, - this_run: Tick, -} +/// This is returned from methods like [`Query::transmute_lens`] that construct a fresh [`QueryState`]. +pub type QueryLens<'w, Q, F = ()> = Query<'w, 'static, Q, F, Box>>; impl<'w, Q: QueryData, F: QueryFilter> QueryLens<'w, Q, F> { /// Create a [`Query`] from the underlying [`QueryState`]. + #[deprecated( + since = "0.17.0", + note = "This can usually be removed, since `QueryLens` supports all methods from `Query`. If you need to consume the resulting `Query`, call `reborrow()` instead." + )] pub fn query(&mut self) -> Query<'_, '_, Q, F> { - Query { - world: self.world, - state: &self.state, - last_run: self.last_run, - this_run: self.this_run, - marker: PhantomData, - } + self.reborrow() } } @@ -2587,7 +2577,7 @@ impl<'w, 's, Q: QueryData, F: QueryFilter> From<&'s mut QueryLens<'w, Q, F>> for Query<'s, 's, Q, F> { fn from(value: &'s mut QueryLens<'w, Q, F>) -> Query<'s, 's, Q, F> { - value.query() + value.reborrow() } } diff --git a/release-content/migration-guides/combine_query_and_query_lens.md b/release-content/migration-guides/combine_query_and_query_lens.md new file mode 100644 index 0000000000000..ddf22d41aae2a --- /dev/null +++ b/release-content/migration-guides/combine_query_and_query_lens.md @@ -0,0 +1,20 @@ +--- +title: Combine `Query` and `QueryLens` +pull_requests: [18162] +--- + +The `QueryLens::query()` method has been deprecated. +The `QueryLens` type has now been combined with `Query`, so most methods can be called directly on the `QueryLens` and the call can simply be removed. +If that doesn't work and you do need a fresh `Query`, the call to `.query()` can be replaced with `.reborrow()`. + +```rust +fn with_query(query: Query<&T>) {} +fn with_lens(lens: QueryLens<&T>) -> Result { + // 0.16 + for item in lens.query().iter() {} + with_query(lens.query()); + // 0.17 + for item in lens.iter() {} + with_query(lens.reborrow()); +} +``` From 618fa75eb38cb6832fe5216ac8dda9455b78d79b Mon Sep 17 00:00:00 2001 From: Chris Russell <8494645+chescock@users.noreply.github.com> Date: Thu, 23 Oct 2025 09:43:07 -0400 Subject: [PATCH 05/10] Update version in migration guide and `#[deprecated]`. --- crates/bevy_ecs/src/system/query.rs | 2 +- .../migration-guides/combine_query_and_query_lens.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/bevy_ecs/src/system/query.rs b/crates/bevy_ecs/src/system/query.rs index 15a839eff964e..1d9d3ba6c2456 100644 --- a/crates/bevy_ecs/src/system/query.rs +++ b/crates/bevy_ecs/src/system/query.rs @@ -2583,7 +2583,7 @@ pub type QueryLens<'w, Q, F = ()> = Query<'w, 'static, Q, F, Box QueryLens<'w, Q, F> { /// Create a [`Query`] from the underlying [`QueryState`]. #[deprecated( - since = "0.17.0", + since = "0.18.0", note = "This can usually be removed, since `QueryLens` supports all methods from `Query`. If you need to consume the resulting `Query`, call `reborrow()` instead." )] pub fn query(&mut self) -> Query<'_, '_, Q, F> { diff --git a/release-content/migration-guides/combine_query_and_query_lens.md b/release-content/migration-guides/combine_query_and_query_lens.md index ddf22d41aae2a..a6f8be69168bf 100644 --- a/release-content/migration-guides/combine_query_and_query_lens.md +++ b/release-content/migration-guides/combine_query_and_query_lens.md @@ -10,10 +10,10 @@ If that doesn't work and you do need a fresh `Query`, the call to `.query()` can ```rust fn with_query(query: Query<&T>) {} fn with_lens(lens: QueryLens<&T>) -> Result { - // 0.16 + // 0.17 for item in lens.query().iter() {} with_query(lens.query()); - // 0.17 + // 0.18 for item in lens.iter() {} with_query(lens.reborrow()); } From 8030003fc1f8e8cac9582b5a8e1c32cdeb77e4a0 Mon Sep 17 00:00:00 2001 From: Chris Russell <8494645+chescock@users.noreply.github.com> Date: Fri, 24 Oct 2025 13:26:37 -0400 Subject: [PATCH 06/10] Document new type parameter. --- crates/bevy_ecs/src/system/query.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/crates/bevy_ecs/src/system/query.rs b/crates/bevy_ecs/src/system/query.rs index 1d9d3ba6c2456..57c6cfa2e927d 100644 --- a/crates/bevy_ecs/src/system/query.rs +++ b/crates/bevy_ecs/src/system/query.rs @@ -23,7 +23,7 @@ use core::{ /// Queries enable systems to access [entity identifiers] and [components] without requiring direct access to the [`World`]. /// Its iterators and getter methods return *query items*, which are types containing data related to an entity. /// -/// `Query` is a generic data structure that accepts two type parameters: +/// `Query` is a generic data structure that accepts three type parameters: /// /// - **`D` (query data)**: /// The type of data fetched by the query, which will be returned as the query item. @@ -33,6 +33,11 @@ use core::{ /// An optional set of conditions that determine whether query items should be kept or discarded. /// This defaults to [`unit`], which means no additional filters will be applied. /// Must implement the [`QueryFilter`] trait. +/// - **`S` (query state)**: +/// An optional type that indicates how the internal state of the query is stored. +/// For the query to be a system parameter, this must be the default of `&'state QueryState`. +/// That stores the state along with the system, and borrows from it when running. +/// For cases where a query needs to contain an owned state, use the [`QueryLens`] type alias. /// /// [system parameter]: crate::system::SystemParam /// [`Component`]: crate::component::Component From 27eeba533dc58341ebb6735a97bcd4801345f280 Mon Sep 17 00:00:00 2001 From: Chris Russell <8494645+chescock@users.noreply.github.com> Date: Wed, 29 Oct 2025 16:15:26 -0400 Subject: [PATCH 07/10] Restore changes to `Query::get_inner`. --- crates/bevy_ecs/src/system/query.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/bevy_ecs/src/system/query.rs b/crates/bevy_ecs/src/system/query.rs index f4ea265cc528f..76ae25d3e6f05 100644 --- a/crates/bevy_ecs/src/system/query.rs +++ b/crates/bevy_ecs/src/system/query.rs @@ -2382,13 +2382,13 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { &mut filter, entity, location.table_row, + ) && let Some(item) = D::fetch( + &self.state.fetch_state, + &mut fetch, + entity, + location.table_row, ) { - Ok(D::fetch( - &self.state.fetch_state, - &mut fetch, - entity, - location.table_row, - )) + Ok(item) } else { Err(QueryEntityError::QueryDoesNotMatch( entity, From 72f76ad5012578cca9a16dc07124d2c95a51ba1d Mon Sep 17 00:00:00 2001 From: Chris Russell <8494645+chescock@users.noreply.github.com> Date: Wed, 10 Dec 2025 21:33:43 -0500 Subject: [PATCH 08/10] Use a type family to make it easier to be generic in query type. --- crates/bevy_ecs/src/query/state.rs | 28 ++++- .../src/relationship/relationship_query.rs | 110 +++++------------- crates/bevy_ecs/src/system/query.rs | 49 ++++---- 3 files changed, 75 insertions(+), 112 deletions(-) diff --git a/crates/bevy_ecs/src/query/state.rs b/crates/bevy_ecs/src/query/state.rs index 1ad6cf81cef07..54321643fabb1 100644 --- a/crates/bevy_ecs/src/query/state.rs +++ b/crates/bevy_ecs/src/query/state.rs @@ -14,9 +14,9 @@ use crate::{ #[cfg(all(not(target_arch = "wasm32"), feature = "multi_threaded"))] use crate::entity::UniqueEntityEquivalentSlice; -use alloc::vec::Vec; +use alloc::{boxed::Box, vec::Vec}; use bevy_utils::prelude::DebugName; -use core::{fmt, ptr}; +use core::{fmt, ops::Deref, ptr}; use fixedbitset::FixedBitSet; use log::warn; #[cfg(feature = "trace")] @@ -89,6 +89,30 @@ pub struct QueryState { par_iter_span: Span, } +/// Indicates how the internal state of a [`Query`] is stored. +pub trait QueryType { + /// The type used to store the internal state of a [`Query`]. + type QueryState<'s, D: QueryData + 's, F: QueryFilter + 's>: Deref>; +} + +/// A [`Query`] that holds a shared borrow of its internal state. +/// +/// This is the default [`QueryType`] for a [`Query`], and is used by [system parameters](crate::system::SystemParam). +pub struct BorrowedQuery; + +impl QueryType for BorrowedQuery { + type QueryState<'s, D: QueryData + 's, F: QueryFilter + 's> = &'s QueryState; +} + +/// A [`Query`] that owns its internal state. +/// +/// This is the [`QueryType`] for a [`QueryLens`](crate::system::QueryLens). +pub struct OwnedQuery; + +impl QueryType for OwnedQuery { + type QueryState<'s, D: QueryData + 's, F: QueryFilter + 's> = Box>; +} + impl fmt::Debug for QueryState { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("QueryState") diff --git a/crates/bevy_ecs/src/relationship/relationship_query.rs b/crates/bevy_ecs/src/relationship/relationship_query.rs index d6827b4c94688..2294b0a3c6be4 100644 --- a/crates/bevy_ecs/src/relationship/relationship_query.rs +++ b/crates/bevy_ecs/src/relationship/relationship_query.rs @@ -1,8 +1,6 @@ -use core::ops::Deref; - use crate::{ entity::Entity, - query::{QueryData, QueryFilter, QueryState}, + query::{QueryData, QueryFilter, QueryType}, relationship::{Relationship, RelationshipTarget}, system::Query, }; @@ -11,9 +9,7 @@ use smallvec::SmallVec; use super::SourceIter; -impl<'w, 's, D: QueryData, F: QueryFilter, S: Deref>> - Query<'w, 's, D, F, S> -{ +impl<'w, 's, D: QueryData, F: QueryFilter, T: QueryType> Query<'w, 's, D, F, T> { /// If the given `entity` contains the `R` [`Relationship`] component, returns the /// target entity of that relationship. pub fn related(&'w self, entity: Entity) -> Option @@ -64,7 +60,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter, S: Deref>> pub fn iter_leaves( &'w self, entity: Entity, - ) -> impl Iterator + use<'w, 's, D, F, S, R> + ) -> impl Iterator + use<'w, 's, D, F, T, R> where D::ReadOnly: QueryData = &'w R>, SourceIter<'w, R>: DoubleEndedIterator, @@ -105,7 +101,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter, S: Deref>> pub fn iter_descendants( &'w self, entity: Entity, - ) -> DescendantIter<'w, 's, D, F, S, R> + ) -> DescendantIter<'w, 's, D, F, T, R> where D::ReadOnly: QueryData = &'w R>, { @@ -122,7 +118,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter, S: Deref>> pub fn iter_descendants_depth_first( &'w self, entity: Entity, - ) -> DescendantDepthFirstIter<'w, 's, D, F, S, R> + ) -> DescendantDepthFirstIter<'w, 's, D, F, T, R> where D::ReadOnly: QueryData = &'w R>, SourceIter<'w, R>: DoubleEndedIterator, @@ -139,7 +135,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter, S: Deref>> pub fn iter_ancestors( &'w self, entity: Entity, - ) -> AncestorIter<'w, 's, D, F, S, R> + ) -> AncestorIter<'w, 's, D, F, T, R> where D::ReadOnly: QueryData = &'w R>, { @@ -150,33 +146,21 @@ impl<'w, 's, D: QueryData, F: QueryFilter, S: Deref>> /// An [`Iterator`] of [`Entity`]s over the descendants of an [`Entity`]. /// /// Traverses the hierarchy breadth-first. -pub struct DescendantIter< - 'w, - 's, - D: QueryData, - F: QueryFilter, - S: Deref>, - R: RelationshipTarget, -> where +pub struct DescendantIter<'w, 's, D: QueryData, F: QueryFilter, T: QueryType, R: RelationshipTarget> +where D::ReadOnly: QueryData = &'w R>, { - children_query: &'w Query<'w, 's, D, F, S>, + children_query: &'w Query<'w, 's, D, F, T>, vecdeque: VecDeque, } -impl< - 'w, - 's, - D: QueryData, - F: QueryFilter, - S: Deref>, - R: RelationshipTarget, - > DescendantIter<'w, 's, D, F, S, R> +impl<'w, 's, D: QueryData, F: QueryFilter, T: QueryType, R: RelationshipTarget> + DescendantIter<'w, 's, D, F, T, R> where D::ReadOnly: QueryData = &'w R>, { /// Returns a new [`DescendantIter`]. - pub fn new(children_query: &'w Query<'w, 's, D, F, S>, entity: Entity) -> Self { + pub fn new(children_query: &'w Query<'w, 's, D, F, T>, entity: Entity) -> Self { DescendantIter { children_query, vecdeque: children_query @@ -188,14 +172,8 @@ where } } -impl< - 'w, - 's, - D: QueryData, - F: QueryFilter, - S: Deref>, - R: RelationshipTarget, - > Iterator for DescendantIter<'w, 's, D, F, S, R> +impl<'w, 's, D: QueryData, F: QueryFilter, T: QueryType, R: RelationshipTarget> Iterator + for DescendantIter<'w, 's, D, F, T, R> where D::ReadOnly: QueryData = &'w R>, { @@ -220,29 +198,23 @@ pub struct DescendantDepthFirstIter< 's, D: QueryData, F: QueryFilter, - S: Deref>, + T: QueryType, R: RelationshipTarget, > where D::ReadOnly: QueryData = &'w R>, { - children_query: &'w Query<'w, 's, D, F, S>, + children_query: &'w Query<'w, 's, D, F, T>, stack: SmallVec<[Entity; 8]>, } -impl< - 'w, - 's, - D: QueryData, - F: QueryFilter, - S: Deref>, - R: RelationshipTarget, - > DescendantDepthFirstIter<'w, 's, D, F, S, R> +impl<'w, 's, D: QueryData, F: QueryFilter, T: QueryType, R: RelationshipTarget> + DescendantDepthFirstIter<'w, 's, D, F, T, R> where D::ReadOnly: QueryData = &'w R>, SourceIter<'w, R>: DoubleEndedIterator, { /// Returns a new [`DescendantDepthFirstIter`]. - pub fn new(children_query: &'w Query<'w, 's, D, F, S>, entity: Entity) -> Self { + pub fn new(children_query: &'w Query<'w, 's, D, F, T>, entity: Entity) -> Self { DescendantDepthFirstIter { children_query, stack: children_query @@ -252,14 +224,8 @@ where } } -impl< - 'w, - 's, - D: QueryData, - F: QueryFilter, - S: Deref>, - R: RelationshipTarget, - > Iterator for DescendantDepthFirstIter<'w, 's, D, F, S, R> +impl<'w, 's, D: QueryData, F: QueryFilter, T: QueryType, R: RelationshipTarget> Iterator + for DescendantDepthFirstIter<'w, 's, D, F, T, R> where D::ReadOnly: QueryData = &'w R>, SourceIter<'w, R>: DoubleEndedIterator, @@ -278,33 +244,21 @@ where } /// An [`Iterator`] of [`Entity`]s over the ancestors of an [`Entity`]. -pub struct AncestorIter< - 'w, - 's, - D: QueryData, - F: QueryFilter, - S: Deref>, - R: Relationship, -> where +pub struct AncestorIter<'w, 's, D: QueryData, F: QueryFilter, T: QueryType, R: Relationship> +where D::ReadOnly: QueryData = &'w R>, { - parent_query: &'w Query<'w, 's, D, F, S>, + parent_query: &'w Query<'w, 's, D, F, T>, next: Option, } -impl< - 'w, - 's, - D: QueryData, - F: QueryFilter, - S: Deref>, - R: Relationship, - > AncestorIter<'w, 's, D, F, S, R> +impl<'w, 's, D: QueryData, F: QueryFilter, T: QueryType, R: Relationship> + AncestorIter<'w, 's, D, F, T, R> where D::ReadOnly: QueryData = &'w R>, { /// Returns a new [`AncestorIter`]. - pub fn new(parent_query: &'w Query<'w, 's, D, F, S>, entity: Entity) -> Self { + pub fn new(parent_query: &'w Query<'w, 's, D, F, T>, entity: Entity) -> Self { AncestorIter { parent_query, next: Some(entity), @@ -312,14 +266,8 @@ where } } -impl< - 'w, - 's, - D: QueryData, - F: QueryFilter, - S: Deref>, - R: Relationship, - > Iterator for AncestorIter<'w, 's, D, F, S, R> +impl<'w, 's, D: QueryData, F: QueryFilter, T: QueryType, R: Relationship> Iterator + for AncestorIter<'w, 's, D, F, T, R> where D::ReadOnly: QueryData = &'w R>, { diff --git a/crates/bevy_ecs/src/system/query.rs b/crates/bevy_ecs/src/system/query.rs index 55f7707087898..4360687897539 100644 --- a/crates/bevy_ecs/src/system/query.rs +++ b/crates/bevy_ecs/src/system/query.rs @@ -5,9 +5,10 @@ use crate::{ change_detection::Tick, entity::{Entity, EntityEquivalent, EntitySet, UniqueEntityArray}, query::{ - DebugCheckedUnwrap, NopWorldQuery, QueryCombinationIter, QueryData, QueryEntityError, - QueryFilter, QueryIter, QueryManyIter, QueryManyUniqueIter, QueryParIter, QueryParManyIter, - QueryParManyUniqueIter, QuerySingleError, QueryState, ROQueryItem, ReadOnlyQueryData, + BorrowedQuery, DebugCheckedUnwrap, NopWorldQuery, OwnedQuery, QueryCombinationIter, + QueryData, QueryEntityError, QueryFilter, QueryIter, QueryManyIter, QueryManyUniqueIter, + QueryParIter, QueryParManyIter, QueryParManyUniqueIter, QuerySingleError, QueryState, + QueryType, ROQueryItem, ReadOnlyQueryData, }, world::unsafe_world_cell::UnsafeWorldCell, }; @@ -33,9 +34,9 @@ use core::{ /// An optional set of conditions that determine whether query items should be kept or discarded. /// This defaults to [`unit`], which means no additional filters will be applied. /// Must implement the [`QueryFilter`] trait. -/// - **`S` (query state)**: +/// - **`T` (query type)**: /// An optional type that indicates how the internal state of the query is stored. -/// For the query to be a system parameter, this must be the default of `&'state QueryState`. +/// For the query to be a system parameter, this must be the default of [`BorrowedQuery`]. /// That stores the state along with the system, and borrows from it when running. /// For cases where a query needs to contain an owned state, use the [`QueryLens`] type alias. /// @@ -488,23 +489,15 @@ use core::{ /// ``` /// /// [autovectorization]: https://en.wikipedia.org/wiki/Automatic_vectorization -pub struct Query< - 'world, - // Note that `'state` is only used in the default type for `S`. - // That's necessary to make `Query` be a valid `SystemParam`. - 'state, - D: QueryData, - F: QueryFilter = (), - S: Deref> = &'state QueryState, -> { +pub struct Query<'world, 'state, D: QueryData, F: QueryFilter = (), T: QueryType = BorrowedQuery> { // SAFETY: Must have access to the components registered in `state`. world: UnsafeWorldCell<'world>, - state: S, + state: T::QueryState<'state, D, F>, last_run: Tick, this_run: Tick, - // Note that `&'state QueryState` won't work because - // `QueryLens` uses `'static`, but `D` and `F` might not be `'static`. - marker: PhantomData<(&'state (), fn() -> QueryState)>, + // This `PhantomData` creates implied bounds that `D: 'state` and `F: 'state`, + // making `T::QueryState<'state, D, F>` a valid type without needing explicit bounds + marker: PhantomData<&'state QueryState>, } impl Clone for Query<'_, '_, D, F> { @@ -527,9 +520,7 @@ impl core::fmt::Debug for Query<'_, '_, D, F> { } } -impl<'w, 's, D: QueryData, F: QueryFilter, S: Deref>> - Query<'w, 's, D, F, S> -{ +impl<'w, 's, D: QueryData, F: QueryFilter, T: QueryType> Query<'w, 's, D, F, T> { /// Creates a new query. /// /// # Safety @@ -540,7 +531,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter, S: Deref>> #[inline] pub(crate) unsafe fn new( world: UnsafeWorldCell<'w>, - state: S, + state: T::QueryState<'s, D, F>, last_run: Tick, this_run: Tick, ) -> Self { @@ -628,7 +619,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter, S: Deref>> // SAFETY: // - This is memory safe because the caller ensures that there are no conflicting references. // - The world matches because it was the same one used to construct self. - unsafe { Query::new(self.world, &self.state, self.last_run, self.this_run) } + unsafe { Query::new(self.world, &*self.state, self.last_run, self.this_run) } } /// Returns an [`Iterator`] over the read-only query items. @@ -2542,9 +2533,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> IntoIterator for Query<'w, 's, D, F> } } -impl<'w, D: QueryData, F: QueryFilter, S: Deref>> IntoIterator - for &'w Query<'_, '_, D, F, S> -{ +impl<'w, D: QueryData, F: QueryFilter, T: QueryType> IntoIterator for &'w Query<'_, '_, D, F, T> { type Item = ROQueryItem<'w, 'w, D>; type IntoIter = QueryIter<'w, 'w, D::ReadOnly, F>; @@ -2553,8 +2542,8 @@ impl<'w, D: QueryData, F: QueryFilter, S: Deref>> Into } } -impl<'w, D: QueryData, F: QueryFilter, S: Deref>> IntoIterator - for &'w mut Query<'_, '_, D, F, S> +impl<'w, D: QueryData, F: QueryFilter, T: QueryType> IntoIterator + for &'w mut Query<'_, '_, D, F, T> { type Item = D::Item<'w, 'w>; type IntoIter = QueryIter<'w, 'w, D, F>; @@ -2597,7 +2586,9 @@ impl<'w, 's, D: ReadOnlyQueryData, F: QueryFilter> Query<'w, 's, D, F> { /// A [`Query`] with an owned [`QueryState`]. /// /// This is returned from methods like [`Query::transmute_lens`] that construct a fresh [`QueryState`]. -pub type QueryLens<'w, Q, F = ()> = Query<'w, 'static, Q, F, Box>>; +// The `'state` lifetime is ignored by `OwnedQuery`, but `Query` still requires `D` and `F` outlive it. +// Using `'w` here allows `as_query_lens()` to work for all source queries, since `D: 'w`. +pub type QueryLens<'w, Q, F = ()> = Query<'w, 'w, Q, F, OwnedQuery>; impl<'w, Q: QueryData, F: QueryFilter> QueryLens<'w, Q, F> { /// Create a [`Query`] from the underlying [`QueryState`]. From 71469e9670813c3a5227de579d50ed61e9d2fc54 Mon Sep 17 00:00:00 2001 From: Chris Russell <8494645+chescock@users.noreply.github.com> Date: Wed, 10 Dec 2025 21:52:21 -0500 Subject: [PATCH 09/10] Restore parameter name of `S` for `RelationshipTarget` now that we aren't using it in `Query`. --- .../src/relationship/relationship_query.rs | 62 +++++++++---------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/crates/bevy_ecs/src/relationship/relationship_query.rs b/crates/bevy_ecs/src/relationship/relationship_query.rs index 2294b0a3c6be4..510e7ef985541 100644 --- a/crates/bevy_ecs/src/relationship/relationship_query.rs +++ b/crates/bevy_ecs/src/relationship/relationship_query.rs @@ -21,12 +21,12 @@ impl<'w, 's, D: QueryData, F: QueryFilter, T: QueryType> Query<'w, 's, D, F, T> /// If the given `entity` contains the `S` [`RelationshipTarget`] component, returns the /// source entities stored on that component. - pub fn relationship_sources( + pub fn relationship_sources( &'w self, entity: Entity, ) -> impl Iterator + 'w where - D::ReadOnly: QueryData = &'w R>, + D::ReadOnly: QueryData = &'w S>, { self.get(entity) .into_iter() @@ -57,13 +57,13 @@ impl<'w, 's, D: QueryData, F: QueryFilter, T: QueryType> Query<'w, 's, D, F, T> /// /// For relationship graphs that contain loops, this could loop infinitely. /// If your relationship is not a tree (like Bevy's hierarchy), be sure to stop if you encounter a duplicate entity. - pub fn iter_leaves( + pub fn iter_leaves( &'w self, entity: Entity, - ) -> impl Iterator + use<'w, 's, D, F, T, R> + ) -> impl Iterator + use<'w, 's, S, D, F, T> where - D::ReadOnly: QueryData = &'w R>, - SourceIter<'w, R>: DoubleEndedIterator, + D::ReadOnly: QueryData = &'w S>, + SourceIter<'w, S>: DoubleEndedIterator, { self.iter_descendants_depth_first(entity).filter(|entity| { self.get(*entity) @@ -98,12 +98,12 @@ impl<'w, 's, D: QueryData, F: QueryFilter, T: QueryType> Query<'w, 's, D, F, T> /// /// For relationship graphs that contain loops, this could loop infinitely. /// If your relationship is not a tree (like Bevy's hierarchy), be sure to stop if you encounter a duplicate entity. - pub fn iter_descendants( + pub fn iter_descendants( &'w self, entity: Entity, - ) -> DescendantIter<'w, 's, D, F, T, R> + ) -> DescendantIter<'w, 's, D, F, T, S> where - D::ReadOnly: QueryData = &'w R>, + D::ReadOnly: QueryData = &'w S>, { DescendantIter::new(self, entity) } @@ -115,13 +115,13 @@ impl<'w, 's, D: QueryData, F: QueryFilter, T: QueryType> Query<'w, 's, D, F, T> /// /// For relationship graphs that contain loops, this could loop infinitely. /// If your relationship is not a tree (like Bevy's hierarchy), be sure to stop if you encounter a duplicate entity. - pub fn iter_descendants_depth_first( + pub fn iter_descendants_depth_first( &'w self, entity: Entity, - ) -> DescendantDepthFirstIter<'w, 's, D, F, T, R> + ) -> DescendantDepthFirstIter<'w, 's, D, F, T, S> where - D::ReadOnly: QueryData = &'w R>, - SourceIter<'w, R>: DoubleEndedIterator, + D::ReadOnly: QueryData = &'w S>, + SourceIter<'w, S>: DoubleEndedIterator, { DescendantDepthFirstIter::new(self, entity) } @@ -146,18 +146,18 @@ impl<'w, 's, D: QueryData, F: QueryFilter, T: QueryType> Query<'w, 's, D, F, T> /// An [`Iterator`] of [`Entity`]s over the descendants of an [`Entity`]. /// /// Traverses the hierarchy breadth-first. -pub struct DescendantIter<'w, 's, D: QueryData, F: QueryFilter, T: QueryType, R: RelationshipTarget> +pub struct DescendantIter<'w, 's, D: QueryData, F: QueryFilter, T: QueryType, S: RelationshipTarget> where - D::ReadOnly: QueryData = &'w R>, + D::ReadOnly: QueryData = &'w S>, { children_query: &'w Query<'w, 's, D, F, T>, vecdeque: VecDeque, } -impl<'w, 's, D: QueryData, F: QueryFilter, T: QueryType, R: RelationshipTarget> - DescendantIter<'w, 's, D, F, T, R> +impl<'w, 's, D: QueryData, F: QueryFilter, T: QueryType, S: RelationshipTarget> + DescendantIter<'w, 's, D, F, T, S> where - D::ReadOnly: QueryData = &'w R>, + D::ReadOnly: QueryData = &'w S>, { /// Returns a new [`DescendantIter`]. pub fn new(children_query: &'w Query<'w, 's, D, F, T>, entity: Entity) -> Self { @@ -172,10 +172,10 @@ where } } -impl<'w, 's, D: QueryData, F: QueryFilter, T: QueryType, R: RelationshipTarget> Iterator - for DescendantIter<'w, 's, D, F, T, R> +impl<'w, 's, D: QueryData, F: QueryFilter, T: QueryType, S: RelationshipTarget> Iterator + for DescendantIter<'w, 's, D, F, T, S> where - D::ReadOnly: QueryData = &'w R>, + D::ReadOnly: QueryData = &'w S>, { type Item = Entity; @@ -199,19 +199,19 @@ pub struct DescendantDepthFirstIter< D: QueryData, F: QueryFilter, T: QueryType, - R: RelationshipTarget, + S: RelationshipTarget, > where - D::ReadOnly: QueryData = &'w R>, + D::ReadOnly: QueryData = &'w S>, { children_query: &'w Query<'w, 's, D, F, T>, stack: SmallVec<[Entity; 8]>, } -impl<'w, 's, D: QueryData, F: QueryFilter, T: QueryType, R: RelationshipTarget> - DescendantDepthFirstIter<'w, 's, D, F, T, R> +impl<'w, 's, D: QueryData, F: QueryFilter, T: QueryType, S: RelationshipTarget> + DescendantDepthFirstIter<'w, 's, D, F, T, S> where - D::ReadOnly: QueryData = &'w R>, - SourceIter<'w, R>: DoubleEndedIterator, + D::ReadOnly: QueryData = &'w S>, + SourceIter<'w, S>: DoubleEndedIterator, { /// Returns a new [`DescendantDepthFirstIter`]. pub fn new(children_query: &'w Query<'w, 's, D, F, T>, entity: Entity) -> Self { @@ -224,11 +224,11 @@ where } } -impl<'w, 's, D: QueryData, F: QueryFilter, T: QueryType, R: RelationshipTarget> Iterator - for DescendantDepthFirstIter<'w, 's, D, F, T, R> +impl<'w, 's, D: QueryData, F: QueryFilter, T: QueryType, S: RelationshipTarget> Iterator + for DescendantDepthFirstIter<'w, 's, D, F, T, S> where - D::ReadOnly: QueryData = &'w R>, - SourceIter<'w, R>: DoubleEndedIterator, + D::ReadOnly: QueryData = &'w S>, + SourceIter<'w, S>: DoubleEndedIterator, { type Item = Entity; From 885831b10358b1b9521973923e5f3dbb8226cc6c Mon Sep 17 00:00:00 2001 From: Chris Russell <8494645+chescock@users.noreply.github.com> Date: Wed, 10 Dec 2025 22:02:25 -0500 Subject: [PATCH 10/10] Add additional lifetime because `Query` is no longer covariant in `'state`. --- crates/bevy_text/src/text_access.rs | 12 +++--- .../src/experimental/ghost_hierarchy.rs | 22 +++++----- .../combine_query_and_query_lens.md | 43 ++++++++++++++++++- 3 files changed, 59 insertions(+), 18 deletions(-) diff --git a/crates/bevy_text/src/text_access.rs b/crates/bevy_text/src/text_access.rs index 9d04c1dbb5da8..cb4de4ddccbc4 100644 --- a/crates/bevy_text/src/text_access.rs +++ b/crates/bevy_text/src/text_access.rs @@ -77,7 +77,7 @@ pub struct TextReader<'w, 's, R: TextRoot> { impl<'w, 's, R: TextRoot> TextReader<'w, 's, R> { /// Returns an iterator over text spans in a text block, starting with the root entity. - pub fn iter(&mut self, root_entity: Entity) -> TextSpanIter<'_, R> { + pub fn iter(&mut self, root_entity: Entity) -> TextSpanIter<'_, 's, R> { let stack = self.scratch.take(); TextSpanIter { @@ -154,14 +154,14 @@ impl<'w, 's, R: TextRoot> TextReader<'w, 's, R> { /// Iterates all spans in a text block according to hierarchy traversal order. /// Does *not* flatten interspersed ghost nodes. Only contiguous spans are traversed. // TODO: Use this iterator design in UiChildrenIter to reduce allocations. -pub struct TextSpanIter<'a, R: TextRoot> { +pub struct TextSpanIter<'a, 's, R: TextRoot> { scratch: &'a mut TextIterScratch, root_entity: Option, /// Stack of (children, next index into children). stack: Vec<(&'a Children, usize)>, roots: &'a Query< 'a, - 'a, + 's, ( &'static R, &'static TextFont, @@ -172,7 +172,7 @@ pub struct TextSpanIter<'a, R: TextRoot> { >, spans: &'a Query< 'a, - 'a, + 's, ( &'static TextSpan, &'static TextFont, @@ -183,7 +183,7 @@ pub struct TextSpanIter<'a, R: TextRoot> { >, } -impl<'a, R: TextRoot> Iterator for TextSpanIter<'a, R> { +impl<'a, R: TextRoot> Iterator for TextSpanIter<'a, '_, R> { /// Item = (entity in text block, hierarchy depth in the block, span text, span style). type Item = (Entity, usize, &'a str, &'a TextFont, Color, LineHeight); fn next(&mut self) -> Option { @@ -246,7 +246,7 @@ impl<'a, R: TextRoot> Iterator for TextSpanIter<'a, R> { } } -impl<'a, R: TextRoot> Drop for TextSpanIter<'a, R> { +impl<'a, R: TextRoot> Drop for TextSpanIter<'a, '_, R> { fn drop(&mut self) { // Return the internal stack. let stack = core::mem::take(&mut self.stack); diff --git a/crates/bevy_ui/src/experimental/ghost_hierarchy.rs b/crates/bevy_ui/src/experimental/ghost_hierarchy.rs index 79d081c6bfd4d..3de3c58dde51c 100644 --- a/crates/bevy_ui/src/experimental/ghost_hierarchy.rs +++ b/crates/bevy_ui/src/experimental/ghost_hierarchy.rs @@ -41,7 +41,7 @@ pub type UiRootNodes<'w, 's> = Query<'w, 's, Entity, (With, Without UiRootNodes<'w, 's> { - pub fn iter(&'s self) -> impl Iterator + 's { + pub fn iter(&self) -> impl Iterator + '_ { self.root_node_query .iter() .chain(self.root_ghost_node_query.iter().flat_map(|root_ghost| { @@ -85,7 +85,7 @@ impl<'w, 's> UiChildren<'w, 's> { /// # Performance /// /// This iterator allocates if the `entity` node has more than 8 children (including ghost nodes). - pub fn iter_ui_children(&'s self, entity: Entity) -> UiChildrenIter<'w, 's> { + pub fn iter_ui_children(&self, entity: Entity) -> UiChildrenIter<'_, 's> { UiChildrenIter { stack: self .ui_children_query @@ -98,14 +98,14 @@ impl<'w, 's> UiChildren<'w, 's> { } /// Returns the UI parent of the provided entity, skipping over [`GhostNode`]. - pub fn get_parent(&'s self, entity: Entity) -> Option { + pub fn get_parent(&self, entity: Entity) -> Option { self.parents_query .iter_ancestors(entity) .find(|entity| !self.ghost_nodes_query.contains(*entity)) } /// Iterates the [`GhostNode`]s between this entity and its UI children. - pub fn iter_ghost_nodes(&'s self, entity: Entity) -> Box + 's> { + pub fn iter_ghost_nodes(&self, entity: Entity) -> Box + '_> { Box::new( self.children_query .get(entity) @@ -121,7 +121,7 @@ impl<'w, 's> UiChildren<'w, 's> { } /// Given an entity in the UI hierarchy, check if its set of children has changed, e.g if children has been added/removed or if the order has changed. - pub fn is_changed(&'s self, entity: Entity) -> bool { + pub fn is_changed(&self, entity: Entity) -> bool { self.changed_children_query.contains(entity) || self .iter_ghost_nodes(entity) @@ -129,7 +129,7 @@ impl<'w, 's> UiChildren<'w, 's> { } /// Returns `true` if the given entity is either a [`Node`] or a [`GhostNode`]. - pub fn is_ui_node(&'s self, entity: Entity) -> bool { + pub fn is_ui_node(&self, entity: Entity) -> bool { self.ui_children_query.contains(entity) } } @@ -137,7 +137,7 @@ impl<'w, 's> UiChildren<'w, 's> { #[cfg(not(feature = "ghost_nodes"))] impl<'w, 's> UiChildren<'w, 's> { /// Iterates the children of `entity`. - pub fn iter_ui_children(&'s self, entity: Entity) -> impl Iterator + 's { + pub fn iter_ui_children(&self, entity: Entity) -> impl Iterator + '_ { self.ui_children_query .get(entity) .ok() @@ -149,17 +149,17 @@ impl<'w, 's> UiChildren<'w, 's> { } /// Returns the UI parent of the provided entity. - pub fn get_parent(&'s self, entity: Entity) -> Option { + pub fn get_parent(&self, entity: Entity) -> Option { self.parents_query.get(entity).ok().map(ChildOf::parent) } /// Given an entity in the UI hierarchy, check if its set of children has changed, e.g if children has been added/removed or if the order has changed. - pub fn is_changed(&'s self, entity: Entity) -> bool { + pub fn is_changed(&self, entity: Entity) -> bool { self.changed_children_query.contains(entity) } /// Returns `true` if the given entity is either a [`Node`] or a [`GhostNode`]. - pub fn is_ui_node(&'s self, entity: Entity) -> bool { + pub fn is_ui_node(&self, entity: Entity) -> bool { self.ui_children_query.contains(entity) } } @@ -167,7 +167,7 @@ impl<'w, 's> UiChildren<'w, 's> { #[cfg(feature = "ghost_nodes")] pub struct UiChildrenIter<'w, 's> { stack: SmallVec<[Entity; 8]>, - query: &'s Query< + query: &'w Query< 'w, 's, (Option<&'static Children>, Has), diff --git a/release-content/migration-guides/combine_query_and_query_lens.md b/release-content/migration-guides/combine_query_and_query_lens.md index a6f8be69168bf..2d4377517057c 100644 --- a/release-content/migration-guides/combine_query_and_query_lens.md +++ b/release-content/migration-guides/combine_query_and_query_lens.md @@ -1,6 +1,6 @@ --- title: Combine `Query` and `QueryLens` -pull_requests: [18162] +pull_requests: [19787] --- The `QueryLens::query()` method has been deprecated. @@ -18,3 +18,44 @@ fn with_lens(lens: QueryLens<&T>) -> Result { with_query(lens.reborrow()); } ``` + +One consequence of this change is that `Query<'w, 's, D, F>` is no longer covariant in `'s`. +This means trying to convert a `&'a Query<'w, 's, D, F>` to a `&'a Query<'w, 'a, D, F>` will now fail with `lifetime may not live long enough`. + +Note that `'w` is still covariant, so converting `&'a Query<'w, 's, D, F>` to `&'a Query<'a, 's, D, F>` will still succeed. + +You can usually resolve that error by introducing a new lifetime parameter for `'s`, +although in many cases it will be simpler to use the `reborrow()` or `as_readonly()` methods to shorten the lifetimes and create an owned query. + +```rust +// 0.17 +struct HasQueryBorrow<'a> { + query: &'a Query<'a, 'a, &'static C>, +} + +fn create(query: &Query<&'static C>) { + let hqb = HasQueryBorrow { query }; + // ^^^^^ + // This now fails with + // error: lifetime may not live long enough +} + +// 0.18 - Add additional lifetime parameter +struct HasQueryBorrow<'a, 's> { + query: &'a Query<'a, 's, &'static C>, +} + +fn create(query: &Query<&'static C>) { + let hqb = HasQueryBorrow { query }; +} + +// 0.18 - Or store an owned query instead of a reference +// and use `reborrow()` or `as_readonly()` +struct HasQueryBorrow<'a> { + query: Query<'a, 'a, &'static C>, +} + +fn create(query: &Query<&'static C>) { + let hqb = HasQueryBorrow { query: query.as_readonly() }; +} +```