bevy_ecs/query/world_query.rs
1use crate::{
2 archetype::Archetype,
3 component::{ComponentId, Components, Tick},
4 query::FilteredAccess,
5 storage::Table,
6 world::{unsafe_world_cell::UnsafeWorldCell, World},
7};
8use variadics_please::all_tuples;
9
10/// Types that can be used as parameters in a [`Query`].
11/// Types that implement this should also implement either [`QueryData`] or [`QueryFilter`]
12///
13/// # Safety
14///
15/// Implementor must ensure that
16/// [`update_component_access`], [`matches_component_set`], [`QueryData::fetch`], [`QueryFilter::filter_fetch`] and [`init_fetch`]
17/// obey the following:
18///
19/// - For each component mutably accessed by [`QueryData::fetch`], [`update_component_access`] should add write access unless read or write access has already been added, in which case it should panic.
20/// - For each component readonly accessed by [`QueryData::fetch`] or [`QueryFilter::filter_fetch`], [`update_component_access`] should add read access unless write access has already been added, in which case it should panic.
21/// - If `fetch` mutably accesses the same component twice, [`update_component_access`] should panic.
22/// - [`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.
23/// - [`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.
24/// - 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:
25/// - [`matches_component_set`] must be a disjunction of the element's implementations
26/// - [`update_component_access`] must replace the filters with a disjunction of filters
27/// - Each filter in that disjunction must be a conjunction of the corresponding element's filter with the previous `access`
28/// - For each resource readonly accessed by [`init_fetch`], [`update_component_access`] should add read access.
29/// - Mutable resource access is not allowed.
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::fetch`]: crate::query::QueryData::fetch
34/// [`QueryFilter::filter_fetch`]: crate::query::QueryFilter::filter_fetch
35/// [`init_fetch`]: Self::init_fetch
36/// [`matches_component_set`]: Self::matches_component_set
37/// [`Query`]: crate::system::Query
38/// [`update_component_access`]: Self::update_component_access
39/// [`QueryData`]: crate::query::QueryData
40/// [`QueryFilter`]: crate::query::QueryFilter
41pub unsafe trait WorldQuery {
42 /// Per archetype/table state retrieved by this [`WorldQuery`] to compute [`Self::Item`](crate::query::QueryData::Item) for each entity.
43 type Fetch<'a>: Clone;
44
45 /// State used to construct a [`Self::Fetch`](WorldQuery::Fetch). This will be cached inside [`QueryState`](crate::query::QueryState),
46 /// so it is best to move as much data / computation here as possible to reduce the cost of
47 /// constructing [`Self::Fetch`](WorldQuery::Fetch).
48 type State: Send + Sync + Sized;
49
50 /// This function manually implements subtyping for the query fetches.
51 fn shrink_fetch<'wlong: 'wshort, 'wshort>(fetch: Self::Fetch<'wlong>) -> Self::Fetch<'wshort>;
52
53 /// Creates a new instance of [`Self::Fetch`](WorldQuery::Fetch),
54 /// by combining data from the [`World`] with the cached [`Self::State`](WorldQuery::State).
55 /// Readonly accesses resources registered in [`WorldQuery::update_component_access`].
56 ///
57 /// # Safety
58 ///
59 /// - `state` must have been initialized (via [`WorldQuery::init_state`]) using the same `world` passed
60 /// in to this function.
61 /// - `world` must have the **right** to access any access registered in `update_component_access`.
62 /// - There must not be simultaneous resource access conflicting with readonly resource access registered in [`WorldQuery::update_component_access`].
63 unsafe fn init_fetch<'w>(
64 world: UnsafeWorldCell<'w>,
65 state: &Self::State,
66 last_run: Tick,
67 this_run: Tick,
68 ) -> Self::Fetch<'w>;
69
70 /// Returns true if (and only if) every table of every archetype matched by this fetch contains
71 /// all of the matched components.
72 ///
73 /// 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 /// [`QueryData::fetch`](crate::query::QueryData::fetch) can be called for iterators. If this returns false,
76 /// [`WorldQuery::set_archetype`] must be used before [`QueryData::fetch`](crate::query::QueryData::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 /// Adds any component accesses used by this [`WorldQuery`] to `access`.
111 ///
112 /// Used to check which queries are disjoint and can run in parallel
113 // This does not have a default body of `{}` because 99% of cases need to add accesses
114 // and forgetting to do so would be unsound.
115 fn update_component_access(state: &Self::State, access: &mut FilteredAccess<ComponentId>);
116
117 /// Creates and initializes a [`State`](WorldQuery::State) for this [`WorldQuery`] type.
118 fn init_state(world: &mut World) -> Self::State;
119
120 /// Attempts to initialize a [`State`](WorldQuery::State) for this [`WorldQuery`] type using read-only
121 /// access to [`Components`].
122 fn get_state(components: &Components) -> Option<Self::State>;
123
124 /// Returns `true` if this query matches a set of components. Otherwise, returns `false`.
125 ///
126 /// Used to check which [`Archetype`]s can be skipped by the query
127 /// (if none of the [`Component`](crate::component::Component)s match).
128 /// This is how archetypal query filters like `With` work.
129 fn matches_component_set(
130 state: &Self::State,
131 set_contains_id: &impl Fn(ComponentId) -> bool,
132 ) -> bool;
133}
134
135macro_rules! impl_tuple_world_query {
136 ($(#[$meta:meta])* $(($name: ident, $state: ident)),*) => {
137
138 #[expect(
139 clippy::allow_attributes,
140 reason = "This is a tuple-related macro; as such the lints below may not always apply."
141 )]
142 #[allow(
143 non_snake_case,
144 reason = "The names of some variables are provided by the macro's caller, not by us."
145 )]
146 #[allow(
147 unused_variables,
148 reason = "Zero-length tuples won't use any of the parameters."
149 )]
150 #[allow(
151 clippy::unused_unit,
152 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."
153 )]
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 State = ($($name::State,)*);
163
164
165 fn shrink_fetch<'wlong: 'wshort, 'wshort>(fetch: Self::Fetch<'wlong>) -> Self::Fetch<'wshort> {
166 let ($($name,)*) = fetch;
167 ($(
168 $name::shrink_fetch($name),
169 )*)
170 }
171
172 #[inline]
173 unsafe fn init_fetch<'w>(world: UnsafeWorldCell<'w>, state: &Self::State, last_run: Tick, this_run: Tick) -> Self::Fetch<'w> {
174 let ($($name,)*) = state;
175 // SAFETY: The invariants are upheld by the caller.
176 ($(unsafe { $name::init_fetch(world, $name, last_run, this_run) },)*)
177 }
178
179 const IS_DENSE: bool = true $(&& $name::IS_DENSE)*;
180
181 #[inline]
182 unsafe fn set_archetype<'w>(
183 fetch: &mut Self::Fetch<'w>,
184 state: &Self::State,
185 archetype: &'w Archetype,
186 table: &'w Table
187 ) {
188 let ($($name,)*) = fetch;
189 let ($($state,)*) = state;
190 // SAFETY: The invariants are upheld by the caller.
191 $(unsafe { $name::set_archetype($name, $state, archetype, table); })*
192 }
193
194 #[inline]
195 unsafe fn set_table<'w>(fetch: &mut Self::Fetch<'w>, state: &Self::State, table: &'w Table) {
196 let ($($name,)*) = fetch;
197 let ($($state,)*) = state;
198 // SAFETY: The invariants are upheld by the caller.
199 $(unsafe { $name::set_table($name, $state, table); })*
200 }
201
202
203 fn update_component_access(state: &Self::State, access: &mut FilteredAccess<ComponentId>) {
204 let ($($name,)*) = state;
205 $($name::update_component_access($name, access);)*
206 }
207 fn init_state(world: &mut World) -> Self::State {
208 ($($name::init_state(world),)*)
209 }
210 fn get_state(components: &Components) -> Option<Self::State> {
211 Some(($($name::get_state(components)?,)*))
212 }
213
214 fn matches_component_set(state: &Self::State, set_contains_id: &impl Fn(ComponentId) -> bool) -> bool {
215 let ($($name,)*) = state;
216 true $(&& $name::matches_component_set($name, set_contains_id))*
217 }
218 }
219 };
220}
221
222all_tuples!(
223 #[doc(fake_variadic)]
224 impl_tuple_world_query,
225 0,
226 15,
227 F,
228 S
229);