bevy_ecs/query/
world_query.rs

1use crate::{
2    archetype::Archetype,
3    change_detection::Tick,
4    component::{ComponentId, Components},
5    query::FilteredAccess,
6    storage::Table,
7    world::{unsafe_world_cell::UnsafeWorldCell, World},
8};
9use variadics_please::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`], [`QueryData::provide_extra_access`], [`matches_component_set`], [`QueryData::fetch`], [`QueryFilter::filter_fetch`] and [`init_fetch`]
18/// obey the following:
19///
20/// - 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.
21/// - 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.
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/// - For each resource readonly accessed by [`init_fetch`], [`update_component_access`] should add read access.
30/// - Mutable resource access is not allowed.
31/// - Any access added during [`QueryData::provide_extra_access`] must be a subset of `available_access`, and must not conflict with any access in `access`.
32///
33/// 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.
34///
35/// [`QueryData::provide_extra_access`]: crate::query::QueryData::provide_extra_access
36/// [`QueryData::fetch`]: crate::query::QueryData::fetch
37/// [`QueryFilter::filter_fetch`]: crate::query::QueryFilter::filter_fetch
38/// [`init_fetch`]: Self::init_fetch
39/// [`matches_component_set`]: Self::matches_component_set
40/// [`Query`]: crate::system::Query
41/// [`update_component_access`]: Self::update_component_access
42/// [`QueryData`]: crate::query::QueryData
43/// [`QueryFilter`]: crate::query::QueryFilter
44pub unsafe trait WorldQuery {
45    /// Per archetype/table state retrieved by this [`WorldQuery`] to compute [`Self::Item`](crate::query::QueryData::Item) for each entity.
46    type Fetch<'w>: 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 fetches.
54    fn shrink_fetch<'wlong: 'wshort, 'wshort>(fetch: Self::Fetch<'wlong>) -> Self::Fetch<'wshort>;
55
56    /// Creates a new instance of [`Self::Fetch`](WorldQuery::Fetch),
57    /// by combining data from the [`World`] with the cached [`Self::State`](WorldQuery::State).
58    /// Readonly accesses resources registered in [`WorldQuery::update_component_access`].
59    ///
60    /// # Safety
61    ///
62    /// - `state` must have been initialized (via [`WorldQuery::init_state`]) using the same `world` passed
63    ///   in to this function.
64    /// - `world` must have the **right** to access any access registered in `update_component_access`.
65    /// - There must not be simultaneous resource access conflicting with readonly resource access registered in [`WorldQuery::update_component_access`].
66    unsafe fn init_fetch<'w, 's>(
67        world: UnsafeWorldCell<'w>,
68        state: &'s Self::State,
69        last_run: Tick,
70        this_run: Tick,
71    ) -> Self::Fetch<'w>;
72
73    /// Returns true if (and only if) every table of every archetype matched by this fetch contains
74    /// all of the matched components.
75    ///
76    /// This is used to select a more efficient "table iterator"
77    /// for "dense" queries. If this returns true, [`WorldQuery::set_table`] must be used before
78    /// [`QueryData::fetch`](crate::query::QueryData::fetch) can be called for iterators. If this returns false,
79    /// [`WorldQuery::set_archetype`] must be used before [`QueryData::fetch`](crate::query::QueryData::fetch) can be called for
80    /// iterators.
81    const IS_DENSE: bool;
82
83    /// Adjusts internal state to account for the next [`Archetype`]. This will always be called on
84    /// archetypes that match this [`WorldQuery`].
85    ///
86    /// # Safety
87    ///
88    /// - `archetype` and `tables` must be from the same [`World`] that [`WorldQuery::init_state`] was called on.
89    /// - `table` must correspond to `archetype`.
90    /// - `state` must be the [`State`](Self::State) that `fetch` was initialized with.
91    unsafe fn set_archetype<'w, 's>(
92        fetch: &mut Self::Fetch<'w>,
93        state: &'s Self::State,
94        archetype: &'w Archetype,
95        table: &'w Table,
96    );
97
98    /// Adjusts internal state to account for the next [`Table`]. This will always be called on tables
99    /// that match this [`WorldQuery`].
100    ///
101    /// # Safety
102    ///
103    /// - `table` must be from the same [`World`] that [`WorldQuery::init_state`] was called on.
104    /// - `state` must be the [`State`](Self::State) that `fetch` was initialized with.
105    unsafe fn set_table<'w, 's>(
106        fetch: &mut Self::Fetch<'w>,
107        state: &'s Self::State,
108        table: &'w Table,
109    );
110
111    /// Adds any component accesses used by this [`WorldQuery`] to `access`.
112    ///
113    /// Used to check which queries are disjoint and can run in parallel
114    // This does not have a default body of `{}` because 99% of cases need to add accesses
115    // and forgetting to do so would be unsound.
116    fn update_component_access(state: &Self::State, access: &mut FilteredAccess);
117
118    /// Creates and initializes a [`State`](WorldQuery::State) for this [`WorldQuery`] type.
119    fn init_state(world: &mut World) -> Self::State;
120
121    /// Attempts to initialize a [`State`](WorldQuery::State) for this [`WorldQuery`] type using read-only
122    /// access to [`Components`].
123    fn get_state(components: &Components) -> Option<Self::State>;
124
125    /// Returns `true` if this query matches a set of components. Otherwise, returns `false`.
126    ///
127    /// Used to check which [`Archetype`]s can be skipped by the query
128    /// (if none of the [`Component`](crate::component::Component)s match).
129    /// This is how archetypal query filters like `With` work.
130    fn matches_component_set(
131        state: &Self::State,
132        set_contains_id: &impl Fn(ComponentId) -> bool,
133    ) -> bool;
134}
135
136macro_rules! impl_tuple_world_query {
137    ($(#[$meta:meta])* $(($name: ident, $state: ident)),*) => {
138
139        #[expect(
140            clippy::allow_attributes,
141            reason = "This is a tuple-related macro; as such the lints below may not always apply."
142        )]
143        #[allow(
144            non_snake_case,
145            reason = "The names of some variables are provided by the macro's caller, not by us."
146        )]
147        #[allow(
148            unused_variables,
149            reason = "Zero-length tuples won't use any of the parameters."
150        )]
151        #[allow(
152            clippy::unused_unit,
153            reason = "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."
154        )]
155        $(#[$meta])*
156        /// SAFETY:
157        /// `fetch` accesses are the conjunction of the subqueries' accesses
158        /// This is sound because `update_component_access` adds accesses according to the implementations of all the subqueries.
159        /// `update_component_access` adds all `With` and `Without` filters from the subqueries.
160        /// This is sound because `matches_component_set` always returns `false` if any the subqueries' implementations return `false`.
161        unsafe impl<$($name: WorldQuery),*> WorldQuery for ($($name,)*) {
162            type Fetch<'w> = ($($name::Fetch<'w>,)*);
163            type State = ($($name::State,)*);
164
165
166            fn shrink_fetch<'wlong: 'wshort, 'wshort>(fetch: Self::Fetch<'wlong>) -> Self::Fetch<'wshort> {
167                let ($($name,)*) = fetch;
168                ($(
169                    $name::shrink_fetch($name),
170                )*)
171            }
172
173            #[inline]
174            unsafe fn init_fetch<'w, 's>(world: UnsafeWorldCell<'w>, state: &'s Self::State, last_run: Tick, this_run: Tick) -> Self::Fetch<'w> {
175                let ($($name,)*) = state;
176                // SAFETY: The invariants are upheld by the caller.
177                ($(unsafe { $name::init_fetch(world, $name, last_run, this_run) },)*)
178            }
179
180            const IS_DENSE: bool = true $(&& $name::IS_DENSE)*;
181
182            #[inline]
183            unsafe fn set_archetype<'w, 's>(
184                fetch: &mut Self::Fetch<'w>,
185                state: &'s Self::State,
186                archetype: &'w Archetype,
187                table: &'w Table
188            ) {
189                let ($($name,)*) = fetch;
190                let ($($state,)*) = state;
191                // SAFETY: The invariants are upheld by the caller.
192                $(unsafe { $name::set_archetype($name, $state, archetype, table); })*
193            }
194
195            #[inline]
196            unsafe fn set_table<'w, 's>(fetch: &mut Self::Fetch<'w>, state: &'s Self::State, table: &'w Table) {
197                let ($($name,)*) = fetch;
198                let ($($state,)*) = state;
199                // SAFETY: The invariants are upheld by the caller.
200                $(unsafe { $name::set_table($name, $state, table); })*
201            }
202
203
204            fn update_component_access(state: &Self::State, access: &mut FilteredAccess) {
205                let ($($name,)*) = state;
206                $($name::update_component_access($name, access);)*
207            }
208            fn init_state(world: &mut World) -> Self::State {
209                ($($name::init_state(world),)*)
210            }
211            fn get_state(components: &Components) -> Option<Self::State> {
212                Some(($($name::get_state(components)?,)*))
213            }
214
215            fn matches_component_set(state: &Self::State, set_contains_id: &impl Fn(ComponentId) -> bool) -> bool {
216                let ($($name,)*) = state;
217                true $(&& $name::matches_component_set($name, set_contains_id))*
218            }
219        }
220    };
221}
222
223all_tuples!(
224    #[doc(fake_variadic)]
225    impl_tuple_world_query,
226    0,
227    15,
228    F,
229    S
230);