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>>` /// [`WorldQuery`] used to nullify queries by turning `Query<D>` into `Query<NopWorldQuery<D>>`
/// ///
/// This will rarely be useful to consumers of `bevy_ecs`. /// 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: /// SAFETY:
/// `update_component_access` and `update_archetype_component_access` do nothing. /// `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 /// This doesn't use `NopWorldQuery` as it loses filter functionality, for example
/// `NopWorldQuery<Changed<T>>` is functionally equivalent to `With<T>`. /// `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 // SAFETY: `NopWorldQuery` doesn't have any accesses and defers to
// `D` for table/archetype matching // `D` for table/archetype matching
unsafe { self.as_transmuted_state::<NopWorldQuery<D>, F>() } 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`]. /// Checks if the query is empty for the given [`UnsafeWorldCell`].
/// ///
/// # Safety /// # Safety
@ -570,6 +588,8 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
/// Gets the query result for the given [`World`] and [`Entity`]. /// 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 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] #[inline]
pub fn get<'w>( pub fn get<'w>(
&mut self, &mut self,
@ -642,6 +662,8 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
} }
/// Gets the query result for the given [`World`] and [`Entity`]. /// Gets the query result for the given [`World`] and [`Entity`].
///
/// This is always guaranteed to run in `O(1)` time.
#[inline] #[inline]
pub fn get_mut<'w>( pub fn get_mut<'w>(
&mut self, &mut self,
@ -733,6 +755,8 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
/// access to `self`. /// access to `self`.
/// ///
/// This can only be called for read-only queries, see [`Self::get_mut`] for mutable queries. /// 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] #[inline]
pub fn get_manual<'w>( pub fn get_manual<'w>(
&self, &self,
@ -753,6 +777,8 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
/// Gets the query result for the given [`World`] and [`Entity`]. /// Gets the query result for the given [`World`] and [`Entity`].
/// ///
/// This is always guaranteed to run in `O(1)` time.
///
/// # Safety /// # Safety
/// ///
/// This does not check for mutable query correctness. To be safe, make sure mutable queries /// 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 /// Gets the query result for the given [`World`] and [`Entity`], where the last change and
/// the current change tick are given. /// the current change tick are given.
/// ///
/// This is always guaranteed to run in `O(1)` time.
///
/// # Safety /// # Safety
/// ///
/// This does not check for mutable query correctness. To be safe, make sure mutable queries /// 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 /// Gets the query results for the given [`World`] and array of [`Entity`], where the last change and
/// the current change tick are given. /// the current change tick are given.
/// ///
/// This is always guaranteed to run in `O(1)` time.
///
/// # Safety /// # Safety
/// ///
/// This does not check for unique access to subsets of the entity-component data. /// 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. /// 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 /// # Example
/// ///
/// Here, `get` is used to retrieve the exact query item of the entity specified by the `SelectedCharacter` resource. /// 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. /// 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 /// # Example
/// ///
/// Here, `get_mut` is used to retrieve the exact query item of the entity specified by the `PoisonedCharacter` resource. /// 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. /// 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 /// # Safety
/// ///
/// This function makes it possible to violate Rust's aliasing guarantees. /// 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. /// Returns `true` if the given [`Entity`] matches the query.
/// ///
/// This is always guaranteed to run in `O(1)` time.
///
/// # Example /// # Example
/// ///
/// ``` /// ```