bevy_ecs/query/
world_query.rs

1use crate::{
2    archetype::Archetype,
3    component::{ComponentId, Components, Tick},
4    entity::Entity,
5    query::FilteredAccess,
6    storage::{Table, TableRow},
7    world::{unsafe_world_cell::UnsafeWorldCell, World},
8};
9use bevy_utils::all_tuples;
10
11/// Types that can be used as parameters in a [`Query`].
12/// Types that implement this should also implement either [`QueryData`] or [`QueryFilter`]
13///
14/// # Safety
15///
16/// Implementor must ensure that
17/// [`update_component_access`], [`matches_component_set`], and [`fetch`]
18/// obey the following:
19///
20/// - 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.
21/// - 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.
22/// - If `fetch` mutably accesses the same component twice, [`update_component_access`] should panic.
23/// - [`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.
24/// - [`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.
25/// - 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:
26///     - [`matches_component_set`] must be a disjunction of the element's implementations
27///     - [`update_component_access`] must replace the filters with a disjunction of filters
28///     - Each filter in that disjunction must be a conjunction of the corresponding element's filter with the previous `access`
29///
30/// 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.
31///
32/// [`fetch`]: Self::fetch
33/// [`matches_component_set`]: Self::matches_component_set
34/// [`Query`]: crate::system::Query
35/// [`update_component_access`]: Self::update_component_access
36/// [`QueryData`]: crate::query::QueryData
37/// [`QueryFilter`]: crate::query::QueryFilter
38pub unsafe trait WorldQuery {
39    /// The item returned by this [`WorldQuery`]
40    /// For `QueryData` this will be the item returned by the query.
41    /// For `QueryFilter` this will be either `()`, or a `bool` indicating whether the entity should be included
42    /// or a tuple of such things.
43    type Item<'a>;
44
45    /// Per archetype/table state used by this [`WorldQuery`] to fetch [`Self::Item`](WorldQuery::Item)
46    type Fetch<'a>: Clone;
47
48    /// State used to construct a [`Self::Fetch`](WorldQuery::Fetch). This will be cached inside [`QueryState`](crate::query::QueryState),
49    /// so it is best to move as much data / computation here as possible to reduce the cost of
50    /// constructing [`Self::Fetch`](WorldQuery::Fetch).
51    type State: Send + Sync + Sized;
52
53    /// This function manually implements subtyping for the query items.
54    fn shrink<'wlong: 'wshort, 'wshort>(item: Self::Item<'wlong>) -> Self::Item<'wshort>;
55
56    /// This function manually implements subtyping for the query fetches.
57    fn shrink_fetch<'wlong: 'wshort, 'wshort>(fetch: Self::Fetch<'wlong>) -> Self::Fetch<'wshort>;
58
59    /// Creates a new instance of this fetch.
60    ///
61    /// # Safety
62    ///
63    /// - `state` must have been initialized (via [`WorldQuery::init_state`]) using the same `world` passed
64    ///   in to this function.
65    unsafe fn init_fetch<'w>(
66        world: UnsafeWorldCell<'w>,
67        state: &Self::State,
68        last_run: Tick,
69        this_run: Tick,
70    ) -> Self::Fetch<'w>;
71
72    /// Returns true if (and only if) every table of every archetype matched by this fetch contains
73    /// all of the matched components. This is used to select a more efficient "table iterator"
74    /// for "dense" queries. If this returns true, [`WorldQuery::set_table`] must be used before
75    /// [`WorldQuery::fetch`] can be called for iterators. If this returns false,
76    /// [`WorldQuery::set_archetype`] must be used before [`WorldQuery::fetch`] can be called for
77    /// iterators.
78    const IS_DENSE: bool;
79
80    /// Adjusts internal state to account for the next [`Archetype`]. This will always be called on
81    /// archetypes that match this [`WorldQuery`].
82    ///
83    /// # Safety
84    ///
85    /// - `archetype` and `tables` must be from the same [`World`] that [`WorldQuery::init_state`] was called on.
86    /// - `table` must correspond to `archetype`.
87    /// - `state` must be the [`State`](Self::State) that `fetch` was initialized with.
88    unsafe fn set_archetype<'w>(
89        fetch: &mut Self::Fetch<'w>,
90        state: &Self::State,
91        archetype: &'w Archetype,
92        table: &'w Table,
93    );
94
95    /// Adjusts internal state to account for the next [`Table`]. This will always be called on tables
96    /// that match this [`WorldQuery`].
97    ///
98    /// # Safety
99    ///
100    /// - `table` must be from the same [`World`] that [`WorldQuery::init_state`] was called on.
101    /// - `state` must be the [`State`](Self::State) that `fetch` was initialized with.
102    unsafe fn set_table<'w>(fetch: &mut Self::Fetch<'w>, state: &Self::State, table: &'w Table);
103
104    /// Sets available accesses for implementors with dynamic access such as [`FilteredEntityRef`](crate::world::FilteredEntityRef)
105    /// or [`FilteredEntityMut`](crate::world::FilteredEntityMut).
106    ///
107    /// Called when constructing a [`QueryLens`](crate::system::QueryLens) or calling [`QueryState::from_builder`](super::QueryState::from_builder)
108    fn set_access(_state: &mut Self::State, _access: &FilteredAccess<ComponentId>) {}
109
110    /// Fetch [`Self::Item`](`WorldQuery::Item`) for either the given `entity` in the current [`Table`],
111    /// or for the given `entity` in the current [`Archetype`]. This must always be called after
112    /// [`WorldQuery::set_table`] with a `table_row` in the range of the current [`Table`] or after
113    /// [`WorldQuery::set_archetype`]  with a `entity` in the current archetype.
114    ///
115    /// # Safety
116    ///
117    /// Must always be called _after_ [`WorldQuery::set_table`] or [`WorldQuery::set_archetype`]. `entity` and
118    /// `table_row` must be in the range of the current table and archetype.
119    unsafe fn fetch<'w>(
120        fetch: &mut Self::Fetch<'w>,
121        entity: Entity,
122        table_row: TableRow,
123    ) -> Self::Item<'w>;
124
125    /// Adds any component accesses used by this [`WorldQuery`] to `access`.
126    ///
127    /// Used to check which queries are disjoint and can run in parallel
128    // This does not have a default body of `{}` because 99% of cases need to add accesses
129    // and forgetting to do so would be unsound.
130    fn update_component_access(state: &Self::State, access: &mut FilteredAccess<ComponentId>);
131
132    /// Creates and initializes a [`State`](WorldQuery::State) for this [`WorldQuery`] type.
133    fn init_state(world: &mut World) -> Self::State;
134
135    /// Attempts to initialize a [`State`](WorldQuery::State) for this [`WorldQuery`] type using read-only
136    /// access to [`Components`].
137    fn get_state(components: &Components) -> Option<Self::State>;
138
139    /// Returns `true` if this query matches a set of components. Otherwise, returns `false`.
140    ///
141    /// Used to check which [`Archetype`]s can be skipped by the query
142    /// (if none of the [`Component`](crate::component::Component)s match)
143    fn matches_component_set(
144        state: &Self::State,
145        set_contains_id: &impl Fn(ComponentId) -> bool,
146    ) -> bool;
147}
148
149macro_rules! impl_tuple_world_query {
150    ($(#[$meta:meta])* $(($name: ident, $state: ident)),*) => {
151
152        #[allow(non_snake_case)]
153        #[allow(clippy::unused_unit)]
154        $(#[$meta])*
155        /// SAFETY:
156        /// `fetch` accesses are the conjunction of the subqueries' accesses
157        /// This is sound because `update_component_access` adds accesses according to the implementations of all the subqueries.
158        /// `update_component_access` adds all `With` and `Without` filters from the subqueries.
159        /// This is sound because `matches_component_set` always returns `false` if any the subqueries' implementations return `false`.
160        unsafe impl<$($name: WorldQuery),*> WorldQuery for ($($name,)*) {
161            type Fetch<'w> = ($($name::Fetch<'w>,)*);
162            type Item<'w> = ($($name::Item<'w>,)*);
163            type State = ($($name::State,)*);
164
165            fn shrink<'wlong: 'wshort, 'wshort>(item: Self::Item<'wlong>) -> Self::Item<'wshort> {
166                let ($($name,)*) = item;
167                ($(
168                    $name::shrink($name),
169                )*)
170            }
171
172            fn shrink_fetch<'wlong: 'wshort, 'wshort>(fetch: Self::Fetch<'wlong>) -> Self::Fetch<'wshort> {
173                let ($($name,)*) = fetch;
174                ($(
175                    $name::shrink_fetch($name),
176                )*)
177            }
178
179            #[inline]
180            #[allow(clippy::unused_unit)]
181            unsafe fn init_fetch<'w>(_world: UnsafeWorldCell<'w>, state: &Self::State, _last_run: Tick, _this_run: Tick) -> Self::Fetch<'w> {
182                let ($($name,)*) = state;
183                // SAFETY: The invariants are uphold by the caller.
184                ($(unsafe { $name::init_fetch(_world, $name, _last_run, _this_run) },)*)
185            }
186
187            const IS_DENSE: bool = true $(&& $name::IS_DENSE)*;
188
189            #[inline]
190            unsafe fn set_archetype<'w>(
191                _fetch: &mut Self::Fetch<'w>,
192                _state: &Self::State,
193                _archetype: &'w Archetype,
194                _table: &'w Table
195            ) {
196                let ($($name,)*) = _fetch;
197                let ($($state,)*) = _state;
198                // SAFETY: The invariants are uphold by the caller.
199                $(unsafe { $name::set_archetype($name, $state, _archetype, _table); })*
200            }
201
202            #[inline]
203            unsafe fn set_table<'w>(_fetch: &mut Self::Fetch<'w>, _state: &Self::State, _table: &'w Table) {
204                let ($($name,)*) = _fetch;
205                let ($($state,)*) = _state;
206                // SAFETY: The invariants are uphold by the caller.
207                $(unsafe { $name::set_table($name, $state, _table); })*
208            }
209
210            #[inline(always)]
211            #[allow(clippy::unused_unit)]
212            unsafe fn fetch<'w>(
213                _fetch: &mut Self::Fetch<'w>,
214                _entity: Entity,
215                _table_row: TableRow
216            ) -> Self::Item<'w> {
217                let ($($name,)*) = _fetch;
218                // SAFETY: The invariants are uphold by the caller.
219                ($(unsafe { $name::fetch($name, _entity, _table_row) },)*)
220            }
221
222            fn update_component_access(state: &Self::State, _access: &mut FilteredAccess<ComponentId>) {
223                let ($($name,)*) = state;
224                $($name::update_component_access($name, _access);)*
225            }
226            #[allow(unused_variables)]
227            fn init_state(world: &mut World) -> Self::State {
228                ($($name::init_state(world),)*)
229            }
230            #[allow(unused_variables)]
231            fn get_state(components: &Components) -> Option<Self::State> {
232                Some(($($name::get_state(components)?,)*))
233            }
234
235            fn matches_component_set(state: &Self::State, _set_contains_id: &impl Fn(ComponentId) -> bool) -> bool {
236                let ($($name,)*) = state;
237                true $(&& $name::matches_component_set($name, _set_contains_id))*
238            }
239        }
240    };
241}
242
243all_tuples!(
244    #[doc(fake_variadic)]
245    impl_tuple_world_query,
246    0,
247    15,
248    F,
249    S
250);