Improve docs for WorldQuery
(#17654)
# Objective While working on #17649, I found the docs for `WorldQuery` and the related traits frustratingly vague. ## Solution Clarify them and add some more tangible advice. Also fix a copy-pasted typo in related comments. --------- Co-authored-by: James O'Brien <james.obrien@drafly.net>
This commit is contained in:
parent
29d0ef6f3a
commit
0ca9d6968a
@ -1760,7 +1760,7 @@ unsafe impl<T: WorldQuery> WorldQuery for Option<T> {
|
|||||||
this_run: Tick,
|
this_run: Tick,
|
||||||
) -> OptionFetch<'w, T> {
|
) -> OptionFetch<'w, T> {
|
||||||
OptionFetch {
|
OptionFetch {
|
||||||
// SAFETY: The invariants are uphold by the caller.
|
// SAFETY: The invariants are upheld by the caller.
|
||||||
fetch: unsafe { T::init_fetch(world, state, last_run, this_run) },
|
fetch: unsafe { T::init_fetch(world, state, last_run, this_run) },
|
||||||
matches: false,
|
matches: false,
|
||||||
}
|
}
|
||||||
@ -1777,7 +1777,7 @@ unsafe impl<T: WorldQuery> WorldQuery for Option<T> {
|
|||||||
) {
|
) {
|
||||||
fetch.matches = T::matches_component_set(state, &|id| archetype.contains(id));
|
fetch.matches = T::matches_component_set(state, &|id| archetype.contains(id));
|
||||||
if fetch.matches {
|
if fetch.matches {
|
||||||
// SAFETY: The invariants are uphold by the caller.
|
// SAFETY: The invariants are upheld by the caller.
|
||||||
unsafe {
|
unsafe {
|
||||||
T::set_archetype(&mut fetch.fetch, state, archetype, table);
|
T::set_archetype(&mut fetch.fetch, state, archetype, table);
|
||||||
}
|
}
|
||||||
@ -1788,7 +1788,7 @@ unsafe impl<T: WorldQuery> WorldQuery for Option<T> {
|
|||||||
unsafe fn set_table<'w>(fetch: &mut OptionFetch<'w, T>, state: &T::State, table: &'w Table) {
|
unsafe fn set_table<'w>(fetch: &mut OptionFetch<'w, T>, state: &T::State, table: &'w Table) {
|
||||||
fetch.matches = T::matches_component_set(state, &|id| table.has_column(id));
|
fetch.matches = T::matches_component_set(state, &|id| table.has_column(id));
|
||||||
if fetch.matches {
|
if fetch.matches {
|
||||||
// SAFETY: The invariants are uphold by the caller.
|
// SAFETY: The invariants are upheld by the caller.
|
||||||
unsafe {
|
unsafe {
|
||||||
T::set_table(&mut fetch.fetch, state, table);
|
T::set_table(&mut fetch.fetch, state, table);
|
||||||
}
|
}
|
||||||
@ -1803,7 +1803,7 @@ unsafe impl<T: WorldQuery> WorldQuery for Option<T> {
|
|||||||
) -> Self::Item<'w> {
|
) -> Self::Item<'w> {
|
||||||
fetch
|
fetch
|
||||||
.matches
|
.matches
|
||||||
// SAFETY: The invariants are uphold by the caller.
|
// SAFETY: The invariants are upheld by the caller.
|
||||||
.then(|| unsafe { T::fetch(&mut fetch.fetch, entity, table_row) })
|
.then(|| unsafe { T::fetch(&mut fetch.fetch, entity, table_row) })
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2073,7 +2073,7 @@ macro_rules! impl_anytuple_fetch {
|
|||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn init_fetch<'w>(_world: UnsafeWorldCell<'w>, state: &Self::State, _last_run: Tick, _this_run: Tick) -> Self::Fetch<'w> {
|
unsafe fn init_fetch<'w>(_world: UnsafeWorldCell<'w>, state: &Self::State, _last_run: Tick, _this_run: Tick) -> Self::Fetch<'w> {
|
||||||
let ($($name,)*) = state;
|
let ($($name,)*) = state;
|
||||||
// SAFETY: The invariants are uphold by the caller.
|
// SAFETY: The invariants are upheld by the caller.
|
||||||
($(( unsafe { $name::init_fetch(_world, $name, _last_run, _this_run) }, false),)*)
|
($(( unsafe { $name::init_fetch(_world, $name, _last_run, _this_run) }, false),)*)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2091,7 +2091,7 @@ macro_rules! impl_anytuple_fetch {
|
|||||||
$(
|
$(
|
||||||
$name.1 = $name::matches_component_set($state, &|id| _archetype.contains(id));
|
$name.1 = $name::matches_component_set($state, &|id| _archetype.contains(id));
|
||||||
if $name.1 {
|
if $name.1 {
|
||||||
// SAFETY: The invariants are uphold by the caller.
|
// SAFETY: The invariants are upheld by the caller.
|
||||||
unsafe { $name::set_archetype(&mut $name.0, $state, _archetype, _table); }
|
unsafe { $name::set_archetype(&mut $name.0, $state, _archetype, _table); }
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
|
@ -86,6 +86,8 @@ pub unsafe trait QueryFilter: WorldQuery {
|
|||||||
///
|
///
|
||||||
/// This enables optimizations for [`crate::query::QueryIter`] that rely on knowing exactly how
|
/// This enables optimizations for [`crate::query::QueryIter`] that rely on knowing exactly how
|
||||||
/// many elements are being iterated (such as `Iterator::collect()`).
|
/// many elements are being iterated (such as `Iterator::collect()`).
|
||||||
|
///
|
||||||
|
/// If this is `true`, then [`QueryFilter::filter_fetch`] must always return true.
|
||||||
const IS_ARCHETYPAL: bool;
|
const IS_ARCHETYPAL: bool;
|
||||||
|
|
||||||
/// Returns true if the provided [`Entity`] and [`TableRow`] should be included in the query results.
|
/// Returns true if the provided [`Entity`] and [`TableRow`] should be included in the query results.
|
||||||
@ -94,6 +96,9 @@ pub unsafe trait QueryFilter: WorldQuery {
|
|||||||
/// Note that this is called after already restricting the matched [`Table`]s and [`Archetype`]s to the
|
/// Note that this is called after already restricting the matched [`Table`]s and [`Archetype`]s to the
|
||||||
/// ones that are compatible with the Filter's access.
|
/// ones that are compatible with the Filter's access.
|
||||||
///
|
///
|
||||||
|
/// Implementors of this method will generally either have a trivial `true` body (required for archetypal filters),
|
||||||
|
/// or call [`WorldQuery::fetch`] to access the raw data needed to make the final decision on filter inclusion.
|
||||||
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// Must always be called _after_ [`WorldQuery::set_table`] or [`WorldQuery::set_archetype`]. `entity` and
|
/// Must always be called _after_ [`WorldQuery::set_table`] or [`WorldQuery::set_archetype`]. `entity` and
|
||||||
@ -426,7 +431,7 @@ macro_rules! impl_or_query_filter {
|
|||||||
unsafe fn init_fetch<'w>(world: UnsafeWorldCell<'w>, state: &Self::State, last_run: Tick, this_run: Tick) -> Self::Fetch<'w> {
|
unsafe fn init_fetch<'w>(world: UnsafeWorldCell<'w>, state: &Self::State, last_run: Tick, this_run: Tick) -> Self::Fetch<'w> {
|
||||||
let ($($filter,)*) = state;
|
let ($($filter,)*) = state;
|
||||||
($(OrFetch {
|
($(OrFetch {
|
||||||
// SAFETY: The invariants are uphold by the caller.
|
// SAFETY: The invariants are upheld by the caller.
|
||||||
fetch: unsafe { $filter::init_fetch(world, $filter, last_run, this_run) },
|
fetch: unsafe { $filter::init_fetch(world, $filter, last_run, this_run) },
|
||||||
matches: false,
|
matches: false,
|
||||||
},)*)
|
},)*)
|
||||||
@ -439,7 +444,7 @@ macro_rules! impl_or_query_filter {
|
|||||||
$(
|
$(
|
||||||
$filter.matches = $filter::matches_component_set($state, &|id| table.has_column(id));
|
$filter.matches = $filter::matches_component_set($state, &|id| table.has_column(id));
|
||||||
if $filter.matches {
|
if $filter.matches {
|
||||||
// SAFETY: The invariants are uphold by the caller.
|
// SAFETY: The invariants are upheld by the caller.
|
||||||
unsafe { $filter::set_table(&mut $filter.fetch, $state, table); }
|
unsafe { $filter::set_table(&mut $filter.fetch, $state, table); }
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
@ -457,7 +462,7 @@ macro_rules! impl_or_query_filter {
|
|||||||
$(
|
$(
|
||||||
$filter.matches = $filter::matches_component_set($state, &|id| archetype.contains(id));
|
$filter.matches = $filter::matches_component_set($state, &|id| archetype.contains(id));
|
||||||
if $filter.matches {
|
if $filter.matches {
|
||||||
// SAFETY: The invariants are uphold by the caller.
|
// SAFETY: The invariants are upheld by the caller.
|
||||||
unsafe { $filter::set_archetype(&mut $filter.fetch, $state, archetype, table); }
|
unsafe { $filter::set_archetype(&mut $filter.fetch, $state, archetype, table); }
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
@ -470,7 +475,7 @@ macro_rules! impl_or_query_filter {
|
|||||||
table_row: TableRow
|
table_row: TableRow
|
||||||
) -> Self::Item<'w> {
|
) -> Self::Item<'w> {
|
||||||
let ($($filter,)*) = fetch;
|
let ($($filter,)*) = fetch;
|
||||||
// SAFETY: The invariants are uphold by the caller.
|
// SAFETY: The invariants are upheld by the caller.
|
||||||
false $(|| ($filter.matches && unsafe { $filter::filter_fetch(&mut $filter.fetch, entity, table_row) }))*
|
false $(|| ($filter.matches && unsafe { $filter::filter_fetch(&mut $filter.fetch, entity, table_row) }))*
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -521,7 +526,7 @@ macro_rules! impl_or_query_filter {
|
|||||||
entity: Entity,
|
entity: Entity,
|
||||||
table_row: TableRow
|
table_row: TableRow
|
||||||
) -> bool {
|
) -> bool {
|
||||||
// SAFETY: The invariants are uphold by the caller.
|
// SAFETY: The invariants are upheld by the caller.
|
||||||
unsafe { Self::fetch(fetch, entity, table_row) }
|
unsafe { Self::fetch(fetch, entity, table_row) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -554,7 +559,7 @@ macro_rules! impl_tuple_query_filter {
|
|||||||
table_row: TableRow
|
table_row: TableRow
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let ($($name,)*) = fetch;
|
let ($($name,)*) = fetch;
|
||||||
// SAFETY: The invariants are uphold by the caller.
|
// SAFETY: The invariants are upheld by the caller.
|
||||||
true $(&& unsafe { $name::filter_fetch($name, entity, table_row) })*
|
true $(&& unsafe { $name::filter_fetch($name, entity, table_row) })*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -805,7 +810,7 @@ unsafe impl<T: Component> QueryFilter for Added<T> {
|
|||||||
entity: Entity,
|
entity: Entity,
|
||||||
table_row: TableRow,
|
table_row: TableRow,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
// SAFETY: The invariants are uphold by the caller.
|
// SAFETY: The invariants are upheld by the caller.
|
||||||
unsafe { Self::fetch(fetch, entity, table_row) }
|
unsafe { Self::fetch(fetch, entity, table_row) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1039,7 +1044,7 @@ unsafe impl<T: Component> QueryFilter for Changed<T> {
|
|||||||
entity: Entity,
|
entity: Entity,
|
||||||
table_row: TableRow,
|
table_row: TableRow,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
// SAFETY: The invariants are uphold by the caller.
|
// SAFETY: The invariants are upheld by the caller.
|
||||||
unsafe { Self::fetch(fetch, entity, table_row) }
|
unsafe { Self::fetch(fetch, entity, table_row) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIter<'w, 's, D, F> {
|
|||||||
// SAFETY: We only access table data that has been registered in `query_state`.
|
// SAFETY: We only access table data that has been registered in `query_state`.
|
||||||
tables: unsafe { &world.storages().tables },
|
tables: unsafe { &world.storages().tables },
|
||||||
archetypes: world.archetypes(),
|
archetypes: world.archetypes(),
|
||||||
// SAFETY: The invariants are uphold by the caller.
|
// SAFETY: The invariants are upheld by the caller.
|
||||||
cursor: unsafe { QueryIterationCursor::init(world, query_state, last_run, this_run) },
|
cursor: unsafe { QueryIterationCursor::init(world, query_state, last_run, this_run) },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,12 +40,18 @@ use variadics_please::all_tuples;
|
|||||||
/// [`QueryFilter`]: crate::query::QueryFilter
|
/// [`QueryFilter`]: crate::query::QueryFilter
|
||||||
pub unsafe trait WorldQuery {
|
pub unsafe trait WorldQuery {
|
||||||
/// The item returned by this [`WorldQuery`]
|
/// The item returned by this [`WorldQuery`]
|
||||||
/// For `QueryData` this will be the item returned by the query.
|
/// For `QueryData` this will be the data retrieved by the query,
|
||||||
|
/// and is visible to the end user when calling e.g. `Query<Self>::get`.
|
||||||
|
///
|
||||||
/// For `QueryFilter` this will be either `()`, or a `bool` indicating whether the entity should be included
|
/// For `QueryFilter` this will be either `()`, or a `bool` indicating whether the entity should be included
|
||||||
/// or a tuple of such things.
|
/// or a tuple of such things.
|
||||||
|
/// Archetypal query filters (like `With`) set this to `()`,
|
||||||
|
/// as the filtering is done by selecting the archetypes to iterate over via [`WorldQuery::matches_component_set`],
|
||||||
|
/// while non-archetypal query filters (like `Changed`) set this to a `bool` and evaluate the filter for each entity,
|
||||||
|
/// after the set of possible archetypes has been narrowed down.
|
||||||
type Item<'a>;
|
type Item<'a>;
|
||||||
|
|
||||||
/// Per archetype/table state used by this [`WorldQuery`] to fetch [`Self::Item`](WorldQuery::Item)
|
/// Per archetype/table state retrieved by this [`WorldQuery`] to compute [`Self::Item`](WorldQuery::Item) for each entity.
|
||||||
type Fetch<'a>: Clone;
|
type Fetch<'a>: Clone;
|
||||||
|
|
||||||
/// State used to construct a [`Self::Fetch`](WorldQuery::Fetch). This will be cached inside [`QueryState`](crate::query::QueryState),
|
/// State used to construct a [`Self::Fetch`](WorldQuery::Fetch). This will be cached inside [`QueryState`](crate::query::QueryState),
|
||||||
@ -59,7 +65,8 @@ pub unsafe trait WorldQuery {
|
|||||||
/// This function manually implements subtyping for the query fetches.
|
/// This function manually implements subtyping for the query fetches.
|
||||||
fn shrink_fetch<'wlong: 'wshort, 'wshort>(fetch: Self::Fetch<'wlong>) -> Self::Fetch<'wshort>;
|
fn shrink_fetch<'wlong: 'wshort, 'wshort>(fetch: Self::Fetch<'wlong>) -> Self::Fetch<'wshort>;
|
||||||
|
|
||||||
/// Creates a new instance of this fetch.
|
/// Creates a new instance of [`Self::Fetch`](WorldQuery::Fetch),
|
||||||
|
/// by combining data from the [`World`] with the cached [`Self::State`](WorldQuery::State).
|
||||||
/// Readonly accesses resources registered in [`WorldQuery::update_component_access`].
|
/// Readonly accesses resources registered in [`WorldQuery::update_component_access`].
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
@ -76,7 +83,9 @@ pub unsafe trait WorldQuery {
|
|||||||
) -> Self::Fetch<'w>;
|
) -> Self::Fetch<'w>;
|
||||||
|
|
||||||
/// Returns true if (and only if) every table of every archetype matched by this fetch contains
|
/// Returns true if (and only if) every table of every archetype matched by this fetch contains
|
||||||
/// all of the matched components. This is used to select a more efficient "table iterator"
|
/// all of the matched components.
|
||||||
|
///
|
||||||
|
/// This is used to select a more efficient "table iterator"
|
||||||
/// for "dense" queries. If this returns true, [`WorldQuery::set_table`] must be used before
|
/// for "dense" queries. If this returns true, [`WorldQuery::set_table`] must be used before
|
||||||
/// [`WorldQuery::fetch`] can be called for iterators. If this returns false,
|
/// [`WorldQuery::fetch`] can be called for iterators. If this returns false,
|
||||||
/// [`WorldQuery::set_archetype`] must be used before [`WorldQuery::fetch`] can be called for
|
/// [`WorldQuery::set_archetype`] must be used before [`WorldQuery::fetch`] can be called for
|
||||||
@ -147,7 +156,8 @@ pub unsafe trait WorldQuery {
|
|||||||
/// Returns `true` if this query matches a set of components. Otherwise, returns `false`.
|
/// Returns `true` if this query matches a set of components. Otherwise, returns `false`.
|
||||||
///
|
///
|
||||||
/// Used to check which [`Archetype`]s can be skipped by the query
|
/// Used to check which [`Archetype`]s can be skipped by the query
|
||||||
/// (if none of the [`Component`](crate::component::Component)s match)
|
/// (if none of the [`Component`](crate::component::Component)s match).
|
||||||
|
/// This is how archetypal query filters like `With` work.
|
||||||
fn matches_component_set(
|
fn matches_component_set(
|
||||||
state: &Self::State,
|
state: &Self::State,
|
||||||
set_contains_id: &impl Fn(ComponentId) -> bool,
|
set_contains_id: &impl Fn(ComponentId) -> bool,
|
||||||
@ -201,7 +211,7 @@ macro_rules! impl_tuple_world_query {
|
|||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn init_fetch<'w>(world: UnsafeWorldCell<'w>, state: &Self::State, last_run: Tick, this_run: Tick) -> Self::Fetch<'w> {
|
unsafe fn init_fetch<'w>(world: UnsafeWorldCell<'w>, state: &Self::State, last_run: Tick, this_run: Tick) -> Self::Fetch<'w> {
|
||||||
let ($($name,)*) = state;
|
let ($($name,)*) = state;
|
||||||
// SAFETY: The invariants are uphold by the caller.
|
// SAFETY: The invariants are upheld by the caller.
|
||||||
($(unsafe { $name::init_fetch(world, $name, last_run, this_run) },)*)
|
($(unsafe { $name::init_fetch(world, $name, last_run, this_run) },)*)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -216,7 +226,7 @@ macro_rules! impl_tuple_world_query {
|
|||||||
) {
|
) {
|
||||||
let ($($name,)*) = fetch;
|
let ($($name,)*) = fetch;
|
||||||
let ($($state,)*) = state;
|
let ($($state,)*) = state;
|
||||||
// SAFETY: The invariants are uphold by the caller.
|
// SAFETY: The invariants are upheld by the caller.
|
||||||
$(unsafe { $name::set_archetype($name, $state, archetype, table); })*
|
$(unsafe { $name::set_archetype($name, $state, archetype, table); })*
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -224,7 +234,7 @@ macro_rules! impl_tuple_world_query {
|
|||||||
unsafe fn set_table<'w>(fetch: &mut Self::Fetch<'w>, state: &Self::State, table: &'w Table) {
|
unsafe fn set_table<'w>(fetch: &mut Self::Fetch<'w>, state: &Self::State, table: &'w Table) {
|
||||||
let ($($name,)*) = fetch;
|
let ($($name,)*) = fetch;
|
||||||
let ($($state,)*) = state;
|
let ($($state,)*) = state;
|
||||||
// SAFETY: The invariants are uphold by the caller.
|
// SAFETY: The invariants are upheld by the caller.
|
||||||
$(unsafe { $name::set_table($name, $state, table); })*
|
$(unsafe { $name::set_table($name, $state, table); })*
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -235,7 +245,7 @@ macro_rules! impl_tuple_world_query {
|
|||||||
table_row: TableRow
|
table_row: TableRow
|
||||||
) -> Self::Item<'w> {
|
) -> Self::Item<'w> {
|
||||||
let ($($name,)*) = fetch;
|
let ($($name,)*) = fetch;
|
||||||
// SAFETY: The invariants are uphold by the caller.
|
// SAFETY: The invariants are upheld by the caller.
|
||||||
($(unsafe { $name::fetch($name, entity, table_row) },)*)
|
($(unsafe { $name::fetch($name, entity, table_row) },)*)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -630,7 +630,7 @@ impl<Param: SystemParam> SystemState<Param> {
|
|||||||
world: UnsafeWorldCell<'w>,
|
world: UnsafeWorldCell<'w>,
|
||||||
) -> SystemParamItem<'w, 's, Param> {
|
) -> SystemParamItem<'w, 's, Param> {
|
||||||
let change_tick = world.increment_change_tick();
|
let change_tick = world.increment_change_tick();
|
||||||
// SAFETY: The invariants are uphold by the caller.
|
// SAFETY: The invariants are upheld by the caller.
|
||||||
unsafe { self.fetch(world, change_tick) }
|
unsafe { self.fetch(world, change_tick) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -644,7 +644,7 @@ impl<Param: SystemParam> SystemState<Param> {
|
|||||||
world: UnsafeWorldCell<'w>,
|
world: UnsafeWorldCell<'w>,
|
||||||
change_tick: Tick,
|
change_tick: Tick,
|
||||||
) -> SystemParamItem<'w, 's, Param> {
|
) -> SystemParamItem<'w, 's, Param> {
|
||||||
// SAFETY: The invariants are uphold by the caller.
|
// SAFETY: The invariants are upheld by the caller.
|
||||||
let param =
|
let param =
|
||||||
unsafe { Param::get_param(&mut self.param_state, &self.meta, world, change_tick) };
|
unsafe { Param::get_param(&mut self.param_state, &self.meta, world, change_tick) };
|
||||||
self.meta.last_run = change_tick;
|
self.meta.last_run = change_tick;
|
||||||
|
Loading…
Reference in New Issue
Block a user