use crate::{ archetype::Archetype, component::{ComponentId, 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>; /// 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) {} /// 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`. // 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); /// 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 the [`World`]. fn get_state(world: &World) -> Option; /// Returns `true` if this query matches a set of components. Otherwise, returns `false`. fn matches_component_set( state: &Self::State, set_contains_id: &impl Fn(ComponentId) -> bool, ) -> bool; } macro_rules! impl_tuple_world_query { ($(($name: ident, $state: ident)),*) => { #[allow(non_snake_case)] #[allow(clippy::unused_unit)] /// 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), )*) } #[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; ($($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; $($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; $($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; ($($name::fetch($name, _entity, _table_row),)*) } fn update_component_access(state: &Self::State, _access: &mut FilteredAccess) { let ($($name,)*) = state; $($name::update_component_access($name, _access);)* } fn init_state(_world: &mut World) -> Self::State { ($($name::init_state(_world),)*) } fn get_state(_world: &World) -> Option { Some(($($name::get_state(_world)?,)*)) } 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!(impl_tuple_world_query, 0, 15, F, S);