Move implementations of Query
methods from QueryState
to Query
. (#17822)
# Objective Simplify the API surface by removing duplicated functionality between `Query` and `QueryState`. Reduce the amount of `unsafe` code required in `QueryState`. This is a follow-up to #15858. ## Solution Move implementations of `Query` methods from `QueryState` to `Query`. Instead of the original methods being on `QueryState`, with `Query` methods calling them by passing the individual parameters, the original methods are now on `Query`, with `QueryState` methods calling them by constructing a `Query`. This also adds two `_inner` methods that were missed in #15858: `iter_many_unique_inner` and `single_inner`. One goal here is to be able to deprecate and eventually remove many of the methods on `QueryState`, reducing the overall API surface. (I expected to do that in this PR, but this change was large enough on its own!) Now that the `QueryState` methods each consist of a simple expression like `self.query(world).get_inner(entity)`, a future PR can deprecate some or all of them with simple migration instructions. The other goal is to reduce the amount of `unsafe` code. The current implementation of a read-only method like `QueryState::get` directly calls the `unsafe fn get_unchecked_manual` and needs to repeat the proof that `&World` has enough access. With this change, `QueryState::get` is entirely safe code, with the proof that `&World` has enough access done by the `query()` method and shared across all read-only operations. ## Future Work The next step will be to mark the `QueryState` methods as `#[deprecated]` and migrate callers to the methods on `Query`.
This commit is contained in:
parent
0a32450715
commit
794bf6a332
@ -17,7 +17,7 @@ pub enum QueryEntityError<'w> {
|
||||
NoSuchEntity(Entity, EntityDoesNotExistDetails),
|
||||
/// The [`Entity`] was requested mutably more than once.
|
||||
///
|
||||
/// See [`QueryState::get_many_mut`](crate::query::QueryState::get_many_mut) for an example.
|
||||
/// See [`Query::get_many_mut`](crate::system::Query::get_many_mut) for an example.
|
||||
AliasedMutability(Entity),
|
||||
}
|
||||
|
||||
|
@ -849,6 +849,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIter<'w, 's, D, F> {
|
||||
// SAFETY:
|
||||
// `self.world` has permission to access the required components.
|
||||
// The original query iter has not been iterated on, so no items are aliased from it.
|
||||
// `QueryIter::new` ensures `world` is the same one used to initialize `query_state`.
|
||||
let query_lens = unsafe { query_lens_state.query_unchecked_manual(world) }.into_iter();
|
||||
let mut keyed_query: Vec<_> = query_lens
|
||||
.map(|(key, entity)| (key, NeutralOrd(entity)))
|
||||
@ -1683,6 +1684,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter, I: Iterator<Item: EntityBorrow>>
|
||||
// SAFETY:
|
||||
// `self.world` has permission to access the required components.
|
||||
// The original query iter has not been iterated on, so no items are aliased from it.
|
||||
// `QueryIter::new` ensures `world` is the same one used to initialize `query_state`.
|
||||
let query_lens = unsafe { query_lens_state.query_unchecked_manual(world) }
|
||||
.iter_many_inner(self.entity_iter);
|
||||
let mut keyed_query: Vec<_> = query_lens
|
||||
|
@ -94,7 +94,8 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryParIter<'w, 's, D, F> {
|
||||
// at the same time.
|
||||
unsafe {
|
||||
self.state
|
||||
.iter_unchecked_manual(self.world, self.last_run, self.this_run)
|
||||
.query_unchecked_manual_with_ticks(self.world, self.last_run, self.this_run)
|
||||
.into_iter()
|
||||
.fold(init, func);
|
||||
}
|
||||
}
|
||||
@ -106,7 +107,8 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryParIter<'w, 's, D, F> {
|
||||
// SAFETY: See the safety comment above.
|
||||
unsafe {
|
||||
self.state
|
||||
.iter_unchecked_manual(self.world, self.last_run, self.this_run)
|
||||
.query_unchecked_manual_with_ticks(self.world, self.last_run, self.this_run)
|
||||
.into_iter()
|
||||
.fold(init, func);
|
||||
}
|
||||
} else {
|
||||
@ -262,12 +264,8 @@ impl<'w, 's, D: ReadOnlyQueryData, F: QueryFilter, E: EntityBorrow + Sync>
|
||||
// at the same time.
|
||||
unsafe {
|
||||
self.state
|
||||
.iter_many_unchecked_manual(
|
||||
&self.entity_list,
|
||||
self.world,
|
||||
self.last_run,
|
||||
self.this_run,
|
||||
)
|
||||
.query_unchecked_manual_with_ticks(self.world, self.last_run, self.this_run)
|
||||
.iter_many_inner(&self.entity_list)
|
||||
.fold(init, func);
|
||||
}
|
||||
}
|
||||
@ -279,12 +277,8 @@ impl<'w, 's, D: ReadOnlyQueryData, F: QueryFilter, E: EntityBorrow + Sync>
|
||||
// SAFETY: See the safety comment above.
|
||||
unsafe {
|
||||
self.state
|
||||
.iter_many_unchecked_manual(
|
||||
&self.entity_list,
|
||||
self.world,
|
||||
self.last_run,
|
||||
self.this_run,
|
||||
)
|
||||
.query_unchecked_manual_with_ticks(self.world, self.last_run, self.this_run)
|
||||
.iter_many_inner(&self.entity_list)
|
||||
.fold(init, func);
|
||||
}
|
||||
} else {
|
||||
@ -430,12 +424,8 @@ impl<'w, 's, D: QueryData, F: QueryFilter, E: TrustedEntityBorrow + Sync>
|
||||
// at the same time.
|
||||
unsafe {
|
||||
self.state
|
||||
.iter_many_unique_unchecked_manual(
|
||||
self.entity_list,
|
||||
self.world,
|
||||
self.last_run,
|
||||
self.this_run,
|
||||
)
|
||||
.query_unchecked_manual_with_ticks(self.world, self.last_run, self.this_run)
|
||||
.iter_many_unique_inner(self.entity_list)
|
||||
.fold(init, func);
|
||||
}
|
||||
}
|
||||
@ -447,12 +437,8 @@ impl<'w, 's, D: QueryData, F: QueryFilter, E: TrustedEntityBorrow + Sync>
|
||||
// SAFETY: See the safety comment above.
|
||||
unsafe {
|
||||
self.state
|
||||
.iter_many_unique_unchecked_manual(
|
||||
self.entity_list,
|
||||
self.world,
|
||||
self.last_run,
|
||||
self.this_run,
|
||||
)
|
||||
.query_unchecked_manual_with_ticks(self.world, self.last_run, self.this_run)
|
||||
.iter_many_unique_inner(self.entity_list)
|
||||
.fold(init, func);
|
||||
}
|
||||
} else {
|
||||
|
@ -1,14 +1,10 @@
|
||||
use crate::{
|
||||
archetype::{Archetype, ArchetypeComponentId, ArchetypeGeneration, ArchetypeId},
|
||||
batching::BatchingStrategy,
|
||||
component::{ComponentId, Tick},
|
||||
entity::{Entity, EntityBorrow, EntitySet},
|
||||
entity_disabling::DefaultQueryFilters,
|
||||
prelude::FromWorld,
|
||||
query::{
|
||||
Access, DebugCheckedUnwrap, FilteredAccess, QueryCombinationIter, QueryIter, QueryParIter,
|
||||
WorldQuery,
|
||||
},
|
||||
query::{Access, FilteredAccess, QueryCombinationIter, QueryIter, QueryParIter, WorldQuery},
|
||||
storage::{SparseSetIndex, TableId},
|
||||
system::Query,
|
||||
world::{unsafe_world_cell::UnsafeWorldCell, World, WorldId},
|
||||
@ -18,7 +14,7 @@ use crate::{
|
||||
use crate::entity::{TrustedEntityBorrow, UniqueEntitySlice};
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use core::{fmt, mem::MaybeUninit, ptr};
|
||||
use core::{fmt, ptr};
|
||||
use fixedbitset::FixedBitSet;
|
||||
use log::warn;
|
||||
#[cfg(feature = "trace")]
|
||||
@ -341,7 +337,10 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
///
|
||||
/// This will create read-only queries, see [`Self::query_mut`] for mutable queries.
|
||||
pub fn query_manual<'w, 's>(&'s self, world: &'w World) -> Query<'w, 's, D::ReadOnly, F> {
|
||||
// SAFETY: We have read access to the entire world, and we call `as_readonly()` so the query only performs read access.
|
||||
self.validate_world(world.id());
|
||||
// SAFETY:
|
||||
// - We have read access to the entire world, and we call `as_readonly()` so the query only performs read access.
|
||||
// - We called `validate_world`.
|
||||
unsafe {
|
||||
self.as_readonly()
|
||||
.query_unchecked_manual(world.as_unsafe_world_cell_readonly())
|
||||
@ -385,13 +384,17 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
///
|
||||
/// This does not check for mutable query correctness. To be safe, make sure mutable queries
|
||||
/// have unique access to the components they query.
|
||||
/// This does not validate that `world.id()` matches `self.world_id`. Calling this on a `world`
|
||||
/// with a mismatched [`WorldId`] is unsound.
|
||||
pub unsafe fn query_unchecked_manual<'w, 's>(
|
||||
&'s self,
|
||||
world: UnsafeWorldCell<'w>,
|
||||
) -> Query<'w, 's, D, F> {
|
||||
let last_run = world.last_change_tick();
|
||||
let this_run = world.change_tick();
|
||||
// SAFETY: The caller ensured we have the correct access to the world.
|
||||
// SAFETY:
|
||||
// - The caller ensured we have the correct access to the world.
|
||||
// - The caller ensured that the world matches.
|
||||
unsafe { self.query_unchecked_manual_with_ticks(world, last_run, this_run) }
|
||||
}
|
||||
|
||||
@ -408,7 +411,9 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
this_run: Tick,
|
||||
) -> Query<'w, 's, D, F> {
|
||||
self.update_archetypes_unsafe_world_cell(world);
|
||||
// SAFETY: The caller ensured we have the correct access to the world.
|
||||
// SAFETY:
|
||||
// - The caller ensured we have the correct access to the world.
|
||||
// - We called `update_archetypes_unsafe_world_cell`, which calls `validate_world`.
|
||||
unsafe { self.query_unchecked_manual_with_ticks(world, last_run, this_run) }
|
||||
}
|
||||
|
||||
@ -426,16 +431,17 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
///
|
||||
/// This does not check for mutable query correctness. To be safe, make sure mutable queries
|
||||
/// have unique access to the components they query.
|
||||
/// This does not validate that `world.id()` matches `self.world_id`. Calling this on a `world`
|
||||
/// with a mismatched [`WorldId`] is unsound.
|
||||
pub unsafe fn query_unchecked_manual_with_ticks<'w, 's>(
|
||||
&'s self,
|
||||
world: UnsafeWorldCell<'w>,
|
||||
last_run: Tick,
|
||||
this_run: Tick,
|
||||
) -> Query<'w, 's, D, F> {
|
||||
self.validate_world(world.id());
|
||||
// SAFETY:
|
||||
// - The caller ensured we have the correct access to the world.
|
||||
// - `validate_world` did not panic, so the world matches.
|
||||
// - The caller ensured that the world matches.
|
||||
unsafe { Query::new(world, self, last_run, this_run) }
|
||||
}
|
||||
|
||||
@ -456,15 +462,16 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
pub fn is_empty(&self, world: &World, last_run: Tick, this_run: Tick) -> bool {
|
||||
self.validate_world(world.id());
|
||||
// SAFETY:
|
||||
// - We have read-only access to the entire world.
|
||||
// - The world has been validated.
|
||||
// - We have read access to the entire world, and `is_empty()` only performs read access.
|
||||
// - We called `validate_world`.
|
||||
unsafe {
|
||||
self.is_empty_unsafe_world_cell(
|
||||
self.query_unchecked_manual_with_ticks(
|
||||
world.as_unsafe_world_cell_readonly(),
|
||||
last_run,
|
||||
this_run,
|
||||
)
|
||||
}
|
||||
.is_empty()
|
||||
}
|
||||
|
||||
/// Returns `true` if the given [`Entity`] matches the query.
|
||||
@ -472,41 +479,18 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
/// 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
|
||||
///
|
||||
/// - `world` must have permission to read any components required by this instance's `F` [`QueryFilter`].
|
||||
/// - `world` must match the one used to create this [`QueryState`].
|
||||
#[inline]
|
||||
pub(crate) unsafe fn is_empty_unsafe_world_cell(
|
||||
&self,
|
||||
world: UnsafeWorldCell,
|
||||
last_run: Tick,
|
||||
this_run: Tick,
|
||||
) -> bool {
|
||||
self.validate_world(world.id());
|
||||
// SAFETY:
|
||||
// - The caller ensures that `world` has permission to access any data used by the filter.
|
||||
// - The caller ensures that the world matches.
|
||||
// - We have read access to the entire world, and `is_empty()` only performs read access.
|
||||
// - We called `validate_world`.
|
||||
unsafe {
|
||||
self.as_nop()
|
||||
.iter_unchecked_manual(world, last_run, this_run)
|
||||
.next()
|
||||
.is_none()
|
||||
self.query_unchecked_manual_with_ticks(
|
||||
world.as_unsafe_world_cell_readonly(),
|
||||
last_run,
|
||||
this_run,
|
||||
)
|
||||
}
|
||||
.contains(entity)
|
||||
}
|
||||
|
||||
/// Updates the state's internal view of the [`World`]'s archetypes. If this is not called before querying data,
|
||||
@ -932,16 +916,7 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
world: &'w World,
|
||||
entity: Entity,
|
||||
) -> Result<ROQueryItem<'w, D>, QueryEntityError<'w>> {
|
||||
self.update_archetypes(world);
|
||||
// SAFETY: query is read only
|
||||
unsafe {
|
||||
self.as_readonly().get_unchecked_manual(
|
||||
world.as_unsafe_world_cell_readonly(),
|
||||
entity,
|
||||
world.last_change_tick(),
|
||||
world.read_change_tick(),
|
||||
)
|
||||
}
|
||||
self.query(world).get_inner(entity)
|
||||
}
|
||||
|
||||
/// Returns the read-only query results for the given array of [`Entity`].
|
||||
@ -982,19 +957,7 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
world: &'w World,
|
||||
entities: [Entity; N],
|
||||
) -> Result<[ROQueryItem<'w, D>; N], QueryEntityError<'w>> {
|
||||
self.update_archetypes(world);
|
||||
|
||||
// SAFETY:
|
||||
// - We have read-only access to the entire world.
|
||||
// - `update_archetypes` validates that the `World` matches.
|
||||
unsafe {
|
||||
self.get_many_read_only_manual(
|
||||
world.as_unsafe_world_cell_readonly(),
|
||||
entities,
|
||||
world.last_change_tick(),
|
||||
world.read_change_tick(),
|
||||
)
|
||||
}
|
||||
self.query(world).get_many_inner(entities)
|
||||
}
|
||||
|
||||
/// Gets the query result for the given [`World`] and [`Entity`].
|
||||
@ -1006,18 +969,7 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
world: &'w mut World,
|
||||
entity: Entity,
|
||||
) -> Result<D::Item<'w>, QueryEntityError<'w>> {
|
||||
self.update_archetypes(world);
|
||||
let change_tick = world.change_tick();
|
||||
let last_change_tick = world.last_change_tick();
|
||||
// SAFETY: query has unique world access
|
||||
unsafe {
|
||||
self.get_unchecked_manual(
|
||||
world.as_unsafe_world_cell(),
|
||||
entity,
|
||||
last_change_tick,
|
||||
change_tick,
|
||||
)
|
||||
}
|
||||
self.query_mut(world).get_inner(entity)
|
||||
}
|
||||
|
||||
/// Returns the query results for the given array of [`Entity`].
|
||||
@ -1064,20 +1016,7 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
world: &'w mut World,
|
||||
entities: [Entity; N],
|
||||
) -> Result<[D::Item<'w>; N], QueryEntityError<'w>> {
|
||||
self.update_archetypes(world);
|
||||
|
||||
let change_tick = world.change_tick();
|
||||
let last_change_tick = world.last_change_tick();
|
||||
// SAFETY: method requires exclusive world access
|
||||
// and world has been validated via update_archetypes
|
||||
unsafe {
|
||||
self.get_many_unchecked_manual(
|
||||
world.as_unsafe_world_cell(),
|
||||
entities,
|
||||
last_change_tick,
|
||||
change_tick,
|
||||
)
|
||||
}
|
||||
self.query_mut(world).get_many_inner(entities)
|
||||
}
|
||||
|
||||
/// Gets the query result for the given [`World`] and [`Entity`].
|
||||
@ -1099,16 +1038,7 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
world: &'w World,
|
||||
entity: Entity,
|
||||
) -> Result<ROQueryItem<'w, D>, QueryEntityError<'w>> {
|
||||
self.validate_world(world.id());
|
||||
// SAFETY: query is read only and world is validated
|
||||
unsafe {
|
||||
self.as_readonly().get_unchecked_manual(
|
||||
world.as_unsafe_world_cell_readonly(),
|
||||
entity,
|
||||
world.last_change_tick(),
|
||||
world.read_change_tick(),
|
||||
)
|
||||
}
|
||||
self.query_manual(world).get_inner(entity)
|
||||
}
|
||||
|
||||
/// Gets the query result for the given [`World`] and [`Entity`].
|
||||
@ -1125,132 +1055,7 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
world: UnsafeWorldCell<'w>,
|
||||
entity: Entity,
|
||||
) -> Result<D::Item<'w>, QueryEntityError<'w>> {
|
||||
self.update_archetypes_unsafe_world_cell(world);
|
||||
self.get_unchecked_manual(world, entity, world.last_change_tick(), world.change_tick())
|
||||
}
|
||||
|
||||
/// 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
|
||||
/// have unique access to the components they query.
|
||||
///
|
||||
/// This must be called on the same `World` that the `Query` was generated from:
|
||||
/// use `QueryState::validate_world` to verify this.
|
||||
pub(crate) unsafe fn get_unchecked_manual<'w>(
|
||||
&self,
|
||||
world: UnsafeWorldCell<'w>,
|
||||
entity: Entity,
|
||||
last_run: Tick,
|
||||
this_run: Tick,
|
||||
) -> Result<D::Item<'w>, QueryEntityError<'w>> {
|
||||
let location = world
|
||||
.entities()
|
||||
.get(entity)
|
||||
.ok_or(QueryEntityError::NoSuchEntity(
|
||||
entity,
|
||||
world.entities().entity_does_not_exist_error_details(entity),
|
||||
))?;
|
||||
if !self
|
||||
.matched_archetypes
|
||||
.contains(location.archetype_id.index())
|
||||
{
|
||||
return Err(QueryEntityError::QueryDoesNotMatch(entity, world));
|
||||
}
|
||||
let archetype = world
|
||||
.archetypes()
|
||||
.get(location.archetype_id)
|
||||
.debug_checked_unwrap();
|
||||
let mut fetch = D::init_fetch(world, &self.fetch_state, last_run, this_run);
|
||||
let mut filter = F::init_fetch(world, &self.filter_state, last_run, this_run);
|
||||
|
||||
let table = world
|
||||
.storages()
|
||||
.tables
|
||||
.get(location.table_id)
|
||||
.debug_checked_unwrap();
|
||||
D::set_archetype(&mut fetch, &self.fetch_state, archetype, table);
|
||||
F::set_archetype(&mut filter, &self.filter_state, archetype, table);
|
||||
|
||||
if F::filter_fetch(&mut filter, entity, location.table_row) {
|
||||
Ok(D::fetch(&mut fetch, entity, location.table_row))
|
||||
} else {
|
||||
Err(QueryEntityError::QueryDoesNotMatch(entity, world))
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the read-only query results for the given [`World`] and array of [`Entity`], where the last change and
|
||||
/// the current change tick are given.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// * `world` must have permission to read all of the components returned from this call.
|
||||
/// No mutable references may coexist with any of the returned references.
|
||||
/// * This must be called on the same `World` that the `Query` was generated from:
|
||||
/// use `QueryState::validate_world` to verify this.
|
||||
pub(crate) unsafe fn get_many_read_only_manual<'w, const N: usize>(
|
||||
&self,
|
||||
world: UnsafeWorldCell<'w>,
|
||||
entities: [Entity; N],
|
||||
last_run: Tick,
|
||||
this_run: Tick,
|
||||
) -> Result<[ROQueryItem<'w, D>; N], QueryEntityError<'w>> {
|
||||
let mut values = [(); N].map(|_| MaybeUninit::uninit());
|
||||
|
||||
for (value, entity) in core::iter::zip(&mut values, entities) {
|
||||
// SAFETY: fetch is read-only and world must be validated
|
||||
let item = unsafe {
|
||||
self.as_readonly()
|
||||
.get_unchecked_manual(world, entity, last_run, this_run)?
|
||||
};
|
||||
*value = MaybeUninit::new(item);
|
||||
}
|
||||
|
||||
// SAFETY: Each value has been fully initialized.
|
||||
Ok(values.map(|x| unsafe { x.assume_init() }))
|
||||
}
|
||||
|
||||
/// 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.
|
||||
/// To be safe, make sure mutable queries have unique access to the components they query.
|
||||
///
|
||||
/// This must be called on the same `World` that the `Query` was generated from:
|
||||
/// use `QueryState::validate_world` to verify this.
|
||||
pub(crate) unsafe fn get_many_unchecked_manual<'w, const N: usize>(
|
||||
&self,
|
||||
world: UnsafeWorldCell<'w>,
|
||||
entities: [Entity; N],
|
||||
last_run: Tick,
|
||||
this_run: Tick,
|
||||
) -> Result<[D::Item<'w>; N], QueryEntityError<'w>> {
|
||||
// Verify that all entities are unique
|
||||
for i in 0..N {
|
||||
for j in 0..i {
|
||||
if entities[i] == entities[j] {
|
||||
return Err(QueryEntityError::AliasedMutability(entities[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut values = [(); N].map(|_| MaybeUninit::uninit());
|
||||
|
||||
for (value, entity) in core::iter::zip(&mut values, entities) {
|
||||
let item = self.get_unchecked_manual(world, entity, last_run, this_run)?;
|
||||
*value = MaybeUninit::new(item);
|
||||
}
|
||||
|
||||
// SAFETY: Each value has been fully initialized.
|
||||
Ok(values.map(|x| x.assume_init()))
|
||||
self.query_unchecked(world).get_inner(entity)
|
||||
}
|
||||
|
||||
/// Returns an [`Iterator`] over the query results for the given [`World`].
|
||||
@ -1258,15 +1063,7 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
/// This can only be called for read-only queries, see [`Self::iter_mut`] for write-queries.
|
||||
#[inline]
|
||||
pub fn iter<'w, 's>(&'s mut self, world: &'w World) -> QueryIter<'w, 's, D::ReadOnly, F> {
|
||||
self.update_archetypes(world);
|
||||
// SAFETY: query is read only
|
||||
unsafe {
|
||||
self.as_readonly().iter_unchecked_manual(
|
||||
world.as_unsafe_world_cell_readonly(),
|
||||
world.last_change_tick(),
|
||||
world.read_change_tick(),
|
||||
)
|
||||
}
|
||||
self.query(world).into_iter()
|
||||
}
|
||||
|
||||
/// Returns an [`Iterator`] over the query results for the given [`World`].
|
||||
@ -1275,13 +1072,7 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
/// Iteration order is not guaranteed.
|
||||
#[inline]
|
||||
pub fn iter_mut<'w, 's>(&'s mut self, world: &'w mut World) -> QueryIter<'w, 's, D, F> {
|
||||
self.update_archetypes(world);
|
||||
let change_tick = world.change_tick();
|
||||
let last_change_tick = world.last_change_tick();
|
||||
// SAFETY: query has unique world access
|
||||
unsafe {
|
||||
self.iter_unchecked_manual(world.as_unsafe_world_cell(), last_change_tick, change_tick)
|
||||
}
|
||||
self.query_mut(world).into_iter()
|
||||
}
|
||||
|
||||
/// Returns an [`Iterator`] over the query results for the given [`World`] without updating the query's archetypes.
|
||||
@ -1293,15 +1084,7 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
/// This can only be called for read-only queries.
|
||||
#[inline]
|
||||
pub fn iter_manual<'w, 's>(&'s self, world: &'w World) -> QueryIter<'w, 's, D::ReadOnly, F> {
|
||||
self.validate_world(world.id());
|
||||
// SAFETY: query is read only and world is validated
|
||||
unsafe {
|
||||
self.as_readonly().iter_unchecked_manual(
|
||||
world.as_unsafe_world_cell_readonly(),
|
||||
world.last_change_tick(),
|
||||
world.read_change_tick(),
|
||||
)
|
||||
}
|
||||
self.query_manual(world).into_iter()
|
||||
}
|
||||
|
||||
/// Returns an [`Iterator`] over all possible combinations of `K` query results without repetition.
|
||||
@ -1333,15 +1116,7 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
&'s mut self,
|
||||
world: &'w World,
|
||||
) -> QueryCombinationIter<'w, 's, D::ReadOnly, F, K> {
|
||||
self.update_archetypes(world);
|
||||
// SAFETY: query is read only
|
||||
unsafe {
|
||||
self.as_readonly().iter_combinations_unchecked_manual(
|
||||
world.as_unsafe_world_cell_readonly(),
|
||||
world.last_change_tick(),
|
||||
world.read_change_tick(),
|
||||
)
|
||||
}
|
||||
self.query(world).iter_combinations_inner()
|
||||
}
|
||||
|
||||
/// Returns an [`Iterator`] over all possible combinations of `K` query results without repetition.
|
||||
@ -1366,17 +1141,7 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
&'s mut self,
|
||||
world: &'w mut World,
|
||||
) -> QueryCombinationIter<'w, 's, D, F, K> {
|
||||
self.update_archetypes(world);
|
||||
let change_tick = world.change_tick();
|
||||
let last_change_tick = world.last_change_tick();
|
||||
// SAFETY: query has unique world access
|
||||
unsafe {
|
||||
self.iter_combinations_unchecked_manual(
|
||||
world.as_unsafe_world_cell(),
|
||||
last_change_tick,
|
||||
change_tick,
|
||||
)
|
||||
}
|
||||
self.query_mut(world).iter_combinations_inner()
|
||||
}
|
||||
|
||||
/// Returns an [`Iterator`] over the read-only query items generated from an [`Entity`] list.
|
||||
@ -1393,16 +1158,7 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
world: &'w World,
|
||||
entities: EntityList,
|
||||
) -> QueryManyIter<'w, 's, D::ReadOnly, F, EntityList::IntoIter> {
|
||||
self.update_archetypes(world);
|
||||
// SAFETY: query is read only
|
||||
unsafe {
|
||||
self.as_readonly().iter_many_unchecked_manual(
|
||||
entities,
|
||||
world.as_unsafe_world_cell_readonly(),
|
||||
world.last_change_tick(),
|
||||
world.read_change_tick(),
|
||||
)
|
||||
}
|
||||
self.query(world).iter_many_inner(entities)
|
||||
}
|
||||
|
||||
/// Returns an [`Iterator`] over the read-only query items generated from an [`Entity`] list.
|
||||
@ -1425,16 +1181,7 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
world: &'w World,
|
||||
entities: EntityList,
|
||||
) -> QueryManyIter<'w, 's, D::ReadOnly, F, EntityList::IntoIter> {
|
||||
self.validate_world(world.id());
|
||||
// SAFETY: query is read only, world id is validated
|
||||
unsafe {
|
||||
self.as_readonly().iter_many_unchecked_manual(
|
||||
entities,
|
||||
world.as_unsafe_world_cell_readonly(),
|
||||
world.last_change_tick(),
|
||||
world.read_change_tick(),
|
||||
)
|
||||
}
|
||||
self.query_manual(world).iter_many_inner(entities)
|
||||
}
|
||||
|
||||
/// Returns an iterator over the query items generated from an [`Entity`] list.
|
||||
@ -1447,18 +1194,7 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
world: &'w mut World,
|
||||
entities: EntityList,
|
||||
) -> QueryManyIter<'w, 's, D, F, EntityList::IntoIter> {
|
||||
self.update_archetypes(world);
|
||||
let change_tick = world.change_tick();
|
||||
let last_change_tick = world.last_change_tick();
|
||||
// SAFETY: Query has unique world access.
|
||||
unsafe {
|
||||
self.iter_many_unchecked_manual(
|
||||
entities,
|
||||
world.as_unsafe_world_cell(),
|
||||
last_change_tick,
|
||||
change_tick,
|
||||
)
|
||||
}
|
||||
self.query_mut(world).iter_many_inner(entities)
|
||||
}
|
||||
|
||||
/// Returns an [`Iterator`] over the unique read-only query items generated from an [`EntitySet`].
|
||||
@ -1475,16 +1211,7 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
world: &'w World,
|
||||
entities: EntityList,
|
||||
) -> QueryManyUniqueIter<'w, 's, D::ReadOnly, F, EntityList::IntoIter> {
|
||||
self.update_archetypes(world);
|
||||
// SAFETY: query is read only
|
||||
unsafe {
|
||||
self.as_readonly().iter_many_unique_unchecked_manual(
|
||||
entities,
|
||||
world.as_unsafe_world_cell_readonly(),
|
||||
world.last_change_tick(),
|
||||
world.read_change_tick(),
|
||||
)
|
||||
}
|
||||
self.query(world).iter_many_unique_inner(entities)
|
||||
}
|
||||
|
||||
/// Returns an [`Iterator`] over the unique read-only query items generated from an [`EntitySet`].
|
||||
@ -1508,16 +1235,7 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
world: &'w World,
|
||||
entities: EntityList,
|
||||
) -> QueryManyUniqueIter<'w, 's, D::ReadOnly, F, EntityList::IntoIter> {
|
||||
self.validate_world(world.id());
|
||||
// SAFETY: query is read only, world id is validated
|
||||
unsafe {
|
||||
self.as_readonly().iter_many_unique_unchecked_manual(
|
||||
entities,
|
||||
world.as_unsafe_world_cell_readonly(),
|
||||
world.last_change_tick(),
|
||||
world.read_change_tick(),
|
||||
)
|
||||
}
|
||||
self.query_manual(world).iter_many_unique_inner(entities)
|
||||
}
|
||||
|
||||
/// Returns an iterator over the unique query items generated from an [`EntitySet`].
|
||||
@ -1530,18 +1248,7 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
world: &'w mut World,
|
||||
entities: EntityList,
|
||||
) -> QueryManyUniqueIter<'w, 's, D, F, EntityList::IntoIter> {
|
||||
self.update_archetypes(world);
|
||||
let last_change_tick = world.last_change_tick();
|
||||
let change_tick = world.change_tick();
|
||||
// SAFETY: Query has unique world access.
|
||||
unsafe {
|
||||
self.iter_many_unique_unchecked_manual(
|
||||
entities,
|
||||
world.as_unsafe_world_cell(),
|
||||
last_change_tick,
|
||||
change_tick,
|
||||
)
|
||||
}
|
||||
self.query_mut(world).iter_many_unique_inner(entities)
|
||||
}
|
||||
/// Returns an [`Iterator`] over the query results for the given [`World`].
|
||||
///
|
||||
@ -1557,8 +1264,7 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
&'s mut self,
|
||||
world: UnsafeWorldCell<'w>,
|
||||
) -> QueryIter<'w, 's, D, F> {
|
||||
self.update_archetypes_unsafe_world_cell(world);
|
||||
self.iter_unchecked_manual(world, world.last_change_tick(), world.change_tick())
|
||||
self.query_unchecked(world).into_iter()
|
||||
}
|
||||
|
||||
/// Returns an [`Iterator`] over all possible combinations of `K` query results for the
|
||||
@ -1577,107 +1283,7 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
&'s mut self,
|
||||
world: UnsafeWorldCell<'w>,
|
||||
) -> QueryCombinationIter<'w, 's, D, F, K> {
|
||||
self.update_archetypes_unsafe_world_cell(world);
|
||||
self.iter_combinations_unchecked_manual(
|
||||
world,
|
||||
world.last_change_tick(),
|
||||
world.change_tick(),
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns an [`Iterator`] for the given [`World`], where the last change and
|
||||
/// the current change tick are given.
|
||||
///
|
||||
/// This iterator is always guaranteed to return results from each matching entity once and only once.
|
||||
/// Iteration order is not guaranteed.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This does not check for mutable query correctness. To be safe, make sure mutable queries
|
||||
/// have unique access to the components they query.
|
||||
/// This does not validate that `world.id()` matches `self.world_id`. Calling this on a `world`
|
||||
/// with a mismatched [`WorldId`] is unsound.
|
||||
#[inline]
|
||||
pub(crate) unsafe fn iter_unchecked_manual<'w, 's>(
|
||||
&'s self,
|
||||
world: UnsafeWorldCell<'w>,
|
||||
last_run: Tick,
|
||||
this_run: Tick,
|
||||
) -> QueryIter<'w, 's, D, F> {
|
||||
QueryIter::new(world, self, last_run, this_run)
|
||||
}
|
||||
|
||||
/// Returns an [`Iterator`] for the given [`World`] and list of [`Entity`]'s, where the last change and
|
||||
/// the current change tick are given.
|
||||
///
|
||||
/// This iterator is always guaranteed to return results from each unique pair of matching entities.
|
||||
/// Iteration order is not guaranteed.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This does not check for mutable query correctness. To be safe, make sure mutable queries
|
||||
/// have unique access to the components they query.
|
||||
/// This does not check for entity uniqueness
|
||||
/// This does not validate that `world.id()` matches `self.world_id`. Calling this on a `world`
|
||||
/// with a mismatched [`WorldId`] is unsound.
|
||||
#[inline]
|
||||
pub(crate) unsafe fn iter_many_unchecked_manual<'w, 's, EntityList>(
|
||||
&'s self,
|
||||
entities: EntityList,
|
||||
world: UnsafeWorldCell<'w>,
|
||||
last_run: Tick,
|
||||
this_run: Tick,
|
||||
) -> QueryManyIter<'w, 's, D, F, EntityList::IntoIter>
|
||||
where
|
||||
EntityList: IntoIterator<Item: EntityBorrow>,
|
||||
{
|
||||
QueryManyIter::new(world, self, entities, last_run, this_run)
|
||||
}
|
||||
|
||||
/// Returns an [`Iterator`] for the given [`World`] and an [`EntitySet`], where the last change and
|
||||
/// the current change tick are given.
|
||||
///
|
||||
/// Items are returned in the order of the list of entities.
|
||||
/// Entities that don't match the query are skipped.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This does not check for mutable query correctness. To be safe, make sure mutable queries
|
||||
/// have unique access to the components they query.
|
||||
/// This does not validate that `world.id()` matches `self.world_id`. Calling this on a `world`
|
||||
/// with a mismatched [`WorldId`] is unsound.
|
||||
#[inline]
|
||||
pub(crate) unsafe fn iter_many_unique_unchecked_manual<'w, 's, EntityList: EntitySet>(
|
||||
&'s self,
|
||||
entities: EntityList,
|
||||
world: UnsafeWorldCell<'w>,
|
||||
last_run: Tick,
|
||||
this_run: Tick,
|
||||
) -> QueryManyUniqueIter<'w, 's, D, F, EntityList::IntoIter> {
|
||||
QueryManyUniqueIter::new(world, self, entities, last_run, this_run)
|
||||
}
|
||||
|
||||
/// Returns an [`Iterator`] over all possible combinations of `K` query results for the
|
||||
/// given [`World`] without repetition.
|
||||
/// This can only be called for read-only queries.
|
||||
///
|
||||
/// This iterator is always guaranteed to return results from each unique pair of matching entities.
|
||||
/// Iteration order is not guaranteed.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This does not check for mutable query correctness. To be safe, make sure mutable queries
|
||||
/// have unique access to the components they query.
|
||||
/// This does not validate that `world.id()` matches `self.world_id`. Calling this on a `world`
|
||||
/// with a mismatched [`WorldId`] is unsound.
|
||||
#[inline]
|
||||
pub(crate) unsafe fn iter_combinations_unchecked_manual<'w, 's, const K: usize>(
|
||||
&'s self,
|
||||
world: UnsafeWorldCell<'w>,
|
||||
last_run: Tick,
|
||||
this_run: Tick,
|
||||
) -> QueryCombinationIter<'w, 's, D, F, K> {
|
||||
QueryCombinationIter::new(world, self, last_run, this_run)
|
||||
self.query_unchecked(world).iter_combinations_inner()
|
||||
}
|
||||
|
||||
/// Returns a parallel iterator over the query results for the given [`World`].
|
||||
@ -1693,14 +1299,7 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
&'s mut self,
|
||||
world: &'w World,
|
||||
) -> QueryParIter<'w, 's, D::ReadOnly, F> {
|
||||
self.update_archetypes(world);
|
||||
QueryParIter {
|
||||
world: world.as_unsafe_world_cell_readonly(),
|
||||
state: self.as_readonly(),
|
||||
last_run: world.last_change_tick(),
|
||||
this_run: world.read_change_tick(),
|
||||
batching_strategy: BatchingStrategy::new(),
|
||||
}
|
||||
self.query(world).par_iter_inner()
|
||||
}
|
||||
|
||||
/// Returns a parallel iterator over the query results for the given [`World`].
|
||||
@ -1749,16 +1348,7 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
/// [`ComputeTaskPool`]: bevy_tasks::ComputeTaskPool
|
||||
#[inline]
|
||||
pub fn par_iter_mut<'w, 's>(&'s mut self, world: &'w mut World) -> QueryParIter<'w, 's, D, F> {
|
||||
self.update_archetypes(world);
|
||||
let this_run = world.change_tick();
|
||||
let last_run = world.last_change_tick();
|
||||
QueryParIter {
|
||||
world: world.as_unsafe_world_cell(),
|
||||
state: self,
|
||||
last_run,
|
||||
this_run,
|
||||
batching_strategy: BatchingStrategy::new(),
|
||||
}
|
||||
self.query_mut(world).par_iter_inner()
|
||||
}
|
||||
|
||||
/// Runs `func` on each query result in parallel for the given [`World`], where the last change and
|
||||
@ -1813,7 +1403,9 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
scope.spawn(async move {
|
||||
#[cfg(feature = "trace")]
|
||||
let _span = self.par_iter_span.enter();
|
||||
let mut iter = self.iter_unchecked_manual(world, last_run, this_run);
|
||||
let mut iter = self
|
||||
.query_unchecked_manual_with_ticks(world, last_run, this_run)
|
||||
.into_iter();
|
||||
let mut accum = init_accum();
|
||||
for storage_id in queue {
|
||||
accum = iter.fold_over_storage_range(accum, &mut func, storage_id, None);
|
||||
@ -1832,7 +1424,8 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
#[cfg(feature = "trace")]
|
||||
let _span = self.par_iter_span.enter();
|
||||
let accum = init_accum();
|
||||
self.iter_unchecked_manual(world, last_run, this_run)
|
||||
self.query_unchecked_manual_with_ticks(world, last_run, this_run)
|
||||
.into_iter()
|
||||
.fold_over_storage_range(accum, &mut func, storage_id, Some(batch));
|
||||
});
|
||||
}
|
||||
@ -1918,7 +1511,8 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
#[cfg(feature = "trace")]
|
||||
let _span = self.par_iter_span.enter();
|
||||
let accum = init_accum();
|
||||
self.iter_many_unique_unchecked_manual(batch, world, last_run, this_run)
|
||||
self.query_unchecked_manual_with_ticks(world, last_run, this_run)
|
||||
.iter_many_unique_inner(batch)
|
||||
.fold(accum, &mut func);
|
||||
});
|
||||
}
|
||||
@ -1926,7 +1520,8 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
#[cfg(feature = "trace")]
|
||||
let _span = self.par_iter_span.enter();
|
||||
let accum = init_accum();
|
||||
self.iter_many_unique_unchecked_manual(remainder, world, last_run, this_run)
|
||||
self.query_unchecked_manual_with_ticks(world, last_run, this_run)
|
||||
.iter_many_unique_inner(remainder)
|
||||
.fold(accum, &mut func);
|
||||
});
|
||||
}
|
||||
@ -1979,7 +1574,8 @@ impl<D: ReadOnlyQueryData, F: QueryFilter> QueryState<D, F> {
|
||||
#[cfg(feature = "trace")]
|
||||
let _span = self.par_iter_span.enter();
|
||||
let accum = init_accum();
|
||||
self.iter_many_unchecked_manual(batch, world, last_run, this_run)
|
||||
self.query_unchecked_manual_with_ticks(world, last_run, this_run)
|
||||
.iter_many_inner(batch)
|
||||
.fold(accum, &mut func);
|
||||
});
|
||||
}
|
||||
@ -1987,7 +1583,8 @@ impl<D: ReadOnlyQueryData, F: QueryFilter> QueryState<D, F> {
|
||||
#[cfg(feature = "trace")]
|
||||
let _span = self.par_iter_span.enter();
|
||||
let accum = init_accum();
|
||||
self.iter_many_unchecked_manual(remainder, world, last_run, this_run)
|
||||
self.query_unchecked_manual_with_ticks(world, last_run, this_run)
|
||||
.iter_many_inner(remainder)
|
||||
.fold(accum, &mut func);
|
||||
});
|
||||
}
|
||||
@ -2007,10 +1604,7 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
#[track_caller]
|
||||
#[inline]
|
||||
pub fn single<'w>(&mut self, world: &'w World) -> ROQueryItem<'w, D> {
|
||||
match self.get_single(world) {
|
||||
Ok(items) => items,
|
||||
Err(error) => panic!("Cannot get single query result: {error}"),
|
||||
}
|
||||
self.query(world).single_inner()
|
||||
}
|
||||
|
||||
/// Returns a single immutable query result when there is exactly one entity matching
|
||||
@ -2026,16 +1620,7 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
&mut self,
|
||||
world: &'w World,
|
||||
) -> Result<ROQueryItem<'w, D>, QuerySingleError> {
|
||||
self.update_archetypes(world);
|
||||
|
||||
// SAFETY: query is read only
|
||||
unsafe {
|
||||
self.as_readonly().get_single_unchecked_manual(
|
||||
world.as_unsafe_world_cell_readonly(),
|
||||
world.last_change_tick(),
|
||||
world.read_change_tick(),
|
||||
)
|
||||
}
|
||||
self.query(world).get_single_inner()
|
||||
}
|
||||
|
||||
/// Returns a single mutable query result when there is exactly one entity matching
|
||||
@ -2048,11 +1633,7 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
#[track_caller]
|
||||
#[inline]
|
||||
pub fn single_mut<'w>(&mut self, world: &'w mut World) -> D::Item<'w> {
|
||||
// SAFETY: query has unique world access
|
||||
match self.get_single_mut(world) {
|
||||
Ok(items) => items,
|
||||
Err(error) => panic!("Cannot get single query result: {error}"),
|
||||
}
|
||||
self.query_mut(world).single_inner()
|
||||
}
|
||||
|
||||
/// Returns a single mutable query result when there is exactly one entity matching
|
||||
@ -2065,18 +1646,7 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
&mut self,
|
||||
world: &'w mut World,
|
||||
) -> Result<D::Item<'w>, QuerySingleError> {
|
||||
self.update_archetypes(world);
|
||||
|
||||
let change_tick = world.change_tick();
|
||||
let last_change_tick = world.last_change_tick();
|
||||
// SAFETY: query has unique world access
|
||||
unsafe {
|
||||
self.get_single_unchecked_manual(
|
||||
world.as_unsafe_world_cell(),
|
||||
last_change_tick,
|
||||
change_tick,
|
||||
)
|
||||
}
|
||||
self.query_mut(world).get_single_inner()
|
||||
}
|
||||
|
||||
/// Returns a query result when there is exactly one entity matching the query.
|
||||
@ -2093,8 +1663,7 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
&mut self,
|
||||
world: UnsafeWorldCell<'w>,
|
||||
) -> Result<D::Item<'w>, QuerySingleError> {
|
||||
self.update_archetypes_unsafe_world_cell(world);
|
||||
self.get_single_unchecked_manual(world, world.last_change_tick(), world.change_tick())
|
||||
self.query_unchecked(world).get_single_inner()
|
||||
}
|
||||
|
||||
/// Returns a query result when there is exactly one entity matching the query,
|
||||
@ -2107,6 +1676,8 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
///
|
||||
/// This does not check for mutable query correctness. To be safe, make sure mutable queries
|
||||
/// have unique access to the components they query.
|
||||
/// This does not validate that `world.id()` matches `self.world_id`. Calling this on a `world`
|
||||
/// with a mismatched [`WorldId`] is unsound.
|
||||
#[inline]
|
||||
pub unsafe fn get_single_unchecked_manual<'w>(
|
||||
&self,
|
||||
@ -2114,17 +1685,11 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
last_run: Tick,
|
||||
this_run: Tick,
|
||||
) -> Result<D::Item<'w>, QuerySingleError> {
|
||||
let mut query = self.iter_unchecked_manual(world, last_run, this_run);
|
||||
let first = query.next();
|
||||
let extra = query.next().is_some();
|
||||
|
||||
match (first, extra) {
|
||||
(Some(r), false) => Ok(r),
|
||||
(None, _) => Err(QuerySingleError::NoEntities(core::any::type_name::<Self>())),
|
||||
(Some(_), _) => Err(QuerySingleError::MultipleEntities(core::any::type_name::<
|
||||
Self,
|
||||
>())),
|
||||
}
|
||||
// SAFETY:
|
||||
// - The caller ensured we have the correct access to the world.
|
||||
// - The caller ensured that the world matches.
|
||||
self.query_unchecked_manual_with_ticks(world, last_run, this_run)
|
||||
.get_single_inner()
|
||||
}
|
||||
}
|
||||
|
||||
@ -2138,83 +1703,8 @@ impl<D: QueryData, F: QueryFilter> From<QueryBuilder<'_, D, F>> for QueryState<D
|
||||
mod tests {
|
||||
use crate::{
|
||||
component::Component, entity_disabling::DefaultQueryFilters, prelude::*,
|
||||
query::QueryEntityError, world::FilteredEntityRef,
|
||||
world::FilteredEntityRef,
|
||||
};
|
||||
use alloc::vec::Vec;
|
||||
|
||||
#[test]
|
||||
fn get_many_unchecked_manual_uniqueness() {
|
||||
let mut world = World::new();
|
||||
|
||||
let entities: Vec<Entity> = (0..10).map(|_| world.spawn_empty().id()).collect();
|
||||
|
||||
let query_state = world.query::<Entity>();
|
||||
|
||||
// These don't matter for the test
|
||||
let last_change_tick = world.last_change_tick();
|
||||
let change_tick = world.change_tick();
|
||||
|
||||
// It's best to test get_many_unchecked_manual directly,
|
||||
// as it is shared and unsafe
|
||||
// We don't care about aliased mutability for the read-only equivalent
|
||||
|
||||
// SAFETY: Query does not access world data.
|
||||
assert!(unsafe {
|
||||
query_state
|
||||
.get_many_unchecked_manual::<10>(
|
||||
world.as_unsafe_world_cell_readonly(),
|
||||
entities.clone().try_into().unwrap(),
|
||||
last_change_tick,
|
||||
change_tick,
|
||||
)
|
||||
.is_ok()
|
||||
});
|
||||
|
||||
assert_eq!(
|
||||
// SAFETY: Query does not access world data.
|
||||
unsafe {
|
||||
query_state
|
||||
.get_many_unchecked_manual(
|
||||
world.as_unsafe_world_cell_readonly(),
|
||||
[entities[0], entities[0]],
|
||||
last_change_tick,
|
||||
change_tick,
|
||||
)
|
||||
.unwrap_err()
|
||||
},
|
||||
QueryEntityError::AliasedMutability(entities[0])
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
// SAFETY: Query does not access world data.
|
||||
unsafe {
|
||||
query_state
|
||||
.get_many_unchecked_manual(
|
||||
world.as_unsafe_world_cell_readonly(),
|
||||
[entities[0], entities[1], entities[0]],
|
||||
last_change_tick,
|
||||
change_tick,
|
||||
)
|
||||
.unwrap_err()
|
||||
},
|
||||
QueryEntityError::AliasedMutability(entities[0])
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
// SAFETY: Query does not access world data.
|
||||
unsafe {
|
||||
query_state
|
||||
.get_many_unchecked_manual(
|
||||
world.as_unsafe_world_cell_readonly(),
|
||||
[entities[9], entities[9]],
|
||||
last_change_tick,
|
||||
change_tick,
|
||||
)
|
||||
.unwrap_err()
|
||||
},
|
||||
QueryEntityError::AliasedMutability(entities[9])
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
|
@ -3,14 +3,15 @@ use crate::{
|
||||
component::Tick,
|
||||
entity::{Entity, EntityBorrow, EntitySet},
|
||||
query::{
|
||||
QueryCombinationIter, QueryData, QueryEntityError, QueryFilter, QueryIter, QueryManyIter,
|
||||
QueryManyUniqueIter, QueryParIter, QueryParManyIter, QueryParManyUniqueIter,
|
||||
QuerySingleError, QueryState, ROQueryItem, ReadOnlyQueryData,
|
||||
DebugCheckedUnwrap, NopWorldQuery, QueryCombinationIter, QueryData, QueryEntityError,
|
||||
QueryFilter, QueryIter, QueryManyIter, QueryManyUniqueIter, QueryParIter, QueryParManyIter,
|
||||
QueryParManyUniqueIter, QuerySingleError, QueryState, ROQueryItem, ReadOnlyQueryData,
|
||||
},
|
||||
world::unsafe_world_cell::UnsafeWorldCell,
|
||||
};
|
||||
use core::{
|
||||
marker::PhantomData,
|
||||
mem::MaybeUninit,
|
||||
ops::{Deref, DerefMut},
|
||||
};
|
||||
|
||||
@ -439,6 +440,15 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
||||
unsafe { self.reborrow_unsafe() }.into_readonly()
|
||||
}
|
||||
|
||||
/// Returns another `Query` from this does not return any data, which can be faster.
|
||||
fn as_nop(&self) -> Query<'w, 's, NopWorldQuery<D>, F> {
|
||||
let new_state = self.state.as_nop();
|
||||
// SAFETY:
|
||||
// - This is memory safe because it performs no access.
|
||||
// - The world matches because it was the same one used to construct self.
|
||||
unsafe { Query::new(self.world, new_state, self.last_run, self.this_run) }
|
||||
}
|
||||
|
||||
/// Returns another `Query` from this that fetches the read-only version of the query items.
|
||||
///
|
||||
/// For example, `Query<(&mut D1, &D2, &mut D3), With<F>>` will become `Query<(&D1, &D2, &D3), With<F>>`.
|
||||
@ -498,6 +508,24 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
||||
///
|
||||
/// - [`reborrow`](Self::reborrow) for the safe versions.
|
||||
pub unsafe fn reborrow_unsafe(&self) -> Query<'_, 's, D, F> {
|
||||
// SAFETY:
|
||||
// - This is memory safe because the caller ensures that there are no conflicting references.
|
||||
// - The world matches because it was the same one used to construct self.
|
||||
unsafe { self.copy_unsafe() }
|
||||
}
|
||||
|
||||
/// Returns a new `Query` copying the access from this one.
|
||||
/// The current query will still be usable while the new one exists, but must not be used in a way that violates aliasing.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This function makes it possible to violate Rust's aliasing guarantees.
|
||||
/// You must make sure this call does not result in a mutable or shared reference to a component with a mutable reference.
|
||||
///
|
||||
/// # See also
|
||||
///
|
||||
/// - [`reborrow_unsafe`](Self::reborrow_unsafe) for a safer version that constrains the returned `'w` lifetime to the length of the borrow.
|
||||
unsafe fn copy_unsafe(&self) -> Query<'w, 's, D, F> {
|
||||
// SAFETY:
|
||||
// - This is memory safe because the caller ensures that there are no conflicting references.
|
||||
// - The world matches because it was the same one used to construct self.
|
||||
@ -653,10 +681,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
||||
#[inline]
|
||||
pub fn iter_combinations_inner<const K: usize>(self) -> QueryCombinationIter<'w, 's, D, F, K> {
|
||||
// SAFETY: `self.world` has permission to access the required components.
|
||||
unsafe {
|
||||
self.state
|
||||
.iter_combinations_unchecked_manual(self.world, self.last_run, self.this_run)
|
||||
}
|
||||
unsafe { QueryCombinationIter::new(self.world, self.state, self.last_run, self.this_run) }
|
||||
}
|
||||
|
||||
/// Returns an [`Iterator`] over the read-only query items generated from an [`Entity`] list.
|
||||
@ -766,9 +791,10 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
||||
) -> QueryManyIter<'w, 's, D, F, EntityList::IntoIter> {
|
||||
// SAFETY: `self.world` has permission to access the required components.
|
||||
unsafe {
|
||||
self.state.iter_many_unchecked_manual(
|
||||
entities,
|
||||
QueryManyIter::new(
|
||||
self.world,
|
||||
self.state,
|
||||
entities,
|
||||
self.last_run,
|
||||
self.this_run,
|
||||
)
|
||||
@ -822,22 +848,13 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
||||
/// # See also
|
||||
///
|
||||
/// - [`iter_many_unique_mut`](Self::iter_many_unique_mut) to get mutable query items.
|
||||
/// - [`iter_many_unique_inner`](Self::iter_many_unique_inner) to get with the actual "inner" world lifetime.
|
||||
#[inline]
|
||||
pub fn iter_many_unique<EntityList: EntitySet>(
|
||||
&self,
|
||||
entities: EntityList,
|
||||
) -> QueryManyUniqueIter<'_, 's, D::ReadOnly, F, EntityList::IntoIter> {
|
||||
// SAFETY:
|
||||
// - `self.world` has permission to access the required components.
|
||||
// - The query is read-only, so it can be aliased even if it was originally mutable.
|
||||
unsafe {
|
||||
self.state.as_readonly().iter_many_unique_unchecked_manual(
|
||||
entities,
|
||||
self.world,
|
||||
self.last_run,
|
||||
self.this_run,
|
||||
)
|
||||
}
|
||||
self.as_readonly().iter_many_unique_inner(entities)
|
||||
}
|
||||
|
||||
/// Returns an iterator over the unique query items generated from an [`EntitySet`].
|
||||
@ -883,16 +900,76 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
||||
/// }
|
||||
/// # bevy_ecs::system::assert_is_system(system);
|
||||
/// ```
|
||||
/// # See also
|
||||
///
|
||||
/// - [`iter_many_unique`](Self::iter_many_unique) to get read-only query items.
|
||||
/// - [`iter_many_unique_inner`](Self::iter_many_unique_inner) to get with the actual "inner" world lifetime.
|
||||
#[inline]
|
||||
pub fn iter_many_unique_mut<EntityList: EntitySet>(
|
||||
&mut self,
|
||||
entities: EntityList,
|
||||
) -> QueryManyUniqueIter<'_, 's, D, F, EntityList::IntoIter> {
|
||||
self.reborrow().iter_many_unique_inner(entities)
|
||||
}
|
||||
|
||||
/// Returns an iterator over the unique query items generated from an [`EntitySet`].
|
||||
/// This consumes the [`Query`] to return results with the actual "inner" world lifetime.
|
||||
///
|
||||
/// Items are returned in the order of the list of entities. Entities that don't match the query are skipped.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use bevy_ecs::{prelude::*, entity::{EntitySet, UniqueEntityIter}};
|
||||
/// # use core::slice;
|
||||
/// #[derive(Component)]
|
||||
/// struct Counter {
|
||||
/// value: i32
|
||||
/// }
|
||||
///
|
||||
/// // `Friends` ensures that it only lists unique entities.
|
||||
/// #[derive(Component)]
|
||||
/// struct Friends {
|
||||
/// unique_list: Vec<Entity>,
|
||||
/// }
|
||||
///
|
||||
/// impl<'a> IntoIterator for &'a Friends {
|
||||
/// type Item = &'a Entity;
|
||||
/// type IntoIter = UniqueEntityIter<slice::Iter<'a, Entity>>;
|
||||
///
|
||||
/// fn into_iter(self) -> Self::IntoIter {
|
||||
/// // SAFETY: `Friends` ensures that it unique_list contains only unique entities.
|
||||
/// unsafe { UniqueEntityIter::from_iterator_unchecked(self.unique_list.iter()) }
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// fn system(
|
||||
/// friends_query: Query<&Friends>,
|
||||
/// mut counter_query: Query<&mut Counter>,
|
||||
/// ) {
|
||||
/// let friends = friends_query.single();
|
||||
/// for mut counter in counter_query.iter_many_unique_inner(friends) {
|
||||
/// println!("Friend's counter: {:?}", counter.value);
|
||||
/// counter.value += 1;
|
||||
/// }
|
||||
/// }
|
||||
/// # bevy_ecs::system::assert_is_system(system);
|
||||
/// ```
|
||||
/// # See also
|
||||
///
|
||||
/// - [`iter_many_unique`](Self::iter_many_unique) to get read-only query items.
|
||||
/// - [`iter_many_unique_mut`](Self::iter_many_unique_mut) to get mutable query items.
|
||||
#[inline]
|
||||
pub fn iter_many_unique_inner<EntityList: EntitySet>(
|
||||
self,
|
||||
entities: EntityList,
|
||||
) -> QueryManyUniqueIter<'w, 's, D, F, EntityList::IntoIter> {
|
||||
// SAFETY: `self.world` has permission to access the required components.
|
||||
unsafe {
|
||||
self.state.iter_many_unique_unchecked_manual(
|
||||
entities,
|
||||
QueryManyUniqueIter::new(
|
||||
self.world,
|
||||
self.state,
|
||||
entities,
|
||||
self.last_run,
|
||||
self.this_run,
|
||||
)
|
||||
@ -972,22 +1049,15 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
||||
///
|
||||
/// # See also
|
||||
///
|
||||
/// - [`iter_many_mut`](Self::iter_many_mut) to safely access the query items.
|
||||
/// - [`iter_many_unique`](Self::iter_many_unique) to get read-only query items.
|
||||
/// - [`iter_many_unique_mut`](Self::iter_many_unique_mut) to get mutable query items.
|
||||
/// - [`iter_many_unique_inner`](Self::iter_many_unique_inner) to get with the actual "inner" world lifetime.
|
||||
pub unsafe fn iter_many_unique_unsafe<EntityList: EntitySet>(
|
||||
&self,
|
||||
entities: EntityList,
|
||||
) -> QueryManyUniqueIter<'_, 's, D, F, EntityList::IntoIter> {
|
||||
// SAFETY:
|
||||
// - `self.world` has permission to access the required components.
|
||||
// - The caller ensures that this operation will not result in any aliased mutable accesses.
|
||||
unsafe {
|
||||
self.state.iter_many_unique_unchecked_manual(
|
||||
entities,
|
||||
self.world,
|
||||
self.last_run,
|
||||
self.this_run,
|
||||
)
|
||||
}
|
||||
// SAFETY: The caller promises that this will not result in multiple mutable references.
|
||||
unsafe { self.reborrow_unsafe() }.iter_many_unique_inner(entities)
|
||||
}
|
||||
|
||||
/// Returns a parallel iterator over the query results for the given [`World`].
|
||||
@ -1214,6 +1284,39 @@ 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.
|
||||
/// The elements of the array do not need to be unique, unlike `get_many_mut`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use bevy_ecs::prelude::*;
|
||||
/// use bevy_ecs::query::QueryEntityError;
|
||||
///
|
||||
/// #[derive(Component, PartialEq, Debug)]
|
||||
/// struct A(usize);
|
||||
///
|
||||
/// let mut world = World::new();
|
||||
/// let entity_vec: Vec<Entity> = (0..3).map(|i| world.spawn(A(i)).id()).collect();
|
||||
/// let entities: [Entity; 3] = entity_vec.try_into().unwrap();
|
||||
///
|
||||
/// world.spawn(A(73));
|
||||
///
|
||||
/// let mut query_state = world.query::<&A>();
|
||||
/// let query = query_state.query(&world);
|
||||
///
|
||||
/// let component_values = query.get_many(entities).unwrap();
|
||||
///
|
||||
/// assert_eq!(component_values, [&A(0), &A(1), &A(2)]);
|
||||
///
|
||||
/// let wrong_entity = Entity::from_raw(365);
|
||||
///
|
||||
/// assert_eq!(
|
||||
/// match query.get_many([wrong_entity]).unwrap_err() {
|
||||
/// QueryEntityError::NoSuchEntity(entity, _) => entity,
|
||||
/// _ => panic!(),
|
||||
/// },
|
||||
/// wrong_entity
|
||||
/// );
|
||||
/// ```
|
||||
///
|
||||
/// # See also
|
||||
///
|
||||
/// - [`get_many_mut`](Self::get_many_mut) to get mutable query items.
|
||||
@ -1327,8 +1430,55 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
||||
// SAFETY: system runs without conflicts with other systems.
|
||||
// same-system queries have runtime borrow checks when they conflict
|
||||
unsafe {
|
||||
self.state
|
||||
.get_unchecked_manual(self.world, entity, self.last_run, self.this_run)
|
||||
let location =
|
||||
self.world
|
||||
.entities()
|
||||
.get(entity)
|
||||
.ok_or(QueryEntityError::NoSuchEntity(
|
||||
entity,
|
||||
self.world
|
||||
.entities()
|
||||
.entity_does_not_exist_error_details(entity),
|
||||
))?;
|
||||
if !self
|
||||
.state
|
||||
.matched_archetypes
|
||||
.contains(location.archetype_id.index())
|
||||
{
|
||||
return Err(QueryEntityError::QueryDoesNotMatch(entity, self.world));
|
||||
}
|
||||
let archetype = self
|
||||
.world
|
||||
.archetypes()
|
||||
.get(location.archetype_id)
|
||||
.debug_checked_unwrap();
|
||||
let mut fetch = D::init_fetch(
|
||||
self.world,
|
||||
&self.state.fetch_state,
|
||||
self.last_run,
|
||||
self.this_run,
|
||||
);
|
||||
let mut filter = F::init_fetch(
|
||||
self.world,
|
||||
&self.state.filter_state,
|
||||
self.last_run,
|
||||
self.this_run,
|
||||
);
|
||||
|
||||
let table = self
|
||||
.world
|
||||
.storages()
|
||||
.tables
|
||||
.get(location.table_id)
|
||||
.debug_checked_unwrap();
|
||||
D::set_archetype(&mut fetch, &self.state.fetch_state, archetype, table);
|
||||
F::set_archetype(&mut filter, &self.state.filter_state, archetype, table);
|
||||
|
||||
if F::filter_fetch(&mut filter, entity, location.table_row) {
|
||||
Ok(D::fetch(&mut fetch, entity, location.table_row))
|
||||
} else {
|
||||
Err(QueryEntityError::QueryDoesNotMatch(entity, self.world))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1337,6 +1487,65 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
||||
/// The returned query items are in the same order as the input.
|
||||
/// In case of a nonexisting entity, duplicate entities or mismatched component, a [`QueryEntityError`] is returned instead.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use bevy_ecs::prelude::*;
|
||||
/// use bevy_ecs::query::QueryEntityError;
|
||||
///
|
||||
/// #[derive(Component, PartialEq, Debug)]
|
||||
/// struct A(usize);
|
||||
///
|
||||
/// let mut world = World::new();
|
||||
///
|
||||
/// let entities: Vec<Entity> = (0..3).map(|i| world.spawn(A(i)).id()).collect();
|
||||
/// let entities: [Entity; 3] = entities.try_into().unwrap();
|
||||
///
|
||||
/// world.spawn(A(73));
|
||||
/// let wrong_entity = Entity::from_raw(57);
|
||||
/// let invalid_entity = world.spawn_empty().id();
|
||||
///
|
||||
///
|
||||
/// let mut query_state = world.query::<&mut A>();
|
||||
/// let mut query = query_state.query_mut(&mut world);
|
||||
///
|
||||
/// let mut mutable_component_values = query.get_many_mut(entities).unwrap();
|
||||
///
|
||||
/// for mut a in &mut mutable_component_values {
|
||||
/// a.0 += 5;
|
||||
/// }
|
||||
///
|
||||
/// let component_values = query.get_many(entities).unwrap();
|
||||
///
|
||||
/// assert_eq!(component_values, [&A(5), &A(6), &A(7)]);
|
||||
///
|
||||
/// assert_eq!(
|
||||
/// match query
|
||||
/// .get_many_mut([wrong_entity])
|
||||
/// .unwrap_err()
|
||||
/// {
|
||||
/// QueryEntityError::NoSuchEntity(entity, _) => entity,
|
||||
/// _ => panic!(),
|
||||
/// },
|
||||
/// wrong_entity
|
||||
/// );
|
||||
/// assert_eq!(
|
||||
/// match query
|
||||
/// .get_many_mut([invalid_entity])
|
||||
/// .unwrap_err()
|
||||
/// {
|
||||
/// QueryEntityError::QueryDoesNotMatch(entity, _) => entity,
|
||||
/// _ => panic!(),
|
||||
/// },
|
||||
/// invalid_entity
|
||||
/// );
|
||||
/// assert_eq!(
|
||||
/// query
|
||||
/// .get_many_mut([entities[0], entities[0]])
|
||||
/// .unwrap_err(),
|
||||
/// QueryEntityError::AliasedMutability(entities[0])
|
||||
/// );
|
||||
/// ```
|
||||
/// # See also
|
||||
///
|
||||
/// - [`get_many`](Self::get_many) to get read-only query items without checking for duplicate entities.
|
||||
@ -1366,11 +1575,17 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
||||
self,
|
||||
entities: [Entity; N],
|
||||
) -> Result<[D::Item<'w>; N], QueryEntityError<'w>> {
|
||||
// SAFETY: scheduler ensures safe Query world access
|
||||
unsafe {
|
||||
self.state
|
||||
.get_many_unchecked_manual(self.world, entities, self.last_run, self.this_run)
|
||||
// Verify that all entities are unique
|
||||
for i in 0..N {
|
||||
for j in 0..i {
|
||||
if entities[i] == entities[j] {
|
||||
return Err(QueryEntityError::AliasedMutability(entities[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SAFETY: All entities are unique, so the results don't alias.
|
||||
unsafe { self.get_many_impl(entities) }
|
||||
}
|
||||
|
||||
/// Returns the query items for the given array of [`Entity`].
|
||||
@ -1392,11 +1607,31 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
||||
where
|
||||
D: ReadOnlyQueryData,
|
||||
{
|
||||
// SAFETY: scheduler ensures safe Query world access
|
||||
unsafe {
|
||||
self.state
|
||||
.get_many_read_only_manual(self.world, entities, self.last_run, self.this_run)
|
||||
// SAFETY: The query results are read-only, so they don't conflict if there are duplicate entities.
|
||||
unsafe { self.get_many_impl(entities) }
|
||||
}
|
||||
|
||||
/// Returns the query items for the given array of [`Entity`].
|
||||
/// This consumes the [`Query`] to return results with the actual "inner" world lifetime.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller must ensure that the query data returned for the entities does not conflict,
|
||||
/// either because they are all unique or because the data is read-only.
|
||||
unsafe fn get_many_impl<const N: usize>(
|
||||
self,
|
||||
entities: [Entity; N],
|
||||
) -> Result<[D::Item<'w>; N], QueryEntityError<'w>> {
|
||||
let mut values = [(); N].map(|_| MaybeUninit::uninit());
|
||||
|
||||
for (value, entity) in core::iter::zip(&mut values, entities) {
|
||||
// SAFETY: The caller asserts that the results don't alias
|
||||
let item = unsafe { self.copy_unsafe() }.get_inner(entity)?;
|
||||
*value = MaybeUninit::new(item);
|
||||
}
|
||||
|
||||
// SAFETY: Each value has been fully initialized.
|
||||
Ok(values.map(|x| unsafe { x.assume_init() }))
|
||||
}
|
||||
|
||||
/// Returns the query items for the given array of [`Entity`].
|
||||
@ -1604,6 +1839,40 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
||||
self.reborrow().get_single_inner()
|
||||
}
|
||||
|
||||
/// Returns a single query item when there is exactly one entity matching the query.
|
||||
/// This consumes the [`Query`] to return results with the actual "inner" world lifetime.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// This method panics if the number of query items is **not** exactly one.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use bevy_ecs::prelude::*;
|
||||
/// #
|
||||
/// # #[derive(Component)]
|
||||
/// # struct Player;
|
||||
/// # #[derive(Component)]
|
||||
/// # struct Health(u32);
|
||||
/// #
|
||||
/// fn regenerate_player_health_system(query: Query<&mut Health, With<Player>>) {
|
||||
/// let mut health = query.single_inner();
|
||||
/// health.0 += 1;
|
||||
/// }
|
||||
/// # bevy_ecs::system::assert_is_system(regenerate_player_health_system);
|
||||
/// ```
|
||||
///
|
||||
/// # See also
|
||||
///
|
||||
/// - [`get_single_inner`](Self::get_single_inner) for the non-panicking version.
|
||||
/// - [`single`](Self::single) to get the read-only query item.
|
||||
/// - [`single_mut`](Self::single_mut) to get the mutable query item.
|
||||
#[track_caller]
|
||||
pub fn single_inner(self) -> D::Item<'w> {
|
||||
self.get_single_inner().unwrap()
|
||||
}
|
||||
|
||||
/// Returns a single query item when there is exactly one entity matching the query.
|
||||
/// This consumes the [`Query`] to return results with the actual "inner" world lifetime.
|
||||
///
|
||||
@ -1630,14 +1899,19 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
||||
///
|
||||
/// - [`get_single`](Self::get_single) to get the read-only query item.
|
||||
/// - [`get_single_mut`](Self::get_single_mut) to get the mutable query item.
|
||||
/// - [`single_inner`](Self::single_inner) for the panicking version.
|
||||
#[inline]
|
||||
pub fn get_single_inner(self) -> Result<D::Item<'w>, QuerySingleError> {
|
||||
// SAFETY:
|
||||
// the query ensures mutable access to the components it accesses, and the query
|
||||
// is uniquely borrowed
|
||||
unsafe {
|
||||
self.state
|
||||
.get_single_unchecked_manual(self.world, self.last_run, self.this_run)
|
||||
let mut query = self.into_iter();
|
||||
let first = query.next();
|
||||
let extra = query.next().is_some();
|
||||
|
||||
match (first, extra) {
|
||||
(Some(r), false) => Ok(r),
|
||||
(None, _) => Err(QuerySingleError::NoEntities(core::any::type_name::<Self>())),
|
||||
(Some(_), _) => Err(QuerySingleError::MultipleEntities(core::any::type_name::<
|
||||
Self,
|
||||
>())),
|
||||
}
|
||||
}
|
||||
|
||||
@ -1671,14 +1945,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
||||
/// [`Changed`]: crate::query::Changed
|
||||
#[inline]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
// SAFETY:
|
||||
// - `self.world` has permission to read any data required by the WorldQuery.
|
||||
// - `&self` ensures that no one currently has write access.
|
||||
// - `self.world` matches `self.state`.
|
||||
unsafe {
|
||||
self.state
|
||||
.is_empty_unsafe_world_cell(self.world, self.last_run, self.this_run)
|
||||
}
|
||||
self.as_nop().iter().next().is_none()
|
||||
}
|
||||
|
||||
/// Returns `true` if the given [`Entity`] matches the query.
|
||||
@ -1707,13 +1974,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn contains(&self, entity: Entity) -> bool {
|
||||
// SAFETY: NopFetch does not access any members while &self ensures no one has exclusive access
|
||||
unsafe {
|
||||
self.state
|
||||
.as_nop()
|
||||
.get_unchecked_manual(self.world, entity, self.last_run, self.this_run)
|
||||
.is_ok()
|
||||
}
|
||||
self.as_nop().get(entity).is_ok()
|
||||
}
|
||||
|
||||
/// Returns a [`QueryLens`] that can be used to get a query with a more general fetch.
|
||||
@ -2148,10 +2409,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> IntoIterator for Query<'w, 's, D, F>
|
||||
// - `self.world` has permission to access the required components.
|
||||
// - We consume the query, so mutable queries cannot alias.
|
||||
// Read-only queries are `Copy`, but may alias themselves.
|
||||
unsafe {
|
||||
self.state
|
||||
.iter_unchecked_manual(self.world, self.last_run, self.this_run)
|
||||
}
|
||||
unsafe { QueryIter::new(self.world, self.state, self.last_run, self.this_run) }
|
||||
}
|
||||
}
|
||||
|
||||
@ -2325,3 +2583,51 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Populated<'w, 's, D, F> {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{prelude::*, query::QueryEntityError};
|
||||
use alloc::vec::Vec;
|
||||
|
||||
#[test]
|
||||
fn get_many_uniqueness() {
|
||||
let mut world = World::new();
|
||||
|
||||
let entities: Vec<Entity> = (0..10).map(|_| world.spawn_empty().id()).collect();
|
||||
|
||||
let mut query_state = world.query::<Entity>();
|
||||
|
||||
// It's best to test get_many_inner directly, as it is shared
|
||||
// We don't care about aliased mutability for the read-only equivalent
|
||||
|
||||
// SAFETY: Query does not access world data.
|
||||
assert!(query_state
|
||||
.query_mut(&mut world)
|
||||
.get_many_inner::<10>(entities.clone().try_into().unwrap())
|
||||
.is_ok());
|
||||
|
||||
assert_eq!(
|
||||
query_state
|
||||
.query_mut(&mut world)
|
||||
.get_many_inner([entities[0], entities[0]])
|
||||
.unwrap_err(),
|
||||
QueryEntityError::AliasedMutability(entities[0])
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
query_state
|
||||
.query_mut(&mut world)
|
||||
.get_many_inner([entities[0], entities[1], entities[0]])
|
||||
.unwrap_err(),
|
||||
QueryEntityError::AliasedMutability(entities[0])
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
query_state
|
||||
.query_mut(&mut world)
|
||||
.get_many_inner([entities[9], entities[9]])
|
||||
.unwrap_err(),
|
||||
QueryEntityError::AliasedMutability(entities[9])
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -333,6 +333,7 @@ unsafe impl<D: QueryData + 'static, F: QueryFilter + 'static> SystemParam for Qu
|
||||
// SAFETY: We have registered all of the query's world accesses,
|
||||
// so the caller ensures that `world` has permission to access any
|
||||
// world data that the query needs.
|
||||
// The caller ensures the world matches the one used in init_state.
|
||||
unsafe { state.query_unchecked_manual_with_ticks(world, system_meta.last_run, change_tick) }
|
||||
}
|
||||
}
|
||||
@ -401,8 +402,8 @@ unsafe impl<'a, D: QueryData + 'static, F: QueryFilter + 'static> SystemParam fo
|
||||
world: UnsafeWorldCell<'w>,
|
||||
change_tick: Tick,
|
||||
) -> Self::Item<'w, 's> {
|
||||
state.validate_world(world.id());
|
||||
// SAFETY: State ensures that the components it accesses are not accessible somewhere elsewhere.
|
||||
// The caller ensures the world matches the one used in init_state.
|
||||
let query = unsafe {
|
||||
state.query_unchecked_manual_with_ticks(world, system_meta.last_run, change_tick)
|
||||
};
|
||||
@ -421,9 +422,9 @@ unsafe impl<'a, D: QueryData + 'static, F: QueryFilter + 'static> SystemParam fo
|
||||
system_meta: &SystemMeta,
|
||||
world: UnsafeWorldCell,
|
||||
) -> bool {
|
||||
state.validate_world(world.id());
|
||||
// SAFETY: State ensures that the components it accesses are not mutably accessible elsewhere
|
||||
// and the query is read only.
|
||||
// The caller ensures the world matches the one used in init_state.
|
||||
let query = unsafe {
|
||||
state.query_unchecked_manual_with_ticks(
|
||||
world,
|
||||
@ -469,6 +470,7 @@ unsafe impl<'a, D: QueryData + 'static, F: QueryFilter + 'static> SystemParam
|
||||
) -> Self::Item<'w, 's> {
|
||||
state.validate_world(world.id());
|
||||
// SAFETY: State ensures that the components it accesses are not accessible elsewhere.
|
||||
// The caller ensures the world matches the one used in init_state.
|
||||
let query = unsafe {
|
||||
state.query_unchecked_manual_with_ticks(world, system_meta.last_run, change_tick)
|
||||
};
|
||||
@ -488,9 +490,9 @@ unsafe impl<'a, D: QueryData + 'static, F: QueryFilter + 'static> SystemParam
|
||||
system_meta: &SystemMeta,
|
||||
world: UnsafeWorldCell,
|
||||
) -> bool {
|
||||
state.validate_world(world.id());
|
||||
// SAFETY: State ensures that the components it accesses are not mutably accessible elsewhere
|
||||
// and the query is read only.
|
||||
// The caller ensures the world matches the one used in init_state.
|
||||
let query = unsafe {
|
||||
state.query_unchecked_manual_with_ticks(
|
||||
world,
|
||||
@ -558,13 +560,17 @@ unsafe impl<D: QueryData + 'static, F: QueryFilter + 'static> SystemParam
|
||||
system_meta: &SystemMeta,
|
||||
world: UnsafeWorldCell,
|
||||
) -> bool {
|
||||
state.validate_world(world.id());
|
||||
// SAFETY:
|
||||
// - We have read-only access to the components accessed by query.
|
||||
// - The world has been validated.
|
||||
!unsafe {
|
||||
state.is_empty_unsafe_world_cell(world, system_meta.last_run, world.change_tick())
|
||||
}
|
||||
// - The caller ensures the world matches the one used in init_state.
|
||||
let query = unsafe {
|
||||
state.query_unchecked_manual_with_ticks(
|
||||
world,
|
||||
system_meta.last_run,
|
||||
world.change_tick(),
|
||||
)
|
||||
};
|
||||
!query.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user