bevy_ecs/query/world_query.rs
1use crate::{
2 archetype::Archetype,
3 change_detection::Tick,
4 component::{ComponentId, Components},
5 query::{FilteredAccess, FilteredAccessSet},
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 [`WorldQuery::update_component_access`]
65 /// or [`WorldQuery::init_nested_access`].
66 /// - [`WorldQuery::update_component_access`] must not request conflicting access.
67 /// If `Self` is `ReadOnlyQueryData` or `QueryFilter`, the access is read-only and can never conflict.
68 /// Otherwise, [`WorldQuery::update_component_access`] must be called to ensure it does not panic.
69 /// - [`WorldQuery::init_nested_access`] must not request conflicting access.
70 /// If `Self` is [`ReadOnlyQueryData`](crate::query::ReadOnlyQueryData) or [`QueryFilter`](crate::query::QueryFilter), the access is read-only and can never conflict.
71 /// If `Self` is [`SingleEntityQueryData`](crate::query::SingleEntityQueryData), there is no external access and it cannot conflict.
72 /// Otherwise, [`WorldQuery::init_nested_access`] must be called to ensure it does not panic.
73 unsafe fn init_fetch<'w, 's>(
74 world: UnsafeWorldCell<'w>,
75 state: &'s Self::State,
76 last_run: Tick,
77 this_run: Tick,
78 ) -> Self::Fetch<'w>;
79
80 /// Returns true if (and only if) every table of every archetype matched by this fetch contains
81 /// all of the matched components.
82 ///
83 /// This is used to select a more efficient "table iterator"
84 /// for "dense" queries. If this returns true, [`WorldQuery::set_table`] must be used before
85 /// [`QueryData::fetch`](crate::query::QueryData::fetch) can be called for iterators. If this returns false,
86 /// [`WorldQuery::set_archetype`] must be used before [`QueryData::fetch`](crate::query::QueryData::fetch) can be called for
87 /// iterators.
88 const IS_DENSE: bool;
89
90 /// Adjusts internal state to account for the next [`Archetype`]. This will always be called on
91 /// archetypes that match this [`WorldQuery`].
92 ///
93 /// # Safety
94 ///
95 /// - `archetype` and `tables` must be from the same [`World`] that [`WorldQuery::init_state`] was called on.
96 /// - `table` must correspond to `archetype`.
97 /// - `state` must be the [`State`](Self::State) that `fetch` was initialized with.
98 unsafe fn set_archetype<'w, 's>(
99 fetch: &mut Self::Fetch<'w>,
100 state: &'s Self::State,
101 archetype: &'w Archetype,
102 table: &'w Table,
103 );
104
105 /// Adjusts internal state to account for the next [`Table`]. This will always be called on tables
106 /// that match this [`WorldQuery`].
107 ///
108 /// # Safety
109 ///
110 /// - `table` must be from the same [`World`] that [`WorldQuery::init_state`] was called on.
111 /// - `state` must be the [`State`](Self::State) that `fetch` was initialized with.
112 unsafe fn set_table<'w, 's>(
113 fetch: &mut Self::Fetch<'w>,
114 state: &'s Self::State,
115 table: &'w Table,
116 );
117
118 /// Adds any component accesses to the current entity used by this [`WorldQuery`] to `access`.
119 ///
120 /// Used to check which queries are disjoint and can run in parallel
121 // This does not have a default body of `{}` because 99% of cases need to add accesses
122 // and forgetting to do so would be unsound.
123 fn update_component_access(state: &Self::State, access: &mut FilteredAccess);
124
125 /// Adds any component accesses to other entities used by this [`WorldQuery`].
126 ///
127 /// This method must panic if the access would conflict with any existing access in the [`FilteredAccessSet`].
128 ///
129 /// This is used for queries to request access to entities other than the current one,
130 /// such as to read resources or to follow relations.
131 fn init_nested_access(
132 _state: &Self::State,
133 _system_name: Option<&str>,
134 _component_access_set: &mut FilteredAccessSet,
135 _world: UnsafeWorldCell,
136 ) {
137 }
138
139 /// Creates and initializes a [`State`](WorldQuery::State) for this [`WorldQuery`] type.
140 fn init_state(world: &mut World) -> Self::State;
141
142 /// Attempts to initialize a [`State`](WorldQuery::State) for this [`WorldQuery`] type using read-only
143 /// access to [`Components`].
144 fn get_state(components: &Components) -> Option<Self::State>;
145
146 /// Returns `true` if this query matches a set of components. Otherwise, returns `false`.
147 ///
148 /// Used to check which [`Archetype`]s can be skipped by the query
149 /// (if none of the [`Component`](crate::component::Component)s match).
150 /// This is how archetypal query filters like `With` work.
151 fn matches_component_set(
152 state: &Self::State,
153 set_contains_id: &impl Fn(ComponentId) -> bool,
154 ) -> bool;
155
156 /// Called when the query state is updating its archetype cache.
157 /// This can be used by nested queries to update their internal archetype caches.
158 fn update_archetypes(_state: &mut Self::State, _world: UnsafeWorldCell) {}
159}
160
161macro_rules! impl_tuple_world_query {
162 ($(#[$meta:meta])* $(($name: ident, $state: ident)),*) => {
163
164 #[expect(
165 clippy::allow_attributes,
166 reason = "This is a tuple-related macro; as such the lints below may not always apply."
167 )]
168 #[allow(
169 non_snake_case,
170 reason = "The names of some variables are provided by the macro's caller, not by us."
171 )]
172 #[allow(
173 unused_variables,
174 reason = "Zero-length tuples won't use any of the parameters."
175 )]
176 #[allow(
177 clippy::unused_unit,
178 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."
179 )]
180 $(#[$meta])*
181 // SAFETY:
182 // `fetch` accesses are the conjunction of the subqueries' accesses
183 // This is sound because `update_component_access` adds accesses according to the implementations of all the subqueries.
184 // `update_component_access` adds all `With` and `Without` filters from the subqueries.
185 // This is sound because `matches_component_set` always returns `false` if any the subqueries' implementations return `false`.
186 unsafe impl<$($name: WorldQuery),*> WorldQuery for ($($name,)*) {
187 type Fetch<'w> = ($($name::Fetch<'w>,)*);
188 type State = ($($name::State,)*);
189
190
191 fn shrink_fetch<'wlong: 'wshort, 'wshort>(fetch: Self::Fetch<'wlong>) -> Self::Fetch<'wshort> {
192 let ($($name,)*) = fetch;
193 ($(
194 $name::shrink_fetch($name),
195 )*)
196 }
197
198 #[inline]
199 unsafe fn init_fetch<'w, 's>(world: UnsafeWorldCell<'w>, state: &'s Self::State, last_run: Tick, this_run: Tick) -> Self::Fetch<'w> {
200 let ($($name,)*) = state;
201 // SAFETY: The invariants are upheld by the caller.
202 ($(unsafe { $name::init_fetch(world, $name, last_run, this_run) },)*)
203 }
204
205 const IS_DENSE: bool = true $(&& $name::IS_DENSE)*;
206
207 #[inline]
208 unsafe fn set_archetype<'w, 's>(
209 fetch: &mut Self::Fetch<'w>,
210 state: &'s Self::State,
211 archetype: &'w Archetype,
212 table: &'w Table
213 ) {
214 let ($($name,)*) = fetch;
215 let ($($state,)*) = state;
216 // SAFETY: The invariants are upheld by the caller.
217 $(unsafe { $name::set_archetype($name, $state, archetype, table); })*
218 }
219
220 #[inline]
221 unsafe fn set_table<'w, 's>(fetch: &mut Self::Fetch<'w>, state: &'s Self::State, table: &'w Table) {
222 let ($($name,)*) = fetch;
223 let ($($state,)*) = state;
224 // SAFETY: The invariants are upheld by the caller.
225 $(unsafe { $name::set_table($name, $state, table); })*
226 }
227
228
229 fn update_component_access(state: &Self::State, access: &mut FilteredAccess) {
230 let ($($name,)*) = state;
231 $($name::update_component_access($name, access);)*
232 }
233
234 fn init_nested_access(
235 state: &Self::State,
236 _system_name: Option<&str>,
237 _component_access_set: &mut FilteredAccessSet,
238 _world: UnsafeWorldCell,
239 ) {
240 let ($($state,)*) = state;
241 $($name::init_nested_access($state, _system_name, _component_access_set, _world);)*
242 }
243
244 fn init_state(world: &mut World) -> Self::State {
245 ($($name::init_state(world),)*)
246 }
247 fn get_state(components: &Components) -> Option<Self::State> {
248 Some(($($name::get_state(components)?,)*))
249 }
250
251 fn matches_component_set(state: &Self::State, set_contains_id: &impl Fn(ComponentId) -> bool) -> bool {
252 let ($($name,)*) = state;
253 true $(&& $name::matches_component_set($name, set_contains_id))*
254 }
255
256 fn update_archetypes(state: &mut Self::State, _world: UnsafeWorldCell) {
257 let ($($name,)*) = state;
258 $($name::update_archetypes($name, _world);)*
259 }
260 }
261 };
262}
263
264all_tuples!(
265 #[doc(fake_variadic)]
266 impl_tuple_world_query,
267 0,
268 15,
269 F,
270 S
271);