Introduce methods on QueryState to obtain a Query (#15858)

# Objective

Simplify and expand the API for `QueryState`.  

`QueryState` has a lot of methods that mirror those on `Query`. These
are then multiplied by variants that take `&World`, `&mut World`, and
`UnsafeWorldCell`. In addition, many of them have `_manual` variants
that take `&QueryState` and avoid calling `update_archetypes()`. Not all
of the combinations exist, however, so some operations are not possible.

## Solution

Introduce methods to get a `Query` from a `QueryState`. That will reduce
duplication between the types, and ensure that the full `Query` API is
always available for `QueryState`.

Introduce methods on `Query` that consume the query to return types with
the full `'w` lifetime. This avoids issues with borrowing where things
like `query_state.query(&world).get(entity)` don't work because they
borrow from the temporary `Query`.

Finally, implement `Copy` for read-only `Query`s. `get_inner` and
`iter_inner` currently take `&self`, so changing them to consume `self`
would be a breaking change. By making `Query: Copy`, they can consume a
copy of `self` and continue to work.

The consuming methods also let us simplify the implementation of methods
on `Query`, by doing `fn foo(&self) { self.as_readonly().foo_inner() }`
and `fn foo_mut(&mut self) { self.reborrow().foo_inner() }`. That
structure makes it more difficult to accidentally extend lifetimes,
since the safe `as_readonly()` and `reborrow()` methods shrink them
appropriately. The optimizer is able to see that they are both identity
functions and inline them, so there should be no performance cost.

Note that this change would conflict with #15848. If `QueryState` is
stored as a `Cow`, then the consuming methods cannot be implemented, and
`Copy` cannot be implemented.

## Future Work

The next step is to mark the methods on `QueryState` as `#[deprecated]`,
and move the implementations into `Query`.

## Migration Guide

`Query::to_readonly` has been renamed to `Query::as_readonly`.
This commit is contained in:
Chris Russell 2025-02-05 13:33:15 -05:00 committed by GitHub
parent 2ea5e9b846
commit 6f39e44c48
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 548 additions and 243 deletions

View File

@ -6,29 +6,29 @@ struct Foo;
fn for_loops(mut query: Query<&mut Foo>) {
// this should fail to compile
for _ in query.iter_mut() {
for _ in query.to_readonly().iter() {}
for _ in query.as_readonly().iter() {}
//~^ E0502
}
// this should fail to compile
for _ in query.to_readonly().iter() {
for _ in query.as_readonly().iter() {
for _ in query.iter_mut() {}
//~^ E0502
}
// this should *not* fail to compile
for _ in query.to_readonly().iter() {
for _ in query.to_readonly().iter() {}
for _ in query.as_readonly().iter() {
for _ in query.as_readonly().iter() {}
}
// this should *not* fail to compile
for _ in query.to_readonly().iter() {
for _ in query.as_readonly().iter() {
for _ in query.iter() {}
}
// this should *not* fail to compile
for _ in query.iter() {
for _ in query.to_readonly().iter() {}
for _ in query.as_readonly().iter() {}
}
}
@ -38,11 +38,11 @@ fn single_mut_query(mut query: Query<&mut Foo>) {
let mut mut_foo = query.single_mut();
// This solves "temporary value dropped while borrowed"
let readonly_query = query.to_readonly();
let readonly_query = query.as_readonly();
//~^ E0502
let ref_foo = readonly_query.single();
*mut_foo = Foo;
println!("{ref_foo:?}");
@ -51,7 +51,7 @@ fn single_mut_query(mut query: Query<&mut Foo>) {
// this should fail to compile
{
// This solves "temporary value dropped while borrowed"
let readonly_query = query.to_readonly();
let readonly_query = query.as_readonly();
let ref_foo = readonly_query.single();
@ -66,7 +66,7 @@ fn single_mut_query(mut query: Query<&mut Foo>) {
// this should *not* fail to compile
{
// This solves "temporary value dropped while borrowed"
let readonly_query = query.to_readonly();
let readonly_query = query.as_readonly();
let readonly_foo = readonly_query.single();

View File

@ -849,13 +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.
let query_lens = unsafe {
query_lens_state.iter_unchecked_manual(
world,
world.last_change_tick(),
world.change_tick(),
)
};
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)))
.collect();
@ -1689,14 +1683,8 @@ 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.
let query_lens = unsafe {
query_lens_state.iter_many_unchecked_manual(
self.entity_iter,
world,
world.last_change_tick(),
world.change_tick(),
)
};
let query_lens = unsafe { query_lens_state.query_unchecked_manual(world) }
.iter_many_inner(self.entity_iter);
let mut keyed_query: Vec<_> = query_lens
.map(|(key, entity)| (key, NeutralOrd(entity)))
.collect();

View File

@ -10,6 +10,7 @@ use crate::{
WorldQuery,
},
storage::{SparseSetIndex, TableId},
system::Query,
world::{unsafe_world_cell::UnsafeWorldCell, World, WorldId},
};
@ -154,9 +155,7 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
pub fn matched_archetypes(&self) -> impl Iterator<Item = ArchetypeId> + '_ {
self.matched_archetypes.ones().map(ArchetypeId::new)
}
}
impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
/// Creates a new [`QueryState`] from a given [`World`] and inherits the result of `world.id()`.
pub fn new(world: &mut World) -> Self {
let mut state = Self::new_uninitialized(world);
@ -319,6 +318,124 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
state
}
/// Creates a [`Query`] from the given [`QueryState`] and [`World`].
///
/// This will create read-only queries, see [`Self::query_mut`] for mutable queries.
pub fn query<'w, 's>(&'s mut self, world: &'w World) -> Query<'w, 's, D::ReadOnly, F> {
self.update_archetypes(world);
self.query_manual(world)
}
/// Creates a [`Query`] from the given [`QueryState`] and [`World`].
///
/// This method is slightly more efficient than [`QueryState::query`] in some situations, since
/// it does not update this instance's internal cache. The resulting query may skip an entity that
/// belongs to an archetype that has not been cached.
///
/// To ensure that the cache is up to date, call [`QueryState::update_archetypes`] before this method.
/// The cache is also updated in [`QueryState::new`], [`QueryState::get`], or any method with mutable
/// access to `self`.
///
/// 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.
unsafe {
self.as_readonly()
.query_unchecked_manual(world.as_unsafe_world_cell_readonly())
}
}
/// Creates a [`Query`] from the given [`QueryState`] and [`World`].
pub fn query_mut<'w, 's>(&'s mut self, world: &'w mut World) -> Query<'w, 's, D, F> {
let last_run = world.last_change_tick();
let this_run = world.change_tick();
// SAFETY: We have exclusive access to the entire world.
unsafe { self.query_unchecked_with_ticks(world.as_unsafe_world_cell(), last_run, this_run) }
}
/// Creates a [`Query`] from the given [`QueryState`] and [`World`].
///
/// # Safety
///
/// This does not check for mutable query correctness. To be safe, make sure mutable queries
/// have unique access to the components they query.
pub unsafe fn query_unchecked<'w, 's>(
&'s mut self,
world: UnsafeWorldCell<'w>,
) -> Query<'w, 's, D, F> {
self.update_archetypes_unsafe_world_cell(world);
// SAFETY: Caller ensures we have the required access
unsafe { self.query_unchecked_manual(world) }
}
/// Creates a [`Query`] from the given [`QueryState`] and [`World`].
///
/// This method is slightly more efficient than [`QueryState::query_unchecked`] in some situations, since
/// it does not update this instance's internal cache. The resulting query may skip an entity that
/// belongs to an archetype that has not been cached.
///
/// To ensure that the cache is up to date, call [`QueryState::update_archetypes`] before this method.
/// The cache is also updated in [`QueryState::new`], [`QueryState::get`], or any method with mutable
/// access to `self`.
///
/// # Safety
///
/// This does not check for mutable query correctness. To be safe, make sure mutable queries
/// have unique access to the components they query.
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.
unsafe { self.query_unchecked_manual_with_ticks(world, last_run, this_run) }
}
/// Creates a [`Query`] from the given [`QueryState`] and [`World`].
///
/// # Safety
///
/// This does not check for mutable query correctness. To be safe, make sure mutable queries
/// have unique access to the components they query.
pub unsafe fn query_unchecked_with_ticks<'w, 's>(
&'s mut self,
world: UnsafeWorldCell<'w>,
last_run: Tick,
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.
unsafe { self.query_unchecked_manual_with_ticks(world, last_run, this_run) }
}
/// Creates a [`Query`] from the given [`QueryState`] and [`World`].
///
/// This method is slightly more efficient than [`QueryState::query_unchecked_with_ticks`] in some situations, since
/// it does not update this instance's internal cache. The resulting query may skip an entity that
/// belongs to an archetype that has not been cached.
///
/// To ensure that the cache is up to date, call [`QueryState::update_archetypes`] before this method.
/// The cache is also updated in [`QueryState::new`], [`QueryState::get`], or any method with mutable
/// access to `self`.
///
/// # Safety
///
/// This does not check for mutable query correctness. To be safe, make sure mutable queries
/// have unique access to the components they query.
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.
unsafe { Query::new(world, self, last_run, this_run) }
}
/// Checks if the query is empty for the given [`World`], where the last change and current tick are given.
///
/// This is equivalent to `self.iter().next().is_none()`, and thus the worst case runtime will be `O(n)`
@ -624,7 +741,7 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
/// You should not call [`update_archetypes`](Self::update_archetypes) on the returned [`QueryState`] as the result will be unpredictable.
/// You might end up with a mix of archetypes that only matched the original query + archetypes that only match
/// the new [`QueryState`]. Most of the safe methods on [`QueryState`] call [`QueryState::update_archetypes`] internally, so this
/// best used through a [`Query`](crate::system::Query).
/// best used through a [`Query`]
pub fn transmute<'a, NewD: QueryData>(
&self,
world: impl Into<UnsafeWorldCell<'a>>,

View File

@ -334,7 +334,7 @@ mod tests {
archetype::{ArchetypeComponentId, Archetypes},
bundle::Bundles,
change_detection::DetectChanges,
component::{Component, Components, Tick},
component::{Component, Components},
entity::{Entities, Entity},
prelude::{AnyOf, EntityRef},
query::{Added, Changed, Or, With, Without},
@ -1361,7 +1361,7 @@ mod tests {
fn mutable_query(mut query: Query<&mut A>) {
for _ in &mut query {}
immutable_query(query.to_readonly());
immutable_query(query.as_readonly());
}
fn immutable_query(_: Query<&A>) {}
@ -1376,7 +1376,7 @@ mod tests {
fn mutable_query(mut query: Query<Option<&mut A>>) {
for _ in &mut query {}
immutable_query(query.to_readonly());
immutable_query(query.as_readonly());
}
fn immutable_query(_: Query<Option<&A>>) {}
@ -1391,7 +1391,7 @@ mod tests {
fn mutable_query(mut query: Query<(&mut A, &B)>) {
for _ in &mut query {}
immutable_query(query.to_readonly());
immutable_query(query.as_readonly());
}
fn immutable_query(_: Query<(&A, &B)>) {}
@ -1406,7 +1406,7 @@ mod tests {
fn mutable_query(mut query: Query<(&mut A, &mut B)>) {
for _ in &mut query {}
immutable_query(query.to_readonly());
immutable_query(query.as_readonly());
}
fn immutable_query(_: Query<(&A, &B)>) {}
@ -1421,7 +1421,7 @@ mod tests {
fn mutable_query(mut query: Query<(&mut A, &mut B), With<C>>) {
for _ in &mut query {}
immutable_query(query.to_readonly());
immutable_query(query.as_readonly());
}
fn immutable_query(_: Query<(&A, &B), With<C>>) {}
@ -1436,7 +1436,7 @@ mod tests {
fn mutable_query(mut query: Query<(&mut A, &mut B), Without<C>>) {
for _ in &mut query {}
immutable_query(query.to_readonly());
immutable_query(query.as_readonly());
}
fn immutable_query(_: Query<(&A, &B), Without<C>>) {}
@ -1451,7 +1451,7 @@ mod tests {
fn mutable_query(mut query: Query<(&mut A, &mut B), Added<C>>) {
for _ in &mut query {}
immutable_query(query.to_readonly());
immutable_query(query.as_readonly());
}
fn immutable_query(_: Query<(&A, &B), Added<C>>) {}
@ -1466,7 +1466,7 @@ mod tests {
fn mutable_query(mut query: Query<(&mut A, &mut B), Changed<C>>) {
for _ in &mut query {}
immutable_query(query.to_readonly());
immutable_query(query.as_readonly());
}
fn immutable_query(_: Query<(&A, &B), Changed<C>>) {}
@ -1572,24 +1572,6 @@ mod tests {
});
}
#[test]
#[should_panic = "Encountered a mismatched World."]
fn query_validates_world_id() {
let mut world1 = World::new();
let world2 = World::new();
let qstate = world1.query::<()>();
// SAFETY: doesnt access anything
let query = unsafe {
Query::new(
world2.as_unsafe_world_cell_readonly(),
&qstate,
Tick::new(0),
Tick::new(0),
)
};
query.iter();
}
#[test]
#[should_panic]
fn assert_system_does_not_conflict() {

View File

@ -381,6 +381,14 @@ pub struct Query<'world, 'state, D: QueryData, F: QueryFilter = ()> {
this_run: Tick,
}
impl<D: ReadOnlyQueryData, F: QueryFilter> Clone for Query<'_, '_, D, F> {
fn clone(&self) -> Self {
*self
}
}
impl<D: ReadOnlyQueryData, F: QueryFilter> Copy for Query<'_, '_, D, F> {}
impl<D: QueryData, F: QueryFilter> core::fmt::Debug for Query<'_, '_, D, F> {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
f.debug_struct("Query")
@ -396,14 +404,11 @@ impl<D: QueryData, F: QueryFilter> core::fmt::Debug for Query<'_, '_, D, F> {
impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
/// Creates a new query.
///
/// # Panics
///
/// This will panic if the world used to create `state` is not `world`.
///
/// # Safety
///
/// This will create a query that could violate memory safety rules. Make sure that this is only
/// called in ways that ensure the queries have unique mutable access.
/// * This will create a query that could violate memory safety rules. Make sure that this is only
/// called in ways that ensure the queries have unique mutable access.
/// * `world` must be the world used to create `state`.
#[inline]
pub(crate) unsafe fn new(
world: UnsafeWorldCell<'w>,
@ -411,8 +416,6 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
last_run: Tick,
this_run: Tick,
) -> Self {
state.validate_world(world.id());
Self {
world,
state,
@ -426,9 +429,30 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
/// For example, `Query<(&mut D1, &D2, &mut D3), With<F>>` will become `Query<(&D1, &D2, &D3), With<F>>`.
/// This can be useful when working around the borrow checker,
/// or reusing functionality between systems via functions that accept query types.
pub fn to_readonly(&self) -> Query<'_, 's, D::ReadOnly, F> {
///
/// # See also
///
/// [`into_readonly`](Self::into_readonly) for a version that consumes the `Query` to return one with the full `'world` lifetime.
pub fn as_readonly(&self) -> Query<'_, 's, D::ReadOnly, F> {
// SAFETY: The reborrowed query is converted to read-only, so it cannot perform mutable access,
// and the original query is held with a shared borrow, so it cannot perform mutable access either.
unsafe { self.reborrow_unsafe() }.into_readonly()
}
/// 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>>`.
/// This can be useful when working around the borrow checker,
/// or reusing functionality between systems via functions that accept query types.
///
/// # See also
///
/// [`as_readonly`](Self::as_readonly) for a version that borrows the `Query` instead of consuming it.
pub fn into_readonly(self) -> Query<'w, 's, D::ReadOnly, F> {
let new_state = self.state.as_readonly();
// SAFETY: This is memory safe because it turns the query immutable.
// SAFETY:
// - This is memory safe because it turns the query immutable.
// - 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) }
}
@ -459,6 +483,24 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
pub fn reborrow(&mut self) -> Query<'_, 's, D, F> {
// SAFETY: this query is exclusively borrowed while the new one exists, so
// no overlapping access can occur.
unsafe { self.reborrow_unsafe() }
}
/// Returns a new `Query` reborrowing 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`](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 { Query::new(self.world, self.state, self.last_run, self.this_run) }
}
@ -490,14 +532,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
/// [`iter_mut`](Self::iter_mut) for mutable query items.
#[inline]
pub fn iter(&self) -> QueryIter<'_, 's, D::ReadOnly, F> {
// 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_unchecked_manual(self.world, self.last_run, self.this_run)
}
self.as_readonly().into_iter()
}
/// Returns an [`Iterator`] over the query items.
@ -528,11 +563,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
/// [`iter`](Self::iter) for read-only query items.
#[inline]
pub fn iter_mut(&mut self) -> QueryIter<'_, 's, D, F> {
// SAFETY: `self.world` has permission to access the required components.
unsafe {
self.state
.iter_unchecked_manual(self.world, self.last_run, self.this_run)
}
self.reborrow().into_iter()
}
/// Returns a [`QueryCombinationIter`] over all combinations of `K` read-only query items without repetition.
@ -557,20 +588,12 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
/// # See also
///
/// - [`iter_combinations_mut`](Self::iter_combinations_mut) for mutable query item combinations.
/// - [`iter_combinations_inner`](Self::iter_combinations_inner) for mutable query item combinations with the full `'world` lifetime.
#[inline]
pub fn iter_combinations<const K: usize>(
&self,
) -> QueryCombinationIter<'_, 's, D::ReadOnly, F, K> {
// 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_combinations_unchecked_manual(
self.world,
self.last_run,
self.this_run,
)
}
self.as_readonly().iter_combinations_inner()
}
/// Returns a [`QueryCombinationIter`] over all combinations of `K` query items without repetition.
@ -595,10 +618,40 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
/// # See also
///
/// - [`iter_combinations`](Self::iter_combinations) for read-only query item combinations.
/// - [`iter_combinations_inner`](Self::iter_combinations_inner) for mutable query item combinations with the full `'world` lifetime.
#[inline]
pub fn iter_combinations_mut<const K: usize>(
&mut self,
) -> QueryCombinationIter<'_, 's, D, F, K> {
self.reborrow().iter_combinations_inner()
}
/// Returns a [`QueryCombinationIter`] over all combinations of `K` query items without repetition.
/// This consumes the [`Query`] to return results with the actual "inner" world lifetime.
///
/// This iterator is always guaranteed to return results from each unique pair of matching entities.
/// Iteration order is not guaranteed.
///
/// # Example
///
/// ```
/// # use bevy_ecs::prelude::*;
/// # #[derive(Component)]
/// # struct ComponentA;
/// fn some_system(query: Query<&mut ComponentA>) {
/// let mut combinations = query.iter_combinations_inner();
/// while let Some([mut a1, mut a2]) = combinations.fetch_next() {
/// // mutably access components data
/// }
/// }
/// ```
///
/// # See also
///
/// - [`iter_combinations`](Self::iter_combinations) for read-only query item combinations.
/// - [`iter_combinations_mut`](Self::iter_combinations_mut) for mutable query item combinations.
#[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
@ -642,22 +695,13 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
/// # See also
///
/// - [`iter_many_mut`](Self::iter_many_mut) to get mutable query items.
/// - [`iter_many_inner`](Self::iter_many_inner) to get mutable query items with the full `'world` lifetime.
#[inline]
pub fn iter_many<EntityList: IntoIterator<Item: EntityBorrow>>(
&self,
entities: EntityList,
) -> QueryManyIter<'_, '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_unchecked_manual(
entities,
self.world,
self.last_run,
self.this_run,
)
}
self.as_readonly().iter_many_inner(entities)
}
/// Returns an iterator over the query items generated from an [`Entity`] list.
@ -693,11 +737,33 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
/// }
/// # bevy_ecs::system::assert_is_system(system);
/// ```
/// # See also
///
/// - [`iter_many`](Self::iter_many) to get read-only query items.
/// - [`iter_many_inner`](Self::iter_many_inner) to get mutable query items with the full `'world` lifetime.
#[inline]
pub fn iter_many_mut<EntityList: IntoIterator<Item: EntityBorrow>>(
&mut self,
entities: EntityList,
) -> QueryManyIter<'_, 's, D, F, EntityList::IntoIter> {
self.reborrow().iter_many_inner(entities)
}
/// Returns an iterator over the query items generated from an [`Entity`] list.
/// This consumes the [`Query`] to return results with the actual "inner" world lifetime.
///
/// Items are returned in the order of the list of entities, and may not be unique if the input
/// doesn't guarantee uniqueness. Entities that don't match the query are skipped.
///
/// # See also
///
/// - [`iter_many`](Self::iter_many) to get read-only query items.
/// - [`iter_many_mut`](Self::iter_many_mut) to get mutable query items.
#[inline]
pub fn iter_many_inner<EntityList: IntoIterator<Item: EntityBorrow>>(
self,
entities: EntityList,
) -> QueryManyIter<'w, 's, D, F, EntityList::IntoIter> {
// SAFETY: `self.world` has permission to access the required components.
unsafe {
self.state.iter_many_unchecked_manual(
@ -848,13 +914,8 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
/// - [`iter`](Self::iter) and [`iter_mut`](Self::iter_mut) for the safe versions.
#[inline]
pub unsafe fn iter_unsafe(&self) -> QueryIter<'_, 's, D, F> {
// 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_unchecked_manual(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() }.into_iter()
}
/// Iterates over all possible combinations of `K` query items without repetition.
@ -874,13 +935,8 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
pub unsafe fn iter_combinations_unsafe<const K: usize>(
&self,
) -> QueryCombinationIter<'_, 's, D, F, K> {
// 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_combinations_unchecked_manual(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_combinations_inner()
}
/// Returns an [`Iterator`] over the query items generated from an [`Entity`] list.
@ -901,17 +957,8 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
&self,
entities: EntityList,
) -> QueryManyIter<'_, '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_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_inner(entities)
}
/// Returns an [`Iterator`] over the unique query items generated from an [`Entity`] list.
@ -960,13 +1007,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
/// [`World`]: crate::world::World
#[inline]
pub fn par_iter(&self) -> QueryParIter<'_, '_, D::ReadOnly, F> {
QueryParIter {
world: self.world,
state: self.state.as_readonly(),
last_run: self.last_run,
this_run: self.this_run,
batching_strategy: BatchingStrategy::new(),
}
self.as_readonly().par_iter_inner()
}
/// Returns a parallel iterator over the query results for the given [`World`].
@ -1001,6 +1042,37 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
/// [`World`]: crate::world::World
#[inline]
pub fn par_iter_mut(&mut self) -> QueryParIter<'_, '_, D, F> {
self.reborrow().par_iter_inner()
}
/// Returns a parallel iterator over the query results for the given [`World`](crate::world::World).
/// This consumes the [`Query`] to return results with the actual "inner" world lifetime.
///
/// This parallel iterator is always guaranteed to return results from each matching entity once and
/// only once. Iteration order and thread assignment is not guaranteed.
///
/// If the `multithreaded` feature is disabled, iterating with this operates identically to [`Iterator::for_each`]
/// on [`QueryIter`].
///
/// # Example
///
/// Here, the `gravity_system` updates the `Velocity` component of every entity that contains it:
///
/// ```
/// # use bevy_ecs::prelude::*;
/// #
/// # #[derive(Component)]
/// # struct Velocity { x: f32, y: f32, z: f32 }
/// fn gravity_system(query: Query<&mut Velocity>) {
/// const DELTA: f32 = 1.0 / 60.0;
/// query.par_iter_inner().for_each(|mut velocity| {
/// velocity.y -= 9.8 * DELTA;
/// });
/// }
/// # bevy_ecs::system::assert_is_system(gravity_system);
/// ```
#[inline]
pub fn par_iter_inner(self) -> QueryParIter<'w, 's, D, F> {
QueryParIter {
world: self.world,
state: self.state,
@ -1045,16 +1117,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
/// - [`get_mut`](Self::get_mut) to get a mutable query item.
#[inline]
pub fn get(&self, entity: Entity) -> Result<ROQueryItem<'_, D>, QueryEntityError> {
// SAFETY: system runs without conflicts with other systems.
// same-system queries have runtime borrow checks when they conflict
unsafe {
self.state.as_readonly().get_unchecked_manual(
self.world,
entity,
self.last_run,
self.this_run,
)
}
self.as_readonly().get_inner(entity)
}
/// Returns the read-only query items for the given array of [`Entity`].
@ -1072,13 +1135,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
&self,
entities: [Entity; N],
) -> Result<[ROQueryItem<'_, D>; N], QueryEntityError> {
// SAFETY:
// - `&self` ensures there is no mutable access to any components accessible to this query.
// - `self.world` matches `self.state`.
unsafe {
self.state
.get_many_read_only_manual(self.world, entities, self.last_run, self.this_run)
}
self.as_readonly().get_many_inner(entities)
}
/// Returns the read-only query items for the given array of [`Entity`].
@ -1162,6 +1219,21 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
/// - [`get`](Self::get) to get a read-only query item.
#[inline]
pub fn get_mut(&mut self, entity: Entity) -> Result<D::Item<'_>, QueryEntityError> {
self.reborrow().get_inner(entity)
}
/// Returns the query item for the given [`Entity`].
/// This consumes the [`Query`] to return results with the actual "inner" world lifetime.
///
/// In case of a nonexisting entity or mismatched component, a [`QueryEntityError`] is returned instead.
///
/// This is always guaranteed to run in `O(1)` time.
///
/// # See also
///
/// - [`get_mut`](Self::get_mut) to get the item using a mutable borrow of the [`Query`].
#[inline]
pub fn get_inner(self, entity: Entity) -> Result<D::Item<'w>, QueryEntityError<'w>> {
// SAFETY: system runs without conflicts with other systems.
// same-system queries have runtime borrow checks when they conflict
unsafe {
@ -1184,6 +1256,24 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
&mut self,
entities: [Entity; N],
) -> Result<[D::Item<'_>; N], QueryEntityError> {
self.reborrow().get_many_inner(entities)
}
/// Returns the query items for the given array of [`Entity`].
/// This consumes the [`Query`] to return results with the actual "inner" world lifetime.
///
/// 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.
///
/// # See also
///
/// - [`get_many`](Self::get_many) to get read-only query items.
/// - [`get_many_mut`](Self::get_many_mut) to get items using a mutable reference.
#[inline]
pub fn get_many_inner<const N: usize>(
self,
entities: [Entity; N],
) -> Result<[D::Item<'w>; N], QueryEntityError<'w>> {
// SAFETY: scheduler ensures safe Query world access
unsafe {
self.state
@ -1264,12 +1354,8 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
/// - [`get_mut`](Self::get_mut) for the safe version.
#[inline]
pub unsafe fn get_unchecked(&self, entity: Entity) -> Result<D::Item<'_>, QueryEntityError> {
// SEMI-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)
}
// SAFETY: The caller promises that this will not result in multiple mutable references.
unsafe { self.reborrow_unsafe() }.get_inner(entity)
}
/// Returns a single read-only query item when there is exactly one entity matching the query.
@ -1335,16 +1421,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
/// - [`single`](Self::single) for the panicking version.
#[inline]
pub fn get_single(&self) -> Result<ROQueryItem<'_, D>, QuerySingleError> {
// SAFETY:
// the query ensures that the components it accesses are not mutably accessible somewhere else
// and the query is read only.
unsafe {
self.state.as_readonly().get_single_unchecked_manual(
self.world,
self.last_run,
self.this_run,
)
}
self.as_readonly().get_single_inner()
}
/// Returns a single query item when there is exactly one entity matching the query.
@ -1406,6 +1483,37 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
/// - [`single_mut`](Self::single_mut) for the panicking version.
#[inline]
pub fn get_single_mut(&mut self) -> Result<D::Item<'_>, QuerySingleError> {
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.
///
/// If the number of query items is not exactly one, a [`QuerySingleError`] is returned instead.
///
/// # 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.get_single_inner().expect("Error: Could not find a single player.");
/// health.0 += 1;
/// }
/// # bevy_ecs::system::assert_is_system(regenerate_player_health_system);
/// ```
///
/// # See also
///
/// - [`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.
#[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
@ -1648,6 +1756,80 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
self.transmute_lens_filtered::<NewD, ()>()
}
/// Returns a [`QueryLens`] that can be used to get a query with a more general fetch.
/// This consumes the [`Query`] to return results with the actual "inner" world lifetime.
///
/// For example, this can transform a `Query<(&A, &mut B)>` to a `Query<&B>`.
/// This can be useful for passing the query to another function. Note that since
/// filter terms are dropped, non-archetypal filters like [`Added`](crate::query::Added) and
/// [`Changed`](crate::query::Changed) will not be respected. To maintain or change filter
/// terms see [`Self::transmute_lens_filtered`]
///
/// ## Panics
///
/// This will panic if `NewD` is not a subset of the original fetch `Q`
///
/// ## Example
///
/// ```rust
/// # use bevy_ecs::prelude::*;
/// # use bevy_ecs::system::QueryLens;
/// #
/// # #[derive(Component)]
/// # struct A(usize);
/// #
/// # #[derive(Component)]
/// # struct B(usize);
/// #
/// # let mut world = World::new();
/// #
/// # world.spawn((A(10), B(5)));
/// #
/// fn reusable_function(mut lens: QueryLens<&A>) {
/// assert_eq!(lens.query().single().0, 10);
/// }
///
/// // We can use the function in a system that takes the exact query.
/// fn system_1(query: Query<&A>) {
/// reusable_function(query.into_query_lens());
/// }
///
/// // We can also use it with a query that does not match exactly
/// // by transmuting it.
/// fn system_2(query: Query<(&mut A, &B)>) {
/// let mut lens = query.transmute_lens_inner::<&A>();
/// reusable_function(lens);
/// }
///
/// # let mut schedule = Schedule::default();
/// # schedule.add_systems((system_1, system_2));
/// # schedule.run(&mut world);
/// ```
///
/// ## Allowed Transmutes
///
/// Besides removing parameters from the query, you can also
/// make limited changes to the types of parameters.
///
/// * Can always add/remove [`Entity`]
/// * Can always add/remove [`EntityLocation`]
/// * Can always add/remove [`&Archetype`]
/// * `Ref<T>` <-> `&T`
/// * `&mut T` -> `&T`
/// * `&mut T` -> `Ref<T>`
/// * [`EntityMut`](crate::world::EntityMut) -> [`EntityRef`](crate::world::EntityRef)
///
/// [`EntityLocation`]: crate::entity::EntityLocation
/// [`&Archetype`]: crate::archetype::Archetype
///
/// # See also
///
/// - [`transmute_lens`](Self::transmute_lens) to convert to a lens using a mutable borrow of the [`Query`].
#[track_caller]
pub fn transmute_lens_inner<NewD: QueryData>(self) -> QueryLens<'w, NewD> {
self.transmute_lens_filtered_inner::<NewD, ()>()
}
/// Equivalent to [`Self::transmute_lens`] but also includes a [`QueryFilter`] type.
///
/// Note that the lens will iterate the same tables and archetypes as the original query. This means that
@ -1658,6 +1840,24 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
pub fn transmute_lens_filtered<NewD: QueryData, NewF: QueryFilter>(
&mut self,
) -> QueryLens<'_, NewD, NewF> {
self.reborrow().transmute_lens_filtered_inner()
}
/// Equivalent to [`Self::transmute_lens_inner`] but also includes a [`QueryFilter`] type.
/// This consumes the [`Query`] to return results with the actual "inner" world lifetime.
///
/// Note that the lens will iterate the same tables and archetypes as the original query. This means that
/// additional archetypal query terms like [`With`](crate::query::With) and [`Without`](crate::query::Without)
/// will not necessarily be respected and non-archetypal terms like [`Added`](crate::query::Added) and
/// [`Changed`](crate::query::Changed) will only be respected if they are in the type signature.
///
/// # See also
///
/// - [`transmute_lens_filtered`](Self::transmute_lens_filtered) to convert to a lens using a mutable borrow of the [`Query`].
#[track_caller]
pub fn transmute_lens_filtered_inner<NewD: QueryData, NewF: QueryFilter>(
self,
) -> QueryLens<'w, NewD, NewF> {
let state = self.state.transmute_filtered::<NewD, NewF>(self.world);
QueryLens {
world: self.world,
@ -1672,6 +1872,15 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
self.transmute_lens()
}
/// Gets a [`QueryLens`] with the same accesses as the existing query
///
/// # See also
///
/// - [`as_query_lens`](Self::as_query_lens) to convert to a lens using a mutable borrow of the [`Query`].
pub fn into_query_lens(self) -> QueryLens<'w, D> {
self.transmute_lens_inner()
}
/// Returns a [`QueryLens`] that can be used to get a query with the combined fetch.
///
/// For example, this can take a `Query<&A>` and a `Query<&B>` and return a `Query<(&A, &B)>`.
@ -1733,6 +1942,33 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
self.join_filtered(other)
}
/// Returns a [`QueryLens`] that can be used to get a query with the combined fetch.
/// This consumes the [`Query`] to return results with the actual "inner" world lifetime.
///
/// For example, this can take a `Query<&A>` and a `Query<&B>` and return a `Query<(&A, &B)>`.
/// The returned query will only return items with both `A` and `B`. Note that since filters
/// are dropped, non-archetypal filters like `Added` and `Changed` will not be respected.
/// To maintain or change filter terms see `Self::join_filtered`.
///
/// ## Panics
///
/// This will panic if `NewD` is not a subset of the union of the original fetch `Q` and `OtherD`.
///
/// ## Allowed Transmutes
///
/// Like `transmute_lens` the query terms can be changed with some restrictions.
/// See [`Self::transmute_lens`] for more details.
///
/// # See also
///
/// - [`join`](Self::join) to join using a mutable borrow of the [`Query`].
pub fn join_inner<OtherD: QueryData, NewD: QueryData>(
self,
other: &mut Query<OtherD>,
) -> QueryLens<'w, NewD> {
self.join_filtered_inner(other)
}
/// Equivalent to [`Self::join`] but also includes a [`QueryFilter`] type.
///
/// Note that the lens with iterate a subset of the original queries' tables
@ -1749,6 +1985,30 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
&mut self,
other: &mut Query<OtherD, OtherF>,
) -> QueryLens<'_, NewD, NewF> {
self.reborrow().join_filtered_inner(other)
}
/// Equivalent to [`Self::join_inner`] but also includes a [`QueryFilter`] type.
/// This consumes the [`Query`] to return results with the actual "inner" world lifetime.
///
/// Note that the lens with iterate a subset of the original queries' tables
/// and archetypes. This means that additional archetypal query terms like
/// `With` and `Without` will not necessarily be respected and non-archetypal
/// terms like `Added` and `Changed` will only be respected if they are in
/// the type signature.
///
/// # See also
///
/// - [`join_filtered`](Self::join_filtered) to join using a mutable borrow of the [`Query`].
pub fn join_filtered_inner<
OtherD: QueryData,
OtherF: QueryFilter,
NewD: QueryData,
NewF: QueryFilter,
>(
self,
other: &mut Query<OtherD, OtherF>,
) -> QueryLens<'w, NewD, NewF> {
let state = self
.state
.join_filtered::<OtherD, OtherF, NewD, NewF>(self.world, other.state);
@ -1761,6 +2021,22 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
}
}
impl<'w, 's, D: QueryData, F: QueryFilter> IntoIterator for Query<'w, 's, D, F> {
type Item = D::Item<'w>;
type IntoIter = QueryIter<'w, 's, D, F>;
fn into_iter(self) -> Self::IntoIter {
// SAFETY:
// - `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)
}
}
}
impl<'w, 's, D: QueryData, F: QueryFilter> IntoIterator for &'w Query<'_, 's, D, F> {
type Item = ROQueryItem<'w, D>;
type IntoIter = QueryIter<'w, 's, D::ReadOnly, F>;
@ -1780,52 +2056,6 @@ impl<'w, 's, D: QueryData, F: QueryFilter> IntoIterator for &'w mut Query<'_, 's
}
impl<'w, 's, D: ReadOnlyQueryData, F: QueryFilter> Query<'w, 's, D, F> {
/// Returns the query item for the given [`Entity`], with the actual "inner" world lifetime.
///
/// In case of a nonexisting entity or mismatched component, a [`QueryEntityError`] is
/// returned instead.
///
/// This can only return immutable data (mutable data will be cast to an immutable form).
/// See [`get_mut`](Self::get_mut) for queries that contain at least one mutable component.
///
/// # Example
///
/// Here, `get` is used to retrieve the exact query item of the entity specified by the
/// `SelectedCharacter` resource.
///
/// ```
/// # use bevy_ecs::prelude::*;
/// #
/// # #[derive(Resource)]
/// # struct SelectedCharacter { entity: Entity }
/// # #[derive(Component)]
/// # struct Character { name: String }
/// #
/// fn print_selected_character_name_system(
/// query: Query<&Character>,
/// selection: Res<SelectedCharacter>
/// )
/// {
/// if let Ok(selected_character) = query.get(selection.entity) {
/// println!("{}", selected_character.name);
/// }
/// }
/// # bevy_ecs::system::assert_is_system(print_selected_character_name_system);
/// ```
#[inline]
pub fn get_inner(&self, entity: Entity) -> Result<ROQueryItem<'w, D>, QueryEntityError> {
// SAFETY: system runs without conflicts with other systems.
// same-system queries have runtime borrow checks when they conflict
unsafe {
self.state.as_readonly().get_unchecked_manual(
self.world,
entity,
self.last_run,
self.this_run,
)
}
}
/// Returns an [`Iterator`] over the query items, with the actual "inner" world lifetime.
///
/// This can only return immutable data (mutable data will be cast to an immutable form).
@ -1851,13 +2081,7 @@ impl<'w, 's, D: ReadOnlyQueryData, F: QueryFilter> Query<'w, 's, D, F> {
/// ```
#[inline]
pub fn iter_inner(&self) -> QueryIter<'w, 's, D::ReadOnly, F> {
// SAFETY: system runs without conflicts with other systems.
// same-system queries have runtime borrow checks when they conflict
unsafe {
self.state
.as_readonly()
.iter_unchecked_manual(self.world, self.last_run, self.this_run)
}
(*self).into_iter()
}
}

View File

@ -334,7 +334,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.
unsafe { Query::new(world, state, system_meta.last_run, change_tick) }
unsafe { state.query_unchecked_manual_with_ticks(world, system_meta.last_run, change_tick) }
}
}
@ -404,10 +404,12 @@ unsafe impl<'a, D: QueryData + 'static, F: QueryFilter + 'static> SystemParam fo
) -> Self::Item<'w, 's> {
state.validate_world(world.id());
// SAFETY: State ensures that the components it accesses are not accessible somewhere elsewhere.
let result =
unsafe { state.get_single_unchecked_manual(world, system_meta.last_run, change_tick) };
let single =
result.expect("The query was expected to contain exactly one matching entity.");
let query = unsafe {
state.query_unchecked_manual_with_ticks(world, system_meta.last_run, change_tick)
};
let single = query
.get_single_inner()
.expect("The query was expected to contain exactly one matching entity.");
Single {
item: single,
_filter: PhantomData,
@ -423,14 +425,14 @@ unsafe impl<'a, D: QueryData + 'static, F: QueryFilter + 'static> SystemParam fo
state.validate_world(world.id());
// SAFETY: State ensures that the components it accesses are not mutably accessible elsewhere
// and the query is read only.
let result = unsafe {
state.as_readonly().get_single_unchecked_manual(
let query = unsafe {
state.query_unchecked_manual_with_ticks(
world,
system_meta.last_run,
world.change_tick(),
)
};
let is_valid = result.is_ok();
let is_valid = query.get_single_inner().is_ok();
if !is_valid {
system_meta.try_warn_param::<Self>();
}
@ -468,9 +470,10 @@ 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.
let result =
unsafe { state.get_single_unchecked_manual(world, system_meta.last_run, change_tick) };
match result {
let query = unsafe {
state.query_unchecked_manual_with_ticks(world, system_meta.last_run, change_tick)
};
match query.get_single_inner() {
Ok(single) => Some(Single {
item: single,
_filter: PhantomData,
@ -489,13 +492,14 @@ unsafe impl<'a, D: QueryData + 'static, F: QueryFilter + 'static> SystemParam
state.validate_world(world.id());
// SAFETY: State ensures that the components it accesses are not mutably accessible elsewhere
// and the query is read only.
let result = unsafe {
state.as_readonly().get_single_unchecked_manual(
let query = unsafe {
state.query_unchecked_manual_with_ticks(
world,
system_meta.last_run,
world.change_tick(),
)
};
let result = query.get_single_inner();
let is_valid = !matches!(result, Err(QuerySingleError::MultipleEntities(_)));
if !is_valid {
system_meta.try_warn_param::<Self>();

View File

@ -366,18 +366,8 @@ impl<'w> DeferredWorld<'w> {
&mut self,
state: &'s mut QueryState<D, F>,
) -> Query<'_, 's, D, F> {
state.validate_world(self.world.id());
state.update_archetypes(self);
// SAFETY: We ran validate_world to ensure our state matches
unsafe {
let world_cell = self.world;
Query::new(
world_cell,
state,
world_cell.last_change_tick(),
world_cell.change_tick(),
)
}
// SAFETY: We have mutable access to the entire world
unsafe { state.query_unchecked(self.world) }
}
/// Gets a mutable reference to the resource of the given type

View File

@ -942,7 +942,7 @@ pub fn camera_system(
|| camera.computed.old_sub_camera_view != camera.sub_camera_view
{
let new_computed_target_info = normalized_target.get_render_target_info(
&windows,
windows,
&images,
&manual_texture_views,
);