Path: blob/main/crates/bevy_ecs/src/query/world_query.rs
6600 views
use crate::{1archetype::Archetype,2component::{ComponentId, Components, Tick},3query::FilteredAccess,4storage::Table,5world::{unsafe_world_cell::UnsafeWorldCell, World},6};7use variadics_please::all_tuples;89/// Types that can be used as parameters in a [`Query`].10/// Types that implement this should also implement either [`QueryData`] or [`QueryFilter`]11///12/// # Safety13///14/// Implementor must ensure that15/// [`update_component_access`], [`QueryData::provide_extra_access`], [`matches_component_set`], [`QueryData::fetch`], [`QueryFilter::filter_fetch`] and [`init_fetch`]16/// obey the following:17///18/// - For each component mutably accessed by [`QueryData::fetch`], [`update_component_access`] or [`QueryData::provide_extra_access`] should add write access unless read or write access has already been added, in which case it should panic.19/// - For each component readonly accessed by [`QueryData::fetch`] or [`QueryFilter::filter_fetch`], [`update_component_access`] or [`QueryData::provide_extra_access`] should add read access unless write access has already been added, in which case it should panic.20/// - If `fetch` mutably accesses the same component twice, [`update_component_access`] should panic.21/// - [`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.22/// - [`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.23/// - 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:24/// - [`matches_component_set`] must be a disjunction of the element's implementations25/// - [`update_component_access`] must replace the filters with a disjunction of filters26/// - Each filter in that disjunction must be a conjunction of the corresponding element's filter with the previous `access`27/// - For each resource readonly accessed by [`init_fetch`], [`update_component_access`] should add read access.28/// - Mutable resource access is not allowed.29/// - Any access added during [`QueryData::provide_extra_access`] must be a subset of `available_access`, and must not conflict with any access in `access`.30///31/// 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.32///33/// [`QueryData::provide_extra_access`]: crate::query::QueryData::provide_extra_access34/// [`QueryData::fetch`]: crate::query::QueryData::fetch35/// [`QueryFilter::filter_fetch`]: crate::query::QueryFilter::filter_fetch36/// [`init_fetch`]: Self::init_fetch37/// [`matches_component_set`]: Self::matches_component_set38/// [`Query`]: crate::system::Query39/// [`update_component_access`]: Self::update_component_access40/// [`QueryData`]: crate::query::QueryData41/// [`QueryFilter`]: crate::query::QueryFilter42pub unsafe trait WorldQuery {43/// Per archetype/table state retrieved by this [`WorldQuery`] to compute [`Self::Item`](crate::query::QueryData::Item) for each entity.44type Fetch<'w>: Clone;4546/// State used to construct a [`Self::Fetch`](WorldQuery::Fetch). This will be cached inside [`QueryState`](crate::query::QueryState),47/// so it is best to move as much data / computation here as possible to reduce the cost of48/// constructing [`Self::Fetch`](WorldQuery::Fetch).49type State: Send + Sync + Sized;5051/// This function manually implements subtyping for the query fetches.52fn shrink_fetch<'wlong: 'wshort, 'wshort>(fetch: Self::Fetch<'wlong>) -> Self::Fetch<'wshort>;5354/// Creates a new instance of [`Self::Fetch`](WorldQuery::Fetch),55/// by combining data from the [`World`] with the cached [`Self::State`](WorldQuery::State).56/// Readonly accesses resources registered in [`WorldQuery::update_component_access`].57///58/// # Safety59///60/// - `state` must have been initialized (via [`WorldQuery::init_state`]) using the same `world` passed61/// in to this function.62/// - `world` must have the **right** to access any access registered in `update_component_access`.63/// - There must not be simultaneous resource access conflicting with readonly resource access registered in [`WorldQuery::update_component_access`].64unsafe fn init_fetch<'w, 's>(65world: UnsafeWorldCell<'w>,66state: &'s Self::State,67last_run: Tick,68this_run: Tick,69) -> Self::Fetch<'w>;7071/// Returns true if (and only if) every table of every archetype matched by this fetch contains72/// all of the matched components.73///74/// This is used to select a more efficient "table iterator"75/// for "dense" queries. If this returns true, [`WorldQuery::set_table`] must be used before76/// [`QueryData::fetch`](crate::query::QueryData::fetch) can be called for iterators. If this returns false,77/// [`WorldQuery::set_archetype`] must be used before [`QueryData::fetch`](crate::query::QueryData::fetch) can be called for78/// iterators.79const IS_DENSE: bool;8081/// Adjusts internal state to account for the next [`Archetype`]. This will always be called on82/// archetypes that match this [`WorldQuery`].83///84/// # Safety85///86/// - `archetype` and `tables` must be from the same [`World`] that [`WorldQuery::init_state`] was called on.87/// - `table` must correspond to `archetype`.88/// - `state` must be the [`State`](Self::State) that `fetch` was initialized with.89unsafe fn set_archetype<'w, 's>(90fetch: &mut Self::Fetch<'w>,91state: &'s Self::State,92archetype: &'w Archetype,93table: &'w Table,94);9596/// Adjusts internal state to account for the next [`Table`]. This will always be called on tables97/// that match this [`WorldQuery`].98///99/// # Safety100///101/// - `table` must be from the same [`World`] that [`WorldQuery::init_state`] was called on.102/// - `state` must be the [`State`](Self::State) that `fetch` was initialized with.103unsafe fn set_table<'w, 's>(104fetch: &mut Self::Fetch<'w>,105state: &'s Self::State,106table: &'w Table,107);108109/// Adds any component accesses used by this [`WorldQuery`] to `access`.110///111/// Used to check which queries are disjoint and can run in parallel112// This does not have a default body of `{}` because 99% of cases need to add accesses113// and forgetting to do so would be unsound.114fn update_component_access(state: &Self::State, access: &mut FilteredAccess);115116/// Creates and initializes a [`State`](WorldQuery::State) for this [`WorldQuery`] type.117fn init_state(world: &mut World) -> Self::State;118119/// Attempts to initialize a [`State`](WorldQuery::State) for this [`WorldQuery`] type using read-only120/// access to [`Components`].121fn get_state(components: &Components) -> Option<Self::State>;122123/// Returns `true` if this query matches a set of components. Otherwise, returns `false`.124///125/// Used to check which [`Archetype`]s can be skipped by the query126/// (if none of the [`Component`](crate::component::Component)s match).127/// This is how archetypal query filters like `With` work.128fn matches_component_set(129state: &Self::State,130set_contains_id: &impl Fn(ComponentId) -> bool,131) -> bool;132}133134macro_rules! impl_tuple_world_query {135($(#[$meta:meta])* $(($name: ident, $state: ident)),*) => {136137#[expect(138clippy::allow_attributes,139reason = "This is a tuple-related macro; as such the lints below may not always apply."140)]141#[allow(142non_snake_case,143reason = "The names of some variables are provided by the macro's caller, not by us."144)]145#[allow(146unused_variables,147reason = "Zero-length tuples won't use any of the parameters."148)]149#[allow(150clippy::unused_unit,151reason = "Zero-length tuples will generate some function bodies equivalent to `()`; however, this macro is meant for all applicable tuples, and as such it makes no sense to rewrite it just for that case."152)]153$(#[$meta])*154/// SAFETY:155/// `fetch` accesses are the conjunction of the subqueries' accesses156/// This is sound because `update_component_access` adds accesses according to the implementations of all the subqueries.157/// `update_component_access` adds all `With` and `Without` filters from the subqueries.158/// This is sound because `matches_component_set` always returns `false` if any the subqueries' implementations return `false`.159unsafe impl<$($name: WorldQuery),*> WorldQuery for ($($name,)*) {160type Fetch<'w> = ($($name::Fetch<'w>,)*);161type State = ($($name::State,)*);162163164fn shrink_fetch<'wlong: 'wshort, 'wshort>(fetch: Self::Fetch<'wlong>) -> Self::Fetch<'wshort> {165let ($($name,)*) = fetch;166($(167$name::shrink_fetch($name),168)*)169}170171#[inline]172unsafe fn init_fetch<'w, 's>(world: UnsafeWorldCell<'w>, state: &'s Self::State, last_run: Tick, this_run: Tick) -> Self::Fetch<'w> {173let ($($name,)*) = state;174// SAFETY: The invariants are upheld by the caller.175($(unsafe { $name::init_fetch(world, $name, last_run, this_run) },)*)176}177178const IS_DENSE: bool = true $(&& $name::IS_DENSE)*;179180#[inline]181unsafe fn set_archetype<'w, 's>(182fetch: &mut Self::Fetch<'w>,183state: &'s Self::State,184archetype: &'w Archetype,185table: &'w Table186) {187let ($($name,)*) = fetch;188let ($($state,)*) = state;189// SAFETY: The invariants are upheld by the caller.190$(unsafe { $name::set_archetype($name, $state, archetype, table); })*191}192193#[inline]194unsafe fn set_table<'w, 's>(fetch: &mut Self::Fetch<'w>, state: &'s Self::State, table: &'w Table) {195let ($($name,)*) = fetch;196let ($($state,)*) = state;197// SAFETY: The invariants are upheld by the caller.198$(unsafe { $name::set_table($name, $state, table); })*199}200201202fn update_component_access(state: &Self::State, access: &mut FilteredAccess) {203let ($($name,)*) = state;204$($name::update_component_access($name, access);)*205}206fn init_state(world: &mut World) -> Self::State {207($($name::init_state(world),)*)208}209fn get_state(components: &Components) -> Option<Self::State> {210Some(($($name::get_state(components)?,)*))211}212213fn matches_component_set(state: &Self::State, set_contains_id: &impl Fn(ComponentId) -> bool) -> bool {214let ($($name,)*) = state;215true $(&& $name::matches_component_set($name, set_contains_id))*216}217}218};219}220221all_tuples!(222#[doc(fake_variadic)]223impl_tuple_world_query,2240,22515,226F,227S228);229230231