 e9e9e5e15d
			
		
	
	
		e9e9e5e15d
		
			
		
	
	
	
	
		
			
			# Objective - Sometimes some method or function takes an owned `Query`, but we don't want to give up ours; - transmuting it technically a solution, but it more costly than necessary. - Make query iterators more flexible - this would allow the equivalent of `slice::split_first`/`slice::split_first_mut` for query iterators - helps with requests like #14685 ## Solution - Add a way for reborrowing queries, that is going from a `&'a mut Query<'w, 's, D, F>` to a `Query<'a, 's, D, F>`: - this is safe because the original query will be borrowed while the new query exists and thus no aliased access can happen; - it's basically the equivalent of going from `&'short mut &'long mut T` to `&'short mut T` the the compiler automatically implements. - Add a way for getting the remainder of a query iterator: - this is interesting also because the original iterator keeps its position, which was not possible before; - this in turn requires a way to reborrow query fetches, which I had to add to `WorldQuery`. ## Showcase - You can now reborrow a `Query`, getting an equivalent `Query` with a shorter lifetime. Previously this was possible for read-only queries by using `Query::to_readonly`, now it's possible for mutable queries too; - You can now separately iterate over the remainder of `QueryIter`. ## Migration Guide - `WorldQuery` now has an additional `shrink_fetch` method you have to implement if you were implementing `WorldQuery` manually.
		
			
				
	
	
		
			251 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			251 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| use crate::{
 | |
|     archetype::Archetype,
 | |
|     component::{ComponentId, Components, Tick},
 | |
|     entity::Entity,
 | |
|     query::FilteredAccess,
 | |
|     storage::{Table, TableRow},
 | |
|     world::{unsafe_world_cell::UnsafeWorldCell, World},
 | |
| };
 | |
| use bevy_utils::all_tuples;
 | |
| 
 | |
| /// Types that can be used as parameters in a [`Query`].
 | |
| /// Types that implement this should also implement either [`QueryData`] or [`QueryFilter`]
 | |
| ///
 | |
| /// # Safety
 | |
| ///
 | |
| /// Implementor must ensure that
 | |
| /// [`update_component_access`], [`matches_component_set`], and [`fetch`]
 | |
| /// obey the following:
 | |
| ///
 | |
| /// - For each component mutably accessed by [`fetch`], [`update_component_access`] should add write access unless read or write access has already been added, in which case it should panic.
 | |
| /// - For each component readonly accessed by [`fetch`], [`update_component_access`] should add read access unless write access has already been added, in which case it should panic.
 | |
| /// - If `fetch` mutably accesses the same component twice, [`update_component_access`] should panic.
 | |
| /// - [`update_component_access`] may not add a `Without` filter for a component unless [`matches_component_set`] always returns `false` when the component set contains that component.
 | |
| /// - [`update_component_access`] may not add a `With` filter for a component unless [`matches_component_set`] always returns `false` when the component set doesn't contain that component.
 | |
| /// - In cases where the query represents a disjunction (such as an `Or` filter) where each element is a valid [`WorldQuery`], the following rules must be obeyed:
 | |
| ///     - [`matches_component_set`] must be a disjunction of the element's implementations
 | |
| ///     - [`update_component_access`] must replace the filters with a disjunction of filters
 | |
| ///     - Each filter in that disjunction must be a conjunction of the corresponding element's filter with the previous `access`
 | |
| ///
 | |
| /// When implementing [`update_component_access`], note that `add_read` and `add_write` both also add a `With` filter, whereas `extend_access` does not change the filters.
 | |
| ///
 | |
| /// [`fetch`]: Self::fetch
 | |
| /// [`matches_component_set`]: Self::matches_component_set
 | |
| /// [`Query`]: crate::system::Query
 | |
| /// [`update_component_access`]: Self::update_component_access
 | |
| /// [`QueryData`]: crate::query::QueryData
 | |
| /// [`QueryFilter`]: crate::query::QueryFilter
 | |
| pub unsafe trait WorldQuery {
 | |
|     /// The item returned by this [`WorldQuery`]
 | |
|     /// For `QueryData` this will be the item returned by the query.
 | |
|     /// For `QueryFilter` this will be either `()`, or a `bool` indicating whether the entity should be included
 | |
|     /// or a tuple of such things.
 | |
|     type Item<'a>;
 | |
| 
 | |
|     /// Per archetype/table state used by this [`WorldQuery`] to fetch [`Self::Item`](WorldQuery::Item)
 | |
|     type Fetch<'a>: Clone;
 | |
| 
 | |
|     /// State used to construct a [`Self::Fetch`](WorldQuery::Fetch). This will be cached inside [`QueryState`](crate::query::QueryState),
 | |
|     /// so it is best to move as much data / computation here as possible to reduce the cost of
 | |
|     /// constructing [`Self::Fetch`](WorldQuery::Fetch).
 | |
|     type State: Send + Sync + Sized;
 | |
| 
 | |
|     /// This function manually implements subtyping for the query items.
 | |
|     fn shrink<'wlong: 'wshort, 'wshort>(item: Self::Item<'wlong>) -> Self::Item<'wshort>;
 | |
| 
 | |
|     /// This function manually implements subtyping for the query fetches.
 | |
|     fn shrink_fetch<'wlong: 'wshort, 'wshort>(fetch: Self::Fetch<'wlong>) -> Self::Fetch<'wshort>;
 | |
| 
 | |
|     /// Creates a new instance of this fetch.
 | |
|     ///
 | |
|     /// # Safety
 | |
|     ///
 | |
|     /// - `state` must have been initialized (via [`WorldQuery::init_state`]) using the same `world` passed
 | |
|     ///   in to this function.
 | |
|     unsafe fn init_fetch<'w>(
 | |
|         world: UnsafeWorldCell<'w>,
 | |
|         state: &Self::State,
 | |
|         last_run: Tick,
 | |
|         this_run: Tick,
 | |
|     ) -> Self::Fetch<'w>;
 | |
| 
 | |
|     /// Returns true if (and only if) every table of every archetype matched by this fetch contains
 | |
|     /// all of the matched components. This is used to select a more efficient "table iterator"
 | |
|     /// for "dense" queries. If this returns true, [`WorldQuery::set_table`] must be used before
 | |
|     /// [`WorldQuery::fetch`] can be called for iterators. If this returns false,
 | |
|     /// [`WorldQuery::set_archetype`] must be used before [`WorldQuery::fetch`] can be called for
 | |
|     /// iterators.
 | |
|     const IS_DENSE: bool;
 | |
| 
 | |
|     /// Adjusts internal state to account for the next [`Archetype`]. This will always be called on
 | |
|     /// archetypes that match this [`WorldQuery`].
 | |
|     ///
 | |
|     /// # Safety
 | |
|     ///
 | |
|     /// - `archetype` and `tables` must be from the same [`World`] that [`WorldQuery::init_state`] was called on.
 | |
|     /// - `table` must correspond to `archetype`.
 | |
|     /// - `state` must be the [`State`](Self::State) that `fetch` was initialized with.
 | |
|     unsafe fn set_archetype<'w>(
 | |
|         fetch: &mut Self::Fetch<'w>,
 | |
|         state: &Self::State,
 | |
|         archetype: &'w Archetype,
 | |
|         table: &'w Table,
 | |
|     );
 | |
| 
 | |
|     /// Adjusts internal state to account for the next [`Table`]. This will always be called on tables
 | |
|     /// that match this [`WorldQuery`].
 | |
|     ///
 | |
|     /// # Safety
 | |
|     ///
 | |
|     /// - `table` must be from the same [`World`] that [`WorldQuery::init_state`] was called on.
 | |
|     /// - `state` must be the [`State`](Self::State) that `fetch` was initialized with.
 | |
|     unsafe fn set_table<'w>(fetch: &mut Self::Fetch<'w>, state: &Self::State, table: &'w Table);
 | |
| 
 | |
|     /// Sets available accesses for implementors with dynamic access such as [`FilteredEntityRef`](crate::world::FilteredEntityRef)
 | |
|     /// or [`FilteredEntityMut`](crate::world::FilteredEntityMut).
 | |
|     ///
 | |
|     /// Called when constructing a [`QueryLens`](crate::system::QueryLens) or calling [`QueryState::from_builder`](super::QueryState::from_builder)
 | |
|     fn set_access(_state: &mut Self::State, _access: &FilteredAccess<ComponentId>) {}
 | |
| 
 | |
|     /// Fetch [`Self::Item`](`WorldQuery::Item`) for either the given `entity` in the current [`Table`],
 | |
|     /// or for the given `entity` in the current [`Archetype`]. This must always be called after
 | |
|     /// [`WorldQuery::set_table`] with a `table_row` in the range of the current [`Table`] or after
 | |
|     /// [`WorldQuery::set_archetype`]  with a `entity` in the current archetype.
 | |
|     ///
 | |
|     /// # Safety
 | |
|     ///
 | |
|     /// Must always be called _after_ [`WorldQuery::set_table`] or [`WorldQuery::set_archetype`]. `entity` and
 | |
|     /// `table_row` must be in the range of the current table and archetype.
 | |
|     unsafe fn fetch<'w>(
 | |
|         fetch: &mut Self::Fetch<'w>,
 | |
|         entity: Entity,
 | |
|         table_row: TableRow,
 | |
|     ) -> Self::Item<'w>;
 | |
| 
 | |
|     /// Adds any component accesses used by this [`WorldQuery`] to `access`.
 | |
|     ///
 | |
|     /// Used to check which queries are disjoint and can run in parallel
 | |
|     // This does not have a default body of `{}` because 99% of cases need to add accesses
 | |
|     // and forgetting to do so would be unsound.
 | |
|     fn update_component_access(state: &Self::State, access: &mut FilteredAccess<ComponentId>);
 | |
| 
 | |
|     /// Creates and initializes a [`State`](WorldQuery::State) for this [`WorldQuery`] type.
 | |
|     fn init_state(world: &mut World) -> Self::State;
 | |
| 
 | |
|     /// Attempts to initialize a [`State`](WorldQuery::State) for this [`WorldQuery`] type using read-only
 | |
|     /// access to [`Components`].
 | |
|     fn get_state(components: &Components) -> Option<Self::State>;
 | |
| 
 | |
|     /// Returns `true` if this query matches a set of components. Otherwise, returns `false`.
 | |
|     ///
 | |
|     /// Used to check which [`Archetype`]s can be skipped by the query
 | |
|     /// (if none of the [`Component`](crate::component::Component)s match)
 | |
|     fn matches_component_set(
 | |
|         state: &Self::State,
 | |
|         set_contains_id: &impl Fn(ComponentId) -> bool,
 | |
|     ) -> bool;
 | |
| }
 | |
| 
 | |
| macro_rules! impl_tuple_world_query {
 | |
|     ($(#[$meta:meta])* $(($name: ident, $state: ident)),*) => {
 | |
| 
 | |
|         #[allow(non_snake_case)]
 | |
|         #[allow(clippy::unused_unit)]
 | |
|         $(#[$meta])*
 | |
|         /// SAFETY:
 | |
|         /// `fetch` accesses are the conjunction of the subqueries' accesses
 | |
|         /// This is sound because `update_component_access` adds accesses according to the implementations of all the subqueries.
 | |
|         /// `update_component_access` adds all `With` and `Without` filters from the subqueries.
 | |
|         /// This is sound because `matches_component_set` always returns `false` if any the subqueries' implementations return `false`.
 | |
|         unsafe impl<$($name: WorldQuery),*> WorldQuery for ($($name,)*) {
 | |
|             type Fetch<'w> = ($($name::Fetch<'w>,)*);
 | |
|             type Item<'w> = ($($name::Item<'w>,)*);
 | |
|             type State = ($($name::State,)*);
 | |
| 
 | |
|             fn shrink<'wlong: 'wshort, 'wshort>(item: Self::Item<'wlong>) -> Self::Item<'wshort> {
 | |
|                 let ($($name,)*) = item;
 | |
|                 ($(
 | |
|                     $name::shrink($name),
 | |
|                 )*)
 | |
|             }
 | |
| 
 | |
|             fn shrink_fetch<'wlong: 'wshort, 'wshort>(fetch: Self::Fetch<'wlong>) -> Self::Fetch<'wshort> {
 | |
|                 let ($($name,)*) = fetch;
 | |
|                 ($(
 | |
|                     $name::shrink_fetch($name),
 | |
|                 )*)
 | |
|             }
 | |
| 
 | |
|             #[inline]
 | |
|             #[allow(clippy::unused_unit)]
 | |
|             unsafe fn init_fetch<'w>(_world: UnsafeWorldCell<'w>, state: &Self::State, _last_run: Tick, _this_run: Tick) -> Self::Fetch<'w> {
 | |
|                 let ($($name,)*) = state;
 | |
|                 // SAFETY: The invariants are uphold by the caller.
 | |
|                 ($(unsafe { $name::init_fetch(_world, $name, _last_run, _this_run) },)*)
 | |
|             }
 | |
| 
 | |
|             const IS_DENSE: bool = true $(&& $name::IS_DENSE)*;
 | |
| 
 | |
|             #[inline]
 | |
|             unsafe fn set_archetype<'w>(
 | |
|                 _fetch: &mut Self::Fetch<'w>,
 | |
|                 _state: &Self::State,
 | |
|                 _archetype: &'w Archetype,
 | |
|                 _table: &'w Table
 | |
|             ) {
 | |
|                 let ($($name,)*) = _fetch;
 | |
|                 let ($($state,)*) = _state;
 | |
|                 // SAFETY: The invariants are uphold by the caller.
 | |
|                 $(unsafe { $name::set_archetype($name, $state, _archetype, _table); })*
 | |
|             }
 | |
| 
 | |
|             #[inline]
 | |
|             unsafe fn set_table<'w>(_fetch: &mut Self::Fetch<'w>, _state: &Self::State, _table: &'w Table) {
 | |
|                 let ($($name,)*) = _fetch;
 | |
|                 let ($($state,)*) = _state;
 | |
|                 // SAFETY: The invariants are uphold by the caller.
 | |
|                 $(unsafe { $name::set_table($name, $state, _table); })*
 | |
|             }
 | |
| 
 | |
|             #[inline(always)]
 | |
|             #[allow(clippy::unused_unit)]
 | |
|             unsafe fn fetch<'w>(
 | |
|                 _fetch: &mut Self::Fetch<'w>,
 | |
|                 _entity: Entity,
 | |
|                 _table_row: TableRow
 | |
|             ) -> Self::Item<'w> {
 | |
|                 let ($($name,)*) = _fetch;
 | |
|                 // SAFETY: The invariants are uphold by the caller.
 | |
|                 ($(unsafe { $name::fetch($name, _entity, _table_row) },)*)
 | |
|             }
 | |
| 
 | |
|             fn update_component_access(state: &Self::State, _access: &mut FilteredAccess<ComponentId>) {
 | |
|                 let ($($name,)*) = state;
 | |
|                 $($name::update_component_access($name, _access);)*
 | |
|             }
 | |
|             #[allow(unused_variables)]
 | |
|             fn init_state(world: &mut World) -> Self::State {
 | |
|                 ($($name::init_state(world),)*)
 | |
|             }
 | |
|             #[allow(unused_variables)]
 | |
|             fn get_state(components: &Components) -> Option<Self::State> {
 | |
|                 Some(($($name::get_state(components)?,)*))
 | |
|             }
 | |
| 
 | |
|             fn matches_component_set(state: &Self::State, _set_contains_id: &impl Fn(ComponentId) -> bool) -> bool {
 | |
|                 let ($($name,)*) = state;
 | |
|                 true $(&& $name::matches_component_set($name, _set_contains_id))*
 | |
|             }
 | |
|         }
 | |
|     };
 | |
| }
 | |
| 
 | |
| all_tuples!(
 | |
|     #[doc(fake_variadic)]
 | |
|     impl_tuple_world_query,
 | |
|     0,
 | |
|     15,
 | |
|     F,
 | |
|     S
 | |
| );
 |