Add QueryState::contains, document complexity, and make as_nop pub(crate) (#12776)

# Objective
Fixes #12752. Fixes #12750. Document the runtime complexity of all of
the `O(1)` operations on the individual APIs.

## Solution

  * Mirror `Query::contains` onto `QueryState::contains`
  * Make `QueryState::as_nop` pub(crate)
  * Make `NopWorldQuery` pub(crate)
  * Document all of the O(1) operations on Query and QueryState.
This commit is contained in:
James Liu 2024-03-29 07:49:43 -07:00 committed by GitHub
parent 476e296561
commit a6e37e7a2a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 40 additions and 2 deletions

View file

@ -1809,7 +1809,7 @@ all_tuples!(impl_anytuple_fetch, 0, 15, F, S);
/// [`WorldQuery`] used to nullify queries by turning `Query<D>` into `Query<NopWorldQuery<D>>`
///
/// This will rarely be useful to consumers of `bevy_ecs`.
pub struct NopWorldQuery<D: QueryData>(PhantomData<D>);
pub(crate) struct NopWorldQuery<D: QueryData>(PhantomData<D>);
/// SAFETY:
/// `update_component_access` and `update_archetype_component_access` do nothing.

View file

@ -86,7 +86,7 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
///
/// This doesn't use `NopWorldQuery` as it loses filter functionality, for example
/// `NopWorldQuery<Changed<T>>` is functionally equivalent to `With<T>`.
pub fn as_nop(&self) -> &QueryState<NopWorldQuery<D>, F> {
pub(crate) fn as_nop(&self) -> &QueryState<NopWorldQuery<D>, F> {
// SAFETY: `NopWorldQuery` doesn't have any accesses and defers to
// `D` for table/archetype matching
unsafe { self.as_transmuted_state::<NopWorldQuery<D>, F>() }
@ -244,6 +244,24 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
}
}
/// Returns `true` if the given [`Entity`] matches the query.
///
/// This is always guaranteed to run in `O(1)` time.
#[inline]
pub fn contains(&self, entity: Entity, world: &World, last_run: Tick, this_run: Tick) -> bool {
// SAFETY: NopFetch does not access any members while &self ensures no one has exclusive access
unsafe {
self.as_nop()
.get_unchecked_manual(
world.as_unsafe_world_cell_readonly(),
entity,
last_run,
this_run,
)
.is_ok()
}
}
/// Checks if the query is empty for the given [`UnsafeWorldCell`].
///
/// # Safety
@ -570,6 +588,8 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
/// Gets the query result for the given [`World`] and [`Entity`].
///
/// This can only be called for read-only queries, see [`Self::get_mut`] for write-queries.
///
/// This is always guaranteed to run in `O(1)` time.
#[inline]
pub fn get<'w>(
&mut self,
@ -642,6 +662,8 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
}
/// Gets the query result for the given [`World`] and [`Entity`].
///
/// This is always guaranteed to run in `O(1)` time.
#[inline]
pub fn get_mut<'w>(
&mut self,
@ -733,6 +755,8 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
/// access to `self`.
///
/// This can only be called for read-only queries, see [`Self::get_mut`] for mutable queries.
///
/// This is always guaranteed to run in `O(1)` time.
#[inline]
pub fn get_manual<'w>(
&self,
@ -753,6 +777,8 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
/// Gets the query result for the given [`World`] and [`Entity`].
///
/// This is always guaranteed to run in `O(1)` time.
///
/// # Safety
///
/// This does not check for mutable query correctness. To be safe, make sure mutable queries
@ -770,6 +796,8 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
/// Gets the query result for the given [`World`] and [`Entity`], where the last change and
/// the current change tick are given.
///
/// This is always guaranteed to run in `O(1)` time.
///
/// # Safety
///
/// This does not check for mutable query correctness. To be safe, make sure mutable queries
@ -850,6 +878,8 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
/// Gets the query results for the given [`World`] and array of [`Entity`], where the last change and
/// the current change tick are given.
///
/// This is always guaranteed to run in `O(1)` time.
///
/// # Safety
///
/// This does not check for unique access to subsets of the entity-component data.

View file

@ -813,6 +813,8 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
///
/// In case of a nonexisting entity or mismatched component, a [`QueryEntityError`] is returned instead.
///
/// This is always guaranteed to run in `O(1)` time.
///
/// # Example
///
/// Here, `get` is used to retrieve the exact query item of the entity specified by the `SelectedCharacter` resource.
@ -931,6 +933,8 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
///
/// In case of a nonexisting entity or mismatched component, a [`QueryEntityError`] is returned instead.
///
/// This is always guaranteed to run in `O(1)` time.
///
/// # Example
///
/// Here, `get_mut` is used to retrieve the exact query item of the entity specified by the `PoisonedCharacter` resource.
@ -1045,6 +1049,8 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
///
/// In case of a nonexisting entity or mismatched component, a [`QueryEntityError`] is returned instead.
///
/// This is always guaranteed to run in `O(1)` time.
///
/// # Safety
///
/// This function makes it possible to violate Rust's aliasing guarantees.
@ -1248,6 +1254,8 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
/// Returns `true` if the given [`Entity`] matches the query.
///
/// This is always guaranteed to run in `O(1)` time.
///
/// # Example
///
/// ```