remove QF generics from all Query/State methods and types (#5170)

# Objective

remove `QF` generics from a bunch of types and methods on query related items. this has a few benefits:
- simplifies type signatures `fn iter(&self) -> QueryIter<'_, 's, Q::ReadOnly, F::ReadOnly>` is (imo) conceptually simpler than `fn iter(&self) -> QueryIter<'_, 's, Q, ROQueryFetch<'_, Q>, F>`
- `Fetch` is mostly an implementation detail but previously we had to expose it on every `iter` `get` etc method
- Allows us to potentially in the future simplify the `WorldQuery` trait hierarchy by removing the `Fetch` trait

## Solution

remove the `QF` generic and add a way to (unsafely) turn `&QueryState<Q1, F1>` into `&QueryState<Q2, F2>`

---

## Changelog/Migration Guide

The `QF` generic was removed from various `Query` iterator types and some methods, you should update your code to use the type of the corresponding worldquery of the fetch type that was being used, or call `as_readonly`/`as_nop` to convert a querystate to the appropriate type. For example:
`.get_single_unchecked_manual::<ROQueryFetch<Q>>(..)` -> `.as_readonly().get_single_unchecked_manual(..)`
`my_field: QueryIter<'w, 's, Q, ROQueryFetch<'w, Q>, F>` -> `my_field: QueryIter<'w, 's, Q::ReadOnly, F::ReadOnly>`
This commit is contained in:
Boxy 2022-07-19 00:45:00 +00:00
parent 4affc8cd93
commit 1ac8a476cf
8 changed files with 273 additions and 206 deletions

View File

@ -318,7 +318,8 @@ use std::{cell::UnsafeCell, marker::PhantomData};
/// ``` /// ```
/// # Safety /// # Safety
/// ///
/// component access of `ROQueryFetch<Self>` should be a subset of `QueryFetch<Self>` /// component access of `ROQueryFetch<Self>` must be a subset of `QueryFetch<Self>`
/// and `ROQueryFetch<Self>` must match exactly the same archetypes/tables as `QueryFetch<Self>`
pub unsafe trait WorldQuery: for<'w> WorldQueryGats<'w, _State = Self::State> { pub unsafe trait WorldQuery: for<'w> WorldQueryGats<'w, _State = Self::State> {
type ReadOnly: ReadOnlyWorldQuery<State = Self::State>; type ReadOnly: ReadOnlyWorldQuery<State = Self::State>;
type State: FetchState; type State: FetchState;
@ -1608,6 +1609,25 @@ macro_rules! impl_anytuple_fetch {
all_tuples!(impl_tuple_fetch, 0, 15, F, S); all_tuples!(impl_tuple_fetch, 0, 15, F, S);
all_tuples!(impl_anytuple_fetch, 0, 15, F, S); all_tuples!(impl_anytuple_fetch, 0, 15, F, S);
/// [`WorldQuery`] used to nullify queries by turning `Query<Q>` into `Query<NopWorldQuery<Q>>`
///
/// This will rarely be useful to consumers of `bevy_ecs`.
pub struct NopWorldQuery<Q: WorldQuery>(PhantomData<Q>);
/// SAFETY: `Self::ReadOnly` is `Self`
unsafe impl<Q: WorldQuery> WorldQuery for NopWorldQuery<Q> {
type ReadOnly = Self;
type State = Q::State;
fn shrink<'wlong: 'wshort, 'wshort>(_: ()) {}
}
impl<'a, Q: WorldQuery> WorldQueryGats<'a> for NopWorldQuery<Q> {
type Fetch = NopFetch<QueryFetch<'a, Q>>;
type _State = <Q as WorldQueryGats<'a>>::_State;
}
/// SAFETY: `NopFetch` never accesses any data
unsafe impl<Q: WorldQuery> ReadOnlyWorldQuery for NopWorldQuery<Q> {}
/// [`Fetch`] that does not actually fetch anything /// [`Fetch`] that does not actually fetch anything
/// ///
/// Mostly useful when something is generic over the Fetch and you don't want to fetch as you will discard the result /// Mostly useful when something is generic over the Fetch and you don't want to fetch as you will discard the result
@ -1616,18 +1636,18 @@ pub struct NopFetch<State> {
} }
// SAFETY: NopFetch doesnt access anything // SAFETY: NopFetch doesnt access anything
unsafe impl<'w, State: FetchState> Fetch<'w> for NopFetch<State> { unsafe impl<'w, F: Fetch<'w>> Fetch<'w> for NopFetch<F> {
type Item = (); type Item = ();
type State = State; type State = F::State;
const IS_DENSE: bool = true; const IS_DENSE: bool = F::IS_DENSE;
const IS_ARCHETYPAL: bool = true; const IS_ARCHETYPAL: bool = true;
#[inline(always)] #[inline(always)]
unsafe fn init( unsafe fn init(
_world: &'w World, _world: &'w World,
_state: &State, _state: &F::State,
_last_change_tick: u32, _last_change_tick: u32,
_change_tick: u32, _change_tick: u32,
) -> Self { ) -> Self {

View File

@ -13,17 +13,14 @@ use super::{QueryFetch, QueryItem, ReadOnlyWorldQuery};
/// ///
/// This struct is created by the [`Query::iter`](crate::system::Query::iter) and /// This struct is created by the [`Query::iter`](crate::system::Query::iter) and
/// [`Query::iter_mut`](crate::system::Query::iter_mut) methods. /// [`Query::iter_mut`](crate::system::Query::iter_mut) methods.
pub struct QueryIter<'w, 's, Q: WorldQuery, QF: Fetch<'w, State = Q::State>, F: WorldQuery> { pub struct QueryIter<'w, 's, Q: WorldQuery, F: WorldQuery> {
tables: &'w Tables, tables: &'w Tables,
archetypes: &'w Archetypes, archetypes: &'w Archetypes,
query_state: &'s QueryState<Q, F>, query_state: &'s QueryState<Q, F>,
cursor: QueryIterationCursor<'w, 's, Q, QF, F>, cursor: QueryIterationCursor<'w, 's, Q, F>,
} }
impl<'w, 's, Q: WorldQuery, QF, F: WorldQuery> QueryIter<'w, 's, Q, QF, F> impl<'w, 's, Q: WorldQuery, F: WorldQuery> QueryIter<'w, 's, Q, F> {
where
QF: Fetch<'w, State = Q::State>,
{
/// # Safety /// # Safety
/// This does not check for mutable query correctness. To be safe, make sure mutable queries /// This does not check for mutable query correctness. To be safe, make sure mutable queries
/// have unique access to the components they query. /// have unique access to the components they query.
@ -44,11 +41,8 @@ where
} }
} }
impl<'w, 's, Q: WorldQuery, QF, F: WorldQuery> Iterator for QueryIter<'w, 's, Q, QF, F> impl<'w, 's, Q: WorldQuery, F: WorldQuery> Iterator for QueryIter<'w, 's, Q, F> {
where type Item = QueryItem<'w, Q>;
QF: Fetch<'w, State = Q::State>,
{
type Item = QF::Item;
#[inline(always)] #[inline(always)]
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
@ -69,42 +63,32 @@ where
.map(|id| self.archetypes[*id].len()) .map(|id| self.archetypes[*id].len())
.sum(); .sum();
let archetype_query = F::Fetch::IS_ARCHETYPAL && QF::IS_ARCHETYPAL; let archetype_query = Q::Fetch::IS_ARCHETYPAL && F::Fetch::IS_ARCHETYPAL;
let min_size = if archetype_query { max_size } else { 0 }; let min_size = if archetype_query { max_size } else { 0 };
(min_size, Some(max_size)) (min_size, Some(max_size))
} }
} }
// This is correct as [`QueryIter`] always returns `None` once exhausted. // This is correct as [`QueryIter`] always returns `None` once exhausted.
impl<'w, 's, Q: WorldQuery, QF, F: WorldQuery> FusedIterator for QueryIter<'w, 's, Q, QF, F> where impl<'w, 's, Q: WorldQuery, F: WorldQuery> FusedIterator for QueryIter<'w, 's, Q, F> {}
QF: Fetch<'w, State = Q::State>
{
}
/// An [`Iterator`] over query results of a [`Query`](crate::system::Query). /// An [`Iterator`] over query results of a [`Query`](crate::system::Query).
/// ///
/// This struct is created by the [`Query::iter_many`](crate::system::Query::iter_many) method. /// This struct is created by the [`Query::iter_many`](crate::system::Query::iter_many) method.
pub struct QueryManyIter< pub struct QueryManyIter<'w, 's, Q: WorldQuery, F: WorldQuery, I: Iterator>
'w, where
's,
Q: WorldQuery,
QF: Fetch<'w, State = Q::State>,
F: WorldQuery,
I: Iterator,
> where
I::Item: Borrow<Entity>, I::Item: Borrow<Entity>,
{ {
entity_iter: I, entity_iter: I,
entities: &'w Entities, entities: &'w Entities,
tables: &'w Tables, tables: &'w Tables,
archetypes: &'w Archetypes, archetypes: &'w Archetypes,
fetch: QF, fetch: QueryFetch<'w, Q>,
filter: QueryFetch<'w, F>, filter: QueryFetch<'w, F>,
query_state: &'s QueryState<Q, F>, query_state: &'s QueryState<Q, F>,
} }
impl<'w, 's, Q: WorldQuery, QF: Fetch<'w, State = Q::State>, F: WorldQuery, I: Iterator> impl<'w, 's, Q: WorldQuery, F: WorldQuery, I: Iterator> QueryManyIter<'w, 's, Q, F, I>
QueryManyIter<'w, 's, Q, QF, F, I>
where where
I::Item: Borrow<Entity>, I::Item: Borrow<Entity>,
{ {
@ -119,14 +103,14 @@ where
entity_list: EntityList, entity_list: EntityList,
last_change_tick: u32, last_change_tick: u32,
change_tick: u32, change_tick: u32,
) -> QueryManyIter<'w, 's, Q, QF, F, I> { ) -> QueryManyIter<'w, 's, Q, F, I> {
let fetch = QF::init( let fetch = Q::Fetch::init(
world, world,
&query_state.fetch_state, &query_state.fetch_state,
last_change_tick, last_change_tick,
change_tick, change_tick,
); );
let filter = QueryFetch::<F>::init( let filter = F::Fetch::init(
world, world,
&query_state.filter_state, &query_state.filter_state,
last_change_tick, last_change_tick,
@ -144,12 +128,11 @@ where
} }
} }
impl<'w, 's, Q: WorldQuery, QF: Fetch<'w, State = Q::State>, F: WorldQuery, I: Iterator> Iterator impl<'w, 's, Q: WorldQuery, F: WorldQuery, I: Iterator> Iterator for QueryManyIter<'w, 's, Q, F, I>
for QueryManyIter<'w, 's, Q, QF, F, I>
where where
I::Item: Borrow<Entity>, I::Item: Borrow<Entity>,
{ {
type Item = QF::Item; type Item = QueryItem<'w, Q>;
#[inline(always)] #[inline(always)]
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
@ -201,7 +184,7 @@ pub struct QueryCombinationIter<'w, 's, Q: WorldQuery, F: WorldQuery, const K: u
tables: &'w Tables, tables: &'w Tables,
archetypes: &'w Archetypes, archetypes: &'w Archetypes,
query_state: &'s QueryState<Q, F>, query_state: &'s QueryState<Q, F>,
cursors: [QueryIterationCursor<'w, 's, Q, QueryFetch<'w, Q>, F>; K], cursors: [QueryIterationCursor<'w, 's, Q, F>; K],
} }
impl<'w, 's, Q: WorldQuery, F: WorldQuery, const K: usize> QueryCombinationIter<'w, 's, Q, F, K> { impl<'w, 's, Q: WorldQuery, F: WorldQuery, const K: usize> QueryCombinationIter<'w, 's, Q, F, K> {
@ -219,11 +202,10 @@ impl<'w, 's, Q: WorldQuery, F: WorldQuery, const K: usize> QueryCombinationIter<
// Initialize array with cursors. // Initialize array with cursors.
// There is no FromIterator on arrays, so instead initialize it manually with MaybeUninit // There is no FromIterator on arrays, so instead initialize it manually with MaybeUninit
let mut array: MaybeUninit<[QueryIterationCursor<'w, 's, Q, QueryFetch<'w, Q>, F>; K]> = let mut array: MaybeUninit<[QueryIterationCursor<'w, 's, Q, F>; K]> = MaybeUninit::uninit();
MaybeUninit::uninit();
let ptr = array let ptr = array
.as_mut_ptr() .as_mut_ptr()
.cast::<QueryIterationCursor<'w, 's, Q, QueryFetch<'w, Q>, F>>(); .cast::<QueryIterationCursor<'w, 's, Q, F>>();
if K != 0 { if K != 0 {
ptr.write(QueryIterationCursor::init( ptr.write(QueryIterationCursor::init(
world, world,
@ -367,10 +349,9 @@ where
} }
} }
impl<'w, 's, Q: WorldQuery, QF, F> ExactSizeIterator for QueryIter<'w, 's, Q, QF, F> impl<'w, 's, Q: WorldQuery, F: WorldQuery> ExactSizeIterator for QueryIter<'w, 's, Q, F>
where where
QF: Fetch<'w, State = Q::State>, F: ArchetypeFilter,
F: WorldQuery + ArchetypeFilter,
{ {
fn len(&self) -> usize { fn len(&self) -> usize {
self.query_state self.query_state
@ -405,21 +386,21 @@ where
{ {
} }
struct QueryIterationCursor<'w, 's, Q: WorldQuery, QF: Fetch<'w, State = Q::State>, F: WorldQuery> { struct QueryIterationCursor<'w, 's, Q: WorldQuery, F: WorldQuery> {
table_id_iter: std::slice::Iter<'s, TableId>, table_id_iter: std::slice::Iter<'s, TableId>,
archetype_id_iter: std::slice::Iter<'s, ArchetypeId>, archetype_id_iter: std::slice::Iter<'s, ArchetypeId>,
fetch: QF, fetch: QueryFetch<'w, Q>,
filter: QueryFetch<'w, F>, filter: QueryFetch<'w, F>,
// length of the table table or length of the archetype, depending on whether both `Q`'s and `F`'s fetches are dense // length of the table table or length of the archetype, depending on whether both `Q`'s and `F`'s fetches are dense
current_len: usize, current_len: usize,
// either table row or archetype index, depending on whether both `Q`'s and `F`'s fetches are dense // either table row or archetype index, depending on whether both `Q`'s and `F`'s fetches are dense
current_index: usize, current_index: usize,
phantom: PhantomData<(&'w (), Q)>, phantom: PhantomData<Q>,
} }
impl<'w, 's, Q: WorldQuery, QF, F: WorldQuery> Clone for QueryIterationCursor<'w, 's, Q, QF, F> impl<'w, 's, Q: WorldQuery, F: WorldQuery> Clone for QueryIterationCursor<'w, 's, Q, F>
where where
QF: Fetch<'w, State = Q::State> + Clone, QueryFetch<'w, Q>: Clone,
QueryFetch<'w, F>: Clone, QueryFetch<'w, F>: Clone,
{ {
fn clone(&self) -> Self { fn clone(&self) -> Self {
@ -435,11 +416,8 @@ where
} }
} }
impl<'w, 's, Q: WorldQuery, QF, F: WorldQuery> QueryIterationCursor<'w, 's, Q, QF, F> impl<'w, 's, Q: WorldQuery, F: WorldQuery> QueryIterationCursor<'w, 's, Q, F> {
where const IS_DENSE: bool = Q::Fetch::IS_DENSE && F::Fetch::IS_DENSE;
QF: Fetch<'w, State = Q::State>,
{
const IS_DENSE: bool = QF::IS_DENSE && <QueryFetch<'static, F>>::IS_DENSE;
unsafe fn init_empty( unsafe fn init_empty(
world: &'w World, world: &'w World,
@ -460,13 +438,13 @@ where
last_change_tick: u32, last_change_tick: u32,
change_tick: u32, change_tick: u32,
) -> Self { ) -> Self {
let fetch = QF::init( let fetch = Q::Fetch::init(
world, world,
&query_state.fetch_state, &query_state.fetch_state,
last_change_tick, last_change_tick,
change_tick, change_tick,
); );
let filter = QueryFetch::<F>::init( let filter = F::Fetch::init(
world, world,
&query_state.filter_state, &query_state.filter_state,
last_change_tick, last_change_tick,
@ -485,7 +463,7 @@ where
/// retrieve item returned from most recent `next` call again. /// retrieve item returned from most recent `next` call again.
#[inline] #[inline]
unsafe fn peek_last(&mut self) -> Option<QF::Item> { unsafe fn peek_last(&mut self) -> Option<QueryItem<'w, Q>> {
if self.current_index > 0 { if self.current_index > 0 {
if Self::IS_DENSE { if Self::IS_DENSE {
Some(self.fetch.table_fetch(self.current_index - 1)) Some(self.fetch.table_fetch(self.current_index - 1))
@ -509,7 +487,7 @@ where
tables: &'w Tables, tables: &'w Tables,
archetypes: &'w Archetypes, archetypes: &'w Archetypes,
query_state: &'s QueryState<Q, F>, query_state: &'s QueryState<Q, F>,
) -> Option<QF::Item> { ) -> Option<QueryItem<'w, Q>> {
if Self::IS_DENSE { if Self::IS_DENSE {
loop { loop {
// we are on the beginning of the query, or finished processing a table, so skip to the next // we are on the beginning of the query, or finished processing a table, so skip to the next

View File

@ -21,8 +21,8 @@ pub(crate) unsafe fn debug_checked_unreachable() -> ! {
mod tests { mod tests {
use super::WorldQuery; use super::WorldQuery;
use crate::prelude::{AnyOf, Entity, Or, QueryState, With, Without}; use crate::prelude::{AnyOf, Entity, Or, QueryState, With, Without};
use crate::query::{ArchetypeFilter, QueryCombinationIter, QueryFetch, ReadOnlyWorldQuery}; use crate::query::{ArchetypeFilter, QueryCombinationIter, QueryFetch};
use crate::system::{IntoSystem, Query, System}; use crate::system::{IntoSystem, Query, System, SystemState};
use crate::{self as bevy_ecs, component::Component, world::World}; use crate::{self as bevy_ecs, component::Component, world::World};
use std::any::type_name; use std::any::type_name;
use std::collections::HashSet; use std::collections::HashSet;
@ -67,10 +67,11 @@ mod tests {
} }
fn assert_combination<Q, F, const K: usize>(world: &mut World, expected_size: usize) fn assert_combination<Q, F, const K: usize>(world: &mut World, expected_size: usize)
where where
Q: ReadOnlyWorldQuery, Q: WorldQuery,
F: ReadOnlyWorldQuery + ArchetypeFilter, F: WorldQuery,
for<'w> QueryFetch<'w, Q>: Clone, F::ReadOnly: ArchetypeFilter,
for<'w> QueryFetch<'w, F>: Clone, for<'w> QueryFetch<'w, Q::ReadOnly>: Clone,
for<'w> QueryFetch<'w, F::ReadOnly>: Clone,
{ {
let mut query = world.query_filtered::<Q, F>(); let mut query = world.query_filtered::<Q, F>();
let iter = query.iter_combinations::<K>(world); let iter = query.iter_combinations::<K>(world);
@ -79,10 +80,11 @@ mod tests {
} }
fn assert_all_sizes_equal<Q, F>(world: &mut World, expected_size: usize) fn assert_all_sizes_equal<Q, F>(world: &mut World, expected_size: usize)
where where
Q: ReadOnlyWorldQuery, Q: WorldQuery,
F: ReadOnlyWorldQuery + ArchetypeFilter, F: WorldQuery,
for<'w> QueryFetch<'w, Q>: Clone, F::ReadOnly: ArchetypeFilter,
for<'w> QueryFetch<'w, F>: Clone, for<'w> QueryFetch<'w, Q::ReadOnly>: Clone,
for<'w> QueryFetch<'w, F::ReadOnly>: Clone,
{ {
let mut query = world.query_filtered::<Q, F>(); let mut query = world.query_filtered::<Q, F>();
let iter = query.iter(world); let iter = query.iter(world);
@ -653,4 +655,42 @@ count(): {count}"#
system.run((), &mut world); system.run((), &mut world);
} }
} }
#[test]
fn mut_to_immut_query_methods_have_immut_item() {
#[derive(Component)]
struct Foo;
let mut world = World::new();
let e = world.spawn().insert(Foo).id();
// state
let mut q = world.query::<&mut Foo>();
let _: Option<&Foo> = q.iter(&world).next();
let _: Option<[&Foo; 2]> = q.iter_combinations::<2>(&world).next();
let _: Option<&Foo> = q.iter_manual(&world).next();
let _: Option<&Foo> = q.iter_many(&world, [e]).next();
q.for_each(&world, |_: &Foo| ());
let _: Option<&Foo> = q.get(&world, e).ok();
let _: Option<&Foo> = q.get_manual(&world, e).ok();
let _: Option<[&Foo; 1]> = q.get_many(&world, [e]).ok();
let _: Option<&Foo> = q.get_single(&world).ok();
let _: &Foo = q.single(&world);
// system param
let mut q = SystemState::<Query<&mut Foo>>::new(&mut world);
let q = q.get_mut(&mut world);
let _: Option<&Foo> = q.iter().next();
let _: Option<[&Foo; 2]> = q.iter_combinations::<2>().next();
let _: Option<&Foo> = q.iter_many([e]).next();
q.for_each(|_: &Foo| ());
let _: Option<&Foo> = q.get(e).ok();
let _: Option<&Foo> = q.get_component(e).ok();
let _: Option<[&Foo; 1]> = q.get_many([e]).ok();
let _: Option<&Foo> = q.get_single().ok();
let _: [&Foo; 1] = q.many([e]);
let _: &Foo = q.single();
}
} }

View File

@ -4,8 +4,7 @@ use crate::{
entity::Entity, entity::Entity,
prelude::FromWorld, prelude::FromWorld,
query::{ query::{
Access, Fetch, FetchState, FilteredAccess, NopFetch, QueryCombinationIter, QueryIter, Access, Fetch, FetchState, FilteredAccess, QueryCombinationIter, QueryIter, WorldQuery,
WorldQuery,
}, },
storage::TableId, storage::TableId,
world::{World, WorldId}, world::{World, WorldId},
@ -16,9 +15,13 @@ use bevy_utils::tracing::Instrument;
use fixedbitset::FixedBitSet; use fixedbitset::FixedBitSet;
use std::{borrow::Borrow, fmt}; use std::{borrow::Borrow, fmt};
use super::{QueryFetch, QueryItem, QueryManyIter, ROQueryFetch, ROQueryItem}; use super::{NopWorldQuery, QueryFetch, QueryItem, QueryManyIter, ROQueryItem};
/// Provides scoped access to a [`World`] state according to a given [`WorldQuery`] and query filter. /// Provides scoped access to a [`World`] state according to a given [`WorldQuery`] and query filter.
#[repr(C)]
// SAFETY NOTE:
// Do not add any new fields that use the `Q` or `F` generic parameters as this may
// make `QueryState::as_transmuted_state` unsound if not done with care.
pub struct QueryState<Q: WorldQuery, F: WorldQuery = ()> { pub struct QueryState<Q: WorldQuery, F: WorldQuery = ()> {
world_id: WorldId, world_id: WorldId,
pub(crate) archetype_generation: ArchetypeGeneration, pub(crate) archetype_generation: ArchetypeGeneration,
@ -40,6 +43,44 @@ impl<Q: WorldQuery, F: WorldQuery> FromWorld for QueryState<Q, F> {
} }
} }
impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
/// Converts this `QueryState` reference to a `QueryState` that does not access anything mutably.
pub fn as_readonly(&self) -> &QueryState<Q::ReadOnly, F::ReadOnly> {
// SAFETY: invariant on `WorldQuery` trait upholds that `Q::ReadOnly` and `F::ReadOnly`
// have a subset of the access, and match the exact same archetypes/tables as `Q`/`F` respectively.
unsafe { self.as_transmuted_state::<Q::ReadOnly, F::ReadOnly>() }
}
/// Converts this `QueryState` reference to a `QueryState` that does not return any data
/// which can be faster.
///
/// This doesn't use `NopWorldQuery` as it loses filter functionality, for example
/// `NopWorldQuery<Changed<T>>` is functionally equivelent to `With<T>`.
pub fn as_nop(&self) -> &QueryState<NopWorldQuery<Q>, F> {
// SAFETY: `NopWorldQuery` doesn't have any accesses and defers to
// `Q` for table/archetype matching
unsafe { self.as_transmuted_state::<NopWorldQuery<Q>, F>() }
}
/// Converts this `QueryState` reference to any other `QueryState` with
/// the same `WorldQuery::State` associated types.
///
/// Consider using `as_readonly` or `as_nop` instead which are safe functions.
///
/// # SAFETY
///
/// `NewQ` must have a subset of the access that `Q` does and match the exact same archetypes/tables
/// `NewF` must have a subset of the access that `F` does and match the exact same archetypes/tables
pub(crate) unsafe fn as_transmuted_state<
NewQ: WorldQuery<State = Q::State>,
NewF: WorldQuery<State = F::State>,
>(
&self,
) -> &QueryState<NewQ, NewF> {
&*(self as *const QueryState<Q, F> as *const QueryState<NewQ, NewF>)
}
}
impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> { impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
/// Creates a new [`QueryState`] from a given [`World`] and inherits the result of `world.id()`. /// Creates a new [`QueryState`] from a given [`World`] and inherits the result of `world.id()`.
pub fn new(world: &mut World) -> Self { pub fn new(world: &mut World) -> Self {
@ -83,7 +124,8 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
pub fn is_empty(&self, world: &World, last_change_tick: u32, change_tick: u32) -> bool { pub fn is_empty(&self, world: &World, last_change_tick: u32, change_tick: u32) -> bool {
// SAFETY: NopFetch does not access any members while &self ensures no one has exclusive access // SAFETY: NopFetch does not access any members while &self ensures no one has exclusive access
unsafe { unsafe {
self.iter_unchecked_manual::<NopFetch<Q::State>>(world, last_change_tick, change_tick) self.as_nop()
.iter_unchecked_manual(world, last_change_tick, change_tick)
.next() .next()
.is_none() .is_none()
} }
@ -162,7 +204,7 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
self.update_archetypes(world); self.update_archetypes(world);
// SAFETY: query is read only // SAFETY: query is read only
unsafe { unsafe {
self.get_unchecked_manual::<ROQueryFetch<'w, Q>>( self.as_readonly().get_unchecked_manual(
world, world,
entity, entity,
world.last_change_tick(), world.last_change_tick(),
@ -232,7 +274,7 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
self.update_archetypes(world); self.update_archetypes(world);
// SAFETY: query has unique world access // SAFETY: query has unique world access
unsafe { unsafe {
self.get_unchecked_manual::<QueryFetch<'w, Q>>( self.get_unchecked_manual(
world, world,
entity, entity,
world.last_change_tick(), world.last_change_tick(),
@ -308,7 +350,7 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
self.validate_world(world); self.validate_world(world);
// SAFETY: query is read only and world is validated // SAFETY: query is read only and world is validated
unsafe { unsafe {
self.get_unchecked_manual::<ROQueryFetch<'w, Q>>( self.as_readonly().get_unchecked_manual(
world, world,
entity, entity,
world.last_change_tick(), world.last_change_tick(),
@ -330,7 +372,7 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
entity: Entity, entity: Entity,
) -> Result<QueryItem<'w, Q>, QueryEntityError> { ) -> Result<QueryItem<'w, Q>, QueryEntityError> {
self.update_archetypes(world); self.update_archetypes(world);
self.get_unchecked_manual::<QueryFetch<'w, Q>>( self.get_unchecked_manual(
world, world,
entity, entity,
world.last_change_tick(), world.last_change_tick(),
@ -348,13 +390,13 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
/// ///
/// This must be called on the same `World` that the `Query` was generated from: /// This must be called on the same `World` that the `Query` was generated from:
/// use `QueryState::validate_world` to verify this. /// use `QueryState::validate_world` to verify this.
pub(crate) unsafe fn get_unchecked_manual<'w, QF: Fetch<'w, State = Q::State>>( pub(crate) unsafe fn get_unchecked_manual<'w>(
&self, &self,
world: &'w World, world: &'w World,
entity: Entity, entity: Entity,
last_change_tick: u32, last_change_tick: u32,
change_tick: u32, change_tick: u32,
) -> Result<QF::Item, QueryEntityError> { ) -> Result<QueryItem<'w, Q>, QueryEntityError> {
let location = world let location = world
.entities .entities
.get(entity) .get(entity)
@ -366,7 +408,8 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
return Err(QueryEntityError::QueryDoesNotMatch(entity)); return Err(QueryEntityError::QueryDoesNotMatch(entity));
} }
let archetype = &world.archetypes[location.archetype_id]; let archetype = &world.archetypes[location.archetype_id];
let mut fetch = QF::init(world, &self.fetch_state, last_change_tick, change_tick); let mut fetch =
<QueryFetch<Q> as Fetch>::init(world, &self.fetch_state, last_change_tick, change_tick);
let mut filter = <QueryFetch<F> as Fetch>::init( let mut filter = <QueryFetch<F> as Fetch>::init(
world, world,
&self.filter_state, &self.filter_state,
@ -400,12 +443,8 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
// SAFETY: fetch is read-only // SAFETY: fetch is read-only
// and world must be validated // and world must be validated
let array_of_results = entities.map(|entity| { let array_of_results = entities.map(|entity| {
self.get_unchecked_manual::<ROQueryFetch<'w, Q>>( self.as_readonly()
world, .get_unchecked_manual(world, entity, last_change_tick, change_tick)
entity,
last_change_tick,
change_tick,
)
}); });
// TODO: Replace with TryMap once https://github.com/rust-lang/rust/issues/79711 is stabilized // TODO: Replace with TryMap once https://github.com/rust-lang/rust/issues/79711 is stabilized
@ -447,14 +486,8 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
} }
} }
let array_of_results = entities.map(|entity| { let array_of_results = entities
self.get_unchecked_manual::<QueryFetch<'w, Q>>( .map(|entity| self.get_unchecked_manual(world, entity, last_change_tick, change_tick));
world,
entity,
last_change_tick,
change_tick,
)
});
// If any of the get calls failed, bubble up the error // If any of the get calls failed, bubble up the error
for result in &array_of_results { for result in &array_of_results {
@ -475,20 +508,21 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
pub fn iter<'w, 's>( pub fn iter<'w, 's>(
&'s mut self, &'s mut self,
world: &'w World, world: &'w World,
) -> QueryIter<'w, 's, Q, ROQueryFetch<'w, Q>, F> { ) -> QueryIter<'w, 's, Q::ReadOnly, F::ReadOnly> {
// SAFETY: query is read only // SAFETY: query is read only
unsafe { unsafe {
self.update_archetypes(world); self.update_archetypes(world);
self.iter_unchecked_manual(world, world.last_change_tick(), world.read_change_tick()) self.as_readonly().iter_unchecked_manual(
world,
world.last_change_tick(),
world.read_change_tick(),
)
} }
} }
/// Returns an [`Iterator`] over the query results for the given [`World`]. /// Returns an [`Iterator`] over the query results for the given [`World`].
#[inline] #[inline]
pub fn iter_mut<'w, 's>( pub fn iter_mut<'w, 's>(&'s mut self, world: &'w mut World) -> QueryIter<'w, 's, Q, F> {
&'s mut self,
world: &'w mut World,
) -> QueryIter<'w, 's, Q, QueryFetch<'w, Q>, F> {
// SAFETY: query has unique world access // SAFETY: query has unique world access
unsafe { unsafe {
self.update_archetypes(world); self.update_archetypes(world);
@ -504,11 +538,15 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
pub fn iter_manual<'w, 's>( pub fn iter_manual<'w, 's>(
&'s self, &'s self,
world: &'w World, world: &'w World,
) -> QueryIter<'w, 's, Q, ROQueryFetch<'w, Q>, F> { ) -> QueryIter<'w, 's, Q::ReadOnly, F::ReadOnly> {
self.validate_world(world); self.validate_world(world);
// SAFETY: query is read only and world is validated // SAFETY: query is read only and world is validated
unsafe { unsafe {
self.iter_unchecked_manual(world, world.last_change_tick(), world.read_change_tick()) self.as_readonly().iter_unchecked_manual(
world,
world.last_change_tick(),
world.read_change_tick(),
)
} }
} }
@ -526,11 +564,11 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
pub fn iter_combinations<'w, 's, const K: usize>( pub fn iter_combinations<'w, 's, const K: usize>(
&'s mut self, &'s mut self,
world: &'w World, world: &'w World,
) -> QueryCombinationIter<'w, 's, Q, F, K> { ) -> QueryCombinationIter<'w, 's, Q::ReadOnly, F::ReadOnly, K> {
// SAFETY: query is read only // SAFETY: query is read only
unsafe { unsafe {
self.update_archetypes(world); self.update_archetypes(world);
self.iter_combinations_unchecked_manual( self.as_readonly().iter_combinations_unchecked_manual(
world, world,
world.last_change_tick(), world.last_change_tick(),
world.read_change_tick(), world.read_change_tick(),
@ -571,14 +609,14 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
&'s mut self, &'s mut self,
world: &'w World, world: &'w World,
entities: EntityList, entities: EntityList,
) -> QueryManyIter<'w, 's, Q, ROQueryFetch<'w, Q>, F, EntityList::IntoIter> ) -> QueryManyIter<'w, 's, Q::ReadOnly, F::ReadOnly, EntityList::IntoIter>
where where
EntityList::Item: Borrow<Entity>, EntityList::Item: Borrow<Entity>,
{ {
// SAFETY: query is read only // SAFETY: query is read only
unsafe { unsafe {
self.update_archetypes(world); self.update_archetypes(world);
self.iter_many_unchecked_manual( self.as_readonly().iter_many_unchecked_manual(
entities, entities,
world, world,
world.last_change_tick(), world.last_change_tick(),
@ -597,7 +635,7 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
pub unsafe fn iter_unchecked<'w, 's>( pub unsafe fn iter_unchecked<'w, 's>(
&'s mut self, &'s mut self,
world: &'w World, world: &'w World,
) -> QueryIter<'w, 's, Q, QueryFetch<'w, Q>, F> { ) -> QueryIter<'w, 's, Q, F> {
self.update_archetypes(world); self.update_archetypes(world);
self.iter_unchecked_manual(world, world.last_change_tick(), world.read_change_tick()) self.iter_unchecked_manual(world, world.last_change_tick(), world.read_change_tick())
} }
@ -633,12 +671,12 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
/// This does not validate that `world.id()` matches `self.world_id`. Calling this on a `world` /// This does not validate that `world.id()` matches `self.world_id`. Calling this on a `world`
/// with a mismatched [`WorldId`] is unsound. /// with a mismatched [`WorldId`] is unsound.
#[inline] #[inline]
pub(crate) unsafe fn iter_unchecked_manual<'w, 's, QF: Fetch<'w, State = Q::State>>( pub(crate) unsafe fn iter_unchecked_manual<'w, 's>(
&'s self, &'s self,
world: &'w World, world: &'w World,
last_change_tick: u32, last_change_tick: u32,
change_tick: u32, change_tick: u32,
) -> QueryIter<'w, 's, Q, QF, F> { ) -> QueryIter<'w, 's, Q, F> {
QueryIter::new(world, self, last_change_tick, change_tick) QueryIter::new(world, self, last_change_tick, change_tick)
} }
@ -649,22 +687,17 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
/// ///
/// This does not check for mutable query correctness. To be safe, make sure mutable queries /// This does not check for mutable query correctness. To be safe, make sure mutable queries
/// have unique access to the components they query. /// have unique access to the components they query.
/// this does not check for entity uniqueness /// This does not check for entity uniqueness
/// This does not validate that `world.id()` matches `self.world_id`. Calling this on a `world` /// This does not validate that `world.id()` matches `self.world_id`. Calling this on a `world`
/// with a mismatched [`WorldId`] is unsound. /// with a mismatched [`WorldId`] is unsound.
#[inline] #[inline]
pub(crate) unsafe fn iter_many_unchecked_manual< pub(crate) unsafe fn iter_many_unchecked_manual<'w, 's, EntityList: IntoIterator>(
'w,
's,
QF: Fetch<'w, State = Q::State>,
EntityList: IntoIterator,
>(
&'s self, &'s self,
entities: EntityList, entities: EntityList,
world: &'w World, world: &'w World,
last_change_tick: u32, last_change_tick: u32,
change_tick: u32, change_tick: u32,
) -> QueryManyIter<'w, 's, Q, QF, F, EntityList::IntoIter> ) -> QueryManyIter<'w, 's, Q, F, EntityList::IntoIter>
where where
EntityList::Item: Borrow<Entity>, EntityList::Item: Borrow<Entity>,
{ {
@ -700,7 +733,7 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
// SAFETY: query is read only // SAFETY: query is read only
unsafe { unsafe {
self.update_archetypes(world); self.update_archetypes(world);
self.for_each_unchecked_manual::<ROQueryFetch<Q>, FN>( self.as_readonly().for_each_unchecked_manual(
world, world,
func, func,
world.last_change_tick(), world.last_change_tick(),
@ -720,7 +753,7 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
// SAFETY: query has unique world access // SAFETY: query has unique world access
unsafe { unsafe {
self.update_archetypes(world); self.update_archetypes(world);
self.for_each_unchecked_manual::<QueryFetch<Q>, FN>( self.for_each_unchecked_manual(
world, world,
func, func,
world.last_change_tick(), world.last_change_tick(),
@ -745,7 +778,7 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
func: FN, func: FN,
) { ) {
self.update_archetypes(world); self.update_archetypes(world);
self.for_each_unchecked_manual::<QueryFetch<Q>, FN>( self.for_each_unchecked_manual(
world, world,
func, func,
world.last_change_tick(), world.last_change_tick(),
@ -771,7 +804,7 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
// SAFETY: query is read only // SAFETY: query is read only
unsafe { unsafe {
self.update_archetypes(world); self.update_archetypes(world);
self.par_for_each_unchecked_manual::<ROQueryFetch<Q>, FN>( self.as_readonly().par_for_each_unchecked_manual(
world, world,
batch_size, batch_size,
func, func,
@ -796,7 +829,7 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
// SAFETY: query has unique world access // SAFETY: query has unique world access
unsafe { unsafe {
self.update_archetypes(world); self.update_archetypes(world);
self.par_for_each_unchecked_manual::<QueryFetch<Q>, FN>( self.par_for_each_unchecked_manual(
world, world,
batch_size, batch_size,
func, func,
@ -826,7 +859,7 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
func: FN, func: FN,
) { ) {
self.update_archetypes(world); self.update_archetypes(world);
self.par_for_each_unchecked_manual::<QueryFetch<Q>, FN>( self.par_for_each_unchecked_manual(
world, world,
batch_size, batch_size,
func, func,
@ -868,11 +901,7 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
/// have unique access to the components they query. /// have unique access to the components they query.
/// This does not validate that `world.id()` matches `self.world_id`. Calling this on a `world` /// This does not validate that `world.id()` matches `self.world_id`. Calling this on a `world`
/// with a mismatched [`WorldId`] is unsound. /// with a mismatched [`WorldId`] is unsound.
pub(crate) unsafe fn for_each_unchecked_manual< pub(crate) unsafe fn for_each_unchecked_manual<'w, FN: FnMut(QueryItem<'w, Q>)>(
'w,
QF: Fetch<'w, State = Q::State>,
FN: FnMut(QF::Item),
>(
&self, &self,
world: &'w World, world: &'w World,
mut func: FN, mut func: FN,
@ -881,7 +910,8 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
) { ) {
// NOTE: If you are changing query iteration code, remember to update the following places, where relevant: // NOTE: If you are changing query iteration code, remember to update the following places, where relevant:
// QueryIter, QueryIterationCursor, QueryState::for_each_unchecked_manual, QueryState::many_for_each_unchecked_manual, QueryState::par_for_each_unchecked_manual // QueryIter, QueryIterationCursor, QueryState::for_each_unchecked_manual, QueryState::many_for_each_unchecked_manual, QueryState::par_for_each_unchecked_manual
let mut fetch = QF::init(world, &self.fetch_state, last_change_tick, change_tick); let mut fetch =
<QueryFetch<Q> as Fetch>::init(world, &self.fetch_state, last_change_tick, change_tick);
let mut filter = <QueryFetch<F> as Fetch>::init( let mut filter = <QueryFetch<F> as Fetch>::init(
world, world,
&self.filter_state, &self.filter_state,
@ -938,8 +968,7 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
/// with a mismatched [`WorldId`] is unsound. /// with a mismatched [`WorldId`] is unsound.
pub(crate) unsafe fn par_for_each_unchecked_manual< pub(crate) unsafe fn par_for_each_unchecked_manual<
'w, 'w,
QF: Fetch<'w, State = Q::State>, FN: Fn(QueryItem<'w, Q>) + Send + Sync + Clone,
FN: Fn(QF::Item) + Send + Sync + Clone,
>( >(
&self, &self,
world: &'w World, world: &'w World,
@ -951,7 +980,7 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
// NOTE: If you are changing query iteration code, remember to update the following places, where relevant: // NOTE: If you are changing query iteration code, remember to update the following places, where relevant:
// QueryIter, QueryIterationCursor, QueryState::for_each_unchecked_manual, QueryState::many_for_each_unchecked_manual, QueryState::par_for_each_unchecked_manual // QueryIter, QueryIterationCursor, QueryState::for_each_unchecked_manual, QueryState::many_for_each_unchecked_manual, QueryState::par_for_each_unchecked_manual
ComputeTaskPool::get().scope(|scope| { ComputeTaskPool::get().scope(|scope| {
if QF::IS_DENSE && <QueryFetch<'static, F>>::IS_DENSE { if <QueryFetch<'static, Q>>::IS_DENSE && <QueryFetch<'static, F>>::IS_DENSE {
let tables = &world.storages().tables; let tables = &world.storages().tables;
for table_id in &self.matched_table_ids { for table_id in &self.matched_table_ids {
let table = &tables[*table_id]; let table = &tables[*table_id];
@ -960,8 +989,12 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
let func = func.clone(); let func = func.clone();
let len = batch_size.min(table.len() - offset); let len = batch_size.min(table.len() - offset);
let task = async move { let task = async move {
let mut fetch = let mut fetch = <QueryFetch<Q> as Fetch>::init(
QF::init(world, &self.fetch_state, last_change_tick, change_tick); world,
&self.fetch_state,
last_change_tick,
change_tick,
);
let mut filter = <QueryFetch<F> as Fetch>::init( let mut filter = <QueryFetch<F> as Fetch>::init(
world, world,
&self.filter_state, &self.filter_state,
@ -1002,8 +1035,12 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
let func = func.clone(); let func = func.clone();
let len = batch_size.min(archetype.len() - offset); let len = batch_size.min(archetype.len() - offset);
let task = async move { let task = async move {
let mut fetch = let mut fetch = <QueryFetch<Q> as Fetch>::init(
QF::init(world, &self.fetch_state, last_change_tick, change_tick); world,
&self.fetch_state,
last_change_tick,
change_tick,
);
let mut filter = <QueryFetch<F> as Fetch>::init( let mut filter = <QueryFetch<F> as Fetch>::init(
world, world,
&self.filter_state, &self.filter_state,
@ -1130,7 +1167,7 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
// SAFETY: query is read only // SAFETY: query is read only
unsafe { unsafe {
self.get_single_unchecked_manual::<ROQueryFetch<'w, Q>>( self.as_readonly().get_single_unchecked_manual(
world, world,
world.last_change_tick(), world.last_change_tick(),
world.read_change_tick(), world.read_change_tick(),
@ -1166,7 +1203,7 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
// SAFETY: query has unique world access // SAFETY: query has unique world access
unsafe { unsafe {
self.get_single_unchecked_manual::<QueryFetch<'w, Q>>( self.get_single_unchecked_manual(
world, world,
world.last_change_tick(), world.last_change_tick(),
world.read_change_tick(), world.read_change_tick(),
@ -1189,12 +1226,7 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
world: &'w World, world: &'w World,
) -> Result<QueryItem<'w, Q>, QuerySingleError> { ) -> Result<QueryItem<'w, Q>, QuerySingleError> {
self.update_archetypes(world); self.update_archetypes(world);
self.get_single_unchecked_manual(world, world.last_change_tick(), world.read_change_tick())
self.get_single_unchecked_manual::<QueryFetch<'w, Q>>(
world,
world.last_change_tick(),
world.read_change_tick(),
)
} }
/// Returns a query result when there is exactly one entity matching the query, /// Returns a query result when there is exactly one entity matching the query,
@ -1208,13 +1240,13 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
/// This does not check for mutable query correctness. To be safe, make sure mutable queries /// This does not check for mutable query correctness. To be safe, make sure mutable queries
/// have unique access to the components they query. /// have unique access to the components they query.
#[inline] #[inline]
pub unsafe fn get_single_unchecked_manual<'w, QF: Fetch<'w, State = Q::State>>( pub unsafe fn get_single_unchecked_manual<'w>(
&self, &self,
world: &'w World, world: &'w World,
last_change_tick: u32, last_change_tick: u32,
change_tick: u32, change_tick: u32,
) -> Result<QF::Item, QuerySingleError> { ) -> Result<QueryItem<'w, Q>, QuerySingleError> {
let mut query = self.iter_unchecked_manual::<QF>(world, last_change_tick, change_tick); let mut query = self.iter_unchecked_manual(world, last_change_tick, change_tick);
let first = query.next(); let first = query.next();
let extra = query.next().is_some(); let extra = query.next().is_some();

View File

@ -2,9 +2,8 @@ use crate::{
component::Component, component::Component,
entity::Entity, entity::Entity,
query::{ query::{
NopFetch, QueryCombinationIter, QueryEntityError, QueryFetch, QueryItem, QueryIter, QueryCombinationIter, QueryEntityError, QueryItem, QueryIter, QueryManyIter,
QueryManyIter, QuerySingleError, QueryState, ROQueryFetch, ROQueryItem, ReadOnlyWorldQuery, QuerySingleError, QueryState, ROQueryItem, ReadOnlyWorldQuery, WorldQuery,
WorldQuery,
}, },
world::{Mut, World}, world::{Mut, World},
}; };
@ -292,12 +291,15 @@ impl<'w, 's, Q: WorldQuery, F: WorldQuery> Query<'w, 's, Q, F> {
/// # bevy_ecs::system::assert_is_system(report_names_system); /// # bevy_ecs::system::assert_is_system(report_names_system);
/// ``` /// ```
#[inline] #[inline]
pub fn iter(&self) -> QueryIter<'_, 's, Q, ROQueryFetch<'_, Q>, F> { pub fn iter(&self) -> QueryIter<'_, 's, Q::ReadOnly, F::ReadOnly> {
// SAFETY: system runs without conflicts with other systems. // SAFETY: system runs without conflicts with other systems.
// same-system queries have runtime borrow checks when they conflict // same-system queries have runtime borrow checks when they conflict
unsafe { unsafe {
self.state self.state.as_readonly().iter_unchecked_manual(
.iter_unchecked_manual(self.world, self.last_change_tick, self.change_tick) self.world,
self.last_change_tick,
self.change_tick,
)
} }
} }
@ -322,7 +324,7 @@ impl<'w, 's, Q: WorldQuery, F: WorldQuery> Query<'w, 's, Q, F> {
/// # bevy_ecs::system::assert_is_system(gravity_system); /// # bevy_ecs::system::assert_is_system(gravity_system);
/// ``` /// ```
#[inline] #[inline]
pub fn iter_mut(&mut self) -> QueryIter<'_, '_, Q, QueryFetch<'_, Q>, F> { pub fn iter_mut(&mut self) -> QueryIter<'_, 's, Q, F> {
// SAFETY: system runs without conflicts with other systems. // SAFETY: system runs without conflicts with other systems.
// same-system queries have runtime borrow checks when they conflict // same-system queries have runtime borrow checks when they conflict
unsafe { unsafe {
@ -339,11 +341,13 @@ impl<'w, 's, Q: WorldQuery, F: WorldQuery> Query<'w, 's, Q, F> {
/// - if `K < N`: all possible `K`-sized combinations of query results, without repetition /// - if `K < N`: all possible `K`-sized combinations of query results, without repetition
/// - if `K > N`: empty set (no `K`-sized combinations exist) /// - if `K > N`: empty set (no `K`-sized combinations exist)
#[inline] #[inline]
pub fn iter_combinations<const K: usize>(&self) -> QueryCombinationIter<'_, '_, Q, F, K> { pub fn iter_combinations<const K: usize>(
&self,
) -> QueryCombinationIter<'_, '_, Q::ReadOnly, F::ReadOnly, K> {
// SAFETY: system runs without conflicts with other systems. // SAFETY: system runs without conflicts with other systems.
// same-system queries have runtime borrow checks when they conflict // same-system queries have runtime borrow checks when they conflict
unsafe { unsafe {
self.state.iter_combinations_unchecked_manual( self.state.as_readonly().iter_combinations_unchecked_manual(
self.world, self.world,
self.last_change_tick, self.last_change_tick,
self.change_tick, self.change_tick,
@ -422,14 +426,14 @@ impl<'w, 's, Q: WorldQuery, F: WorldQuery> Query<'w, 's, Q, F> {
pub fn iter_many<EntityList: IntoIterator>( pub fn iter_many<EntityList: IntoIterator>(
&self, &self,
entities: EntityList, entities: EntityList,
) -> QueryManyIter<'_, '_, Q, ROQueryFetch<'_, Q>, F, EntityList::IntoIter> ) -> QueryManyIter<'_, '_, Q::ReadOnly, F::ReadOnly, EntityList::IntoIter>
where where
EntityList::Item: Borrow<Entity>, EntityList::Item: Borrow<Entity>,
{ {
// SAFETY: system runs without conflicts with other systems. // SAFETY: system runs without conflicts with other systems.
// same-system queries have runtime borrow checks when they conflict // same-system queries have runtime borrow checks when they conflict
unsafe { unsafe {
self.state.iter_many_unchecked_manual( self.state.as_readonly().iter_many_unchecked_manual(
entities, entities,
self.world, self.world,
self.last_change_tick, self.last_change_tick,
@ -445,7 +449,7 @@ impl<'w, 's, Q: WorldQuery, F: WorldQuery> Query<'w, 's, Q, F> {
/// This function makes it possible to violate Rust's aliasing guarantees. You must make sure /// This function makes it possible to violate Rust's aliasing guarantees. You must make sure
/// this call does not result in multiple mutable references to the same component /// this call does not result in multiple mutable references to the same component
#[inline] #[inline]
pub unsafe fn iter_unsafe(&'s self) -> QueryIter<'w, 's, Q, QueryFetch<'w, Q>, F> { pub unsafe fn iter_unsafe(&'s self) -> QueryIter<'w, 's, Q, F> {
// SEMI-SAFETY: system runs without conflicts with other systems. // SEMI-SAFETY: system runs without conflicts with other systems.
// same-system queries have runtime borrow checks when they conflict // same-system queries have runtime borrow checks when they conflict
self.state self.state
@ -482,7 +486,7 @@ impl<'w, 's, Q: WorldQuery, F: WorldQuery> Query<'w, 's, Q, F> {
pub unsafe fn iter_many_unsafe<EntityList: IntoIterator>( pub unsafe fn iter_many_unsafe<EntityList: IntoIterator>(
&self, &self,
entities: EntityList, entities: EntityList,
) -> QueryManyIter<'_, '_, Q, QueryFetch<'_, Q>, F, EntityList::IntoIter> ) -> QueryManyIter<'_, '_, Q, F, EntityList::IntoIter>
where where
EntityList::Item: Borrow<Entity>, EntityList::Item: Borrow<Entity>,
{ {
@ -522,7 +526,7 @@ impl<'w, 's, Q: WorldQuery, F: WorldQuery> Query<'w, 's, Q, F> {
// SAFETY: system runs without conflicts with other systems. // SAFETY: system runs without conflicts with other systems.
// same-system queries have runtime borrow checks when they conflict // same-system queries have runtime borrow checks when they conflict
unsafe { unsafe {
self.state.for_each_unchecked_manual::<ROQueryFetch<Q>, _>( self.state.as_readonly().for_each_unchecked_manual(
self.world, self.world,
f, f,
self.last_change_tick, self.last_change_tick,
@ -557,7 +561,7 @@ impl<'w, 's, Q: WorldQuery, F: WorldQuery> Query<'w, 's, Q, F> {
// SAFETY: system runs without conflicts with other systems. same-system queries have runtime // SAFETY: system runs without conflicts with other systems. same-system queries have runtime
// borrow checks when they conflict // borrow checks when they conflict
unsafe { unsafe {
self.state.for_each_unchecked_manual::<QueryFetch<Q>, FN>( self.state.for_each_unchecked_manual(
self.world, self.world,
f, f,
self.last_change_tick, self.last_change_tick,
@ -600,14 +604,13 @@ impl<'w, 's, Q: WorldQuery, F: WorldQuery> Query<'w, 's, Q, F> {
// SAFETY: system runs without conflicts with other systems. same-system queries have runtime // SAFETY: system runs without conflicts with other systems. same-system queries have runtime
// borrow checks when they conflict // borrow checks when they conflict
unsafe { unsafe {
self.state self.state.as_readonly().par_for_each_unchecked_manual(
.par_for_each_unchecked_manual::<ROQueryFetch<Q>, _>( self.world,
self.world, batch_size,
batch_size, f,
f, self.last_change_tick,
self.last_change_tick, self.change_tick,
self.change_tick, );
);
}; };
} }
@ -628,14 +631,13 @@ impl<'w, 's, Q: WorldQuery, F: WorldQuery> Query<'w, 's, Q, F> {
// SAFETY: system runs without conflicts with other systems. same-system queries have runtime // SAFETY: system runs without conflicts with other systems. same-system queries have runtime
// borrow checks when they conflict // borrow checks when they conflict
unsafe { unsafe {
self.state self.state.par_for_each_unchecked_manual(
.par_for_each_unchecked_manual::<QueryFetch<Q>, FN>( self.world,
self.world, batch_size,
batch_size, f,
f, self.last_change_tick,
self.last_change_tick, self.change_tick,
self.change_tick, );
);
}; };
} }
@ -724,7 +726,7 @@ impl<'w, 's, Q: WorldQuery, F: WorldQuery> Query<'w, 's, Q, F> {
// SAFETY: system runs without conflicts with other systems. // SAFETY: system runs without conflicts with other systems.
// same-system queries have runtime borrow checks when they conflict // same-system queries have runtime borrow checks when they conflict
unsafe { unsafe {
self.state.get_unchecked_manual::<ROQueryFetch<Q>>( self.state.as_readonly().get_unchecked_manual(
self.world, self.world,
entity, entity,
self.last_change_tick, self.last_change_tick,
@ -826,7 +828,7 @@ impl<'w, 's, Q: WorldQuery, F: WorldQuery> Query<'w, 's, Q, F> {
// SAFETY: system runs without conflicts with other systems. // SAFETY: system runs without conflicts with other systems.
// same-system queries have runtime borrow checks when they conflict // same-system queries have runtime borrow checks when they conflict
unsafe { unsafe {
self.state.get_unchecked_manual::<QueryFetch<Q>>( self.state.get_unchecked_manual(
self.world, self.world,
entity, entity,
self.last_change_tick, self.last_change_tick,
@ -919,12 +921,8 @@ impl<'w, 's, Q: WorldQuery, F: WorldQuery> Query<'w, 's, Q, F> {
) -> Result<QueryItem<'w, Q>, QueryEntityError> { ) -> Result<QueryItem<'w, Q>, QueryEntityError> {
// SEMI-SAFETY: system runs without conflicts with other systems. // SEMI-SAFETY: system runs without conflicts with other systems.
// same-system queries have runtime borrow checks when they conflict // same-system queries have runtime borrow checks when they conflict
self.state.get_unchecked_manual::<QueryFetch<Q>>( self.state
self.world, .get_unchecked_manual(self.world, entity, self.last_change_tick, self.change_tick)
entity,
self.last_change_tick,
self.change_tick,
)
} }
/// Returns a reference to the [`Entity`]'s [`Component`] of the given type. /// Returns a reference to the [`Entity`]'s [`Component`] of the given type.
@ -1121,7 +1119,7 @@ impl<'w, 's, Q: WorldQuery, F: WorldQuery> Query<'w, 's, Q, F> {
// the query ensures that the components it accesses are not mutably accessible somewhere else // the query ensures that the components it accesses are not mutably accessible somewhere else
// and the query is read only. // and the query is read only.
unsafe { unsafe {
self.state.get_single_unchecked_manual::<ROQueryFetch<Q>>( self.state.as_readonly().get_single_unchecked_manual(
self.world, self.world,
self.last_change_tick, self.last_change_tick,
self.change_tick, self.change_tick,
@ -1186,7 +1184,7 @@ impl<'w, 's, Q: WorldQuery, F: WorldQuery> Query<'w, 's, Q, F> {
// the query ensures mutable access to the components it accesses, and the query // the query ensures mutable access to the components it accesses, and the query
// is uniquely borrowed // is uniquely borrowed
unsafe { unsafe {
self.state.get_single_unchecked_manual::<QueryFetch<Q>>( self.state.get_single_unchecked_manual(
self.world, self.world,
self.last_change_tick, self.last_change_tick,
self.change_tick, self.change_tick,
@ -1247,12 +1245,8 @@ impl<'w, 's, Q: WorldQuery, F: WorldQuery> Query<'w, 's, Q, F> {
// SAFETY: NopFetch does not access any members while &self ensures no one has exclusive access // SAFETY: NopFetch does not access any members while &self ensures no one has exclusive access
unsafe { unsafe {
self.state self.state
.get_unchecked_manual::<NopFetch<Q::State>>( .as_nop()
self.world, .get_unchecked_manual(self.world, entity, self.last_change_tick, self.change_tick)
entity,
self.last_change_tick,
self.change_tick,
)
.is_ok() .is_ok()
} }
} }
@ -1260,16 +1254,16 @@ impl<'w, 's, Q: WorldQuery, F: WorldQuery> Query<'w, 's, Q, F> {
impl<'w, 's, Q: WorldQuery, F: WorldQuery> IntoIterator for &'w Query<'_, 's, Q, F> { impl<'w, 's, Q: WorldQuery, F: WorldQuery> IntoIterator for &'w Query<'_, 's, Q, F> {
type Item = ROQueryItem<'w, Q>; type Item = ROQueryItem<'w, Q>;
type IntoIter = QueryIter<'w, 's, Q, ROQueryFetch<'w, Q>, F>; type IntoIter = QueryIter<'w, 's, Q::ReadOnly, F::ReadOnly>;
fn into_iter(self) -> Self::IntoIter { fn into_iter(self) -> Self::IntoIter {
self.iter() self.iter()
} }
} }
impl<'w, Q: WorldQuery, F: WorldQuery> IntoIterator for &'w mut Query<'_, '_, Q, F> { impl<'w, 's, Q: WorldQuery, F: WorldQuery> IntoIterator for &'w mut Query<'_, 's, Q, F> {
type Item = QueryItem<'w, Q>; type Item = QueryItem<'w, Q>;
type IntoIter = QueryIter<'w, 'w, Q, QueryFetch<'w, Q>, F>; type IntoIter = QueryIter<'w, 's, Q, F>;
fn into_iter(self) -> Self::IntoIter { fn into_iter(self) -> Self::IntoIter {
self.iter_mut() self.iter_mut()
@ -1349,7 +1343,7 @@ impl<'w, 's, Q: ReadOnlyWorldQuery, F: WorldQuery> Query<'w, 's, Q, F> {
// SAFETY: system runs without conflicts with other systems. // SAFETY: system runs without conflicts with other systems.
// same-system queries have runtime borrow checks when they conflict // same-system queries have runtime borrow checks when they conflict
unsafe { unsafe {
self.state.get_unchecked_manual::<ROQueryFetch<'w, Q>>( self.state.as_readonly().get_unchecked_manual(
self.world, self.world,
entity, entity,
self.last_change_tick, self.last_change_tick,
@ -1382,12 +1376,15 @@ impl<'w, 's, Q: ReadOnlyWorldQuery, F: WorldQuery> Query<'w, 's, Q, F> {
/// # bevy_ecs::system::assert_is_system(report_names_system); /// # bevy_ecs::system::assert_is_system(report_names_system);
/// ``` /// ```
#[inline] #[inline]
pub fn iter_inner(&'s self) -> QueryIter<'w, 's, Q, ROQueryFetch<'w, Q>, F> { pub fn iter_inner(&'s self) -> QueryIter<'w, 's, Q::ReadOnly, F::ReadOnly> {
// SAFETY: system runs without conflicts with other systems. // SAFETY: system runs without conflicts with other systems.
// same-system queries have runtime borrow checks when they conflict // same-system queries have runtime borrow checks when they conflict
unsafe { unsafe {
self.state self.state.as_readonly().iter_unchecked_manual(
.iter_unchecked_manual(self.world, self.last_change_tick, self.change_tick) self.world,
self.last_change_tick,
self.change_tick,
)
} }
} }
} }

View File

@ -16,7 +16,7 @@ error[E0277]: the trait bound `bevy_ecs::query::Changed<Foo>: ArchetypeFilter` i
(F0, F1, F2, F3, F4, F5, F6) (F0, F1, F2, F3, F4, F5, F6)
(F0, F1, F2, F3, F4, F5, F6, F7) (F0, F1, F2, F3, F4, F5, F6, F7)
and 26 others and 26 others
= note: required because of the requirements on the impl of `ExactSizeIterator` for `QueryIter<'_, '_, &Foo, ReadFetch<'_, Foo>, bevy_ecs::query::Changed<Foo>>` = note: required because of the requirements on the impl of `ExactSizeIterator` for `QueryIter<'_, '_, &Foo, bevy_ecs::query::Changed<Foo>>`
note: required by a bound in `is_exact_size_iterator` note: required by a bound in `is_exact_size_iterator`
--> tests/ui/query_exact_sized_iterator_safety.rs:16:30 --> tests/ui/query_exact_sized_iterator_safety.rs:16:30
| |
@ -41,7 +41,7 @@ error[E0277]: the trait bound `bevy_ecs::query::Added<Foo>: ArchetypeFilter` is
(F0, F1, F2, F3, F4, F5, F6) (F0, F1, F2, F3, F4, F5, F6)
(F0, F1, F2, F3, F4, F5, F6, F7) (F0, F1, F2, F3, F4, F5, F6, F7)
and 26 others and 26 others
= note: required because of the requirements on the impl of `ExactSizeIterator` for `QueryIter<'_, '_, &Foo, ReadFetch<'_, Foo>, bevy_ecs::query::Added<Foo>>` = note: required because of the requirements on the impl of `ExactSizeIterator` for `QueryIter<'_, '_, &Foo, bevy_ecs::query::Added<Foo>>`
note: required by a bound in `is_exact_size_iterator` note: required by a bound in `is_exact_size_iterator`
--> tests/ui/query_exact_sized_iterator_safety.rs:16:30 --> tests/ui/query_exact_sized_iterator_safety.rs:16:30
| |

View File

@ -21,7 +21,7 @@ error[E0277]: the trait bound `&'static mut Foo: ReadOnlyWorldQuery` is not sati
(F0, F1, F2, F3, F4) (F0, F1, F2, F3, F4)
(F0, F1, F2, F3, F4, F5) (F0, F1, F2, F3, F4, F5)
(F0, F1, F2, F3, F4, F5, F6) (F0, F1, F2, F3, F4, F5, F6)
and 48 others and 49 others
= note: `ReadOnlyWorldQuery` is implemented for `&'static Foo`, but not for `&'static mut Foo` = note: `ReadOnlyWorldQuery` is implemented for `&'static Foo`, but not for `&'static mut Foo`
= note: required because of the requirements on the impl of `ReadOnlySystemParamFetch` for `QueryState<&'static mut Foo>` = note: required because of the requirements on the impl of `ReadOnlySystemParamFetch` for `QueryState<&'static mut Foo>`
= note: 2 redundant requirements hidden = note: 2 redundant requirements hidden

View File

@ -13,7 +13,7 @@ error[E0277]: the trait bound `&'static mut Foo: ReadOnlyWorldQuery` is not sati
(F0, F1, F2, F3, F4) (F0, F1, F2, F3, F4)
(F0, F1, F2, F3, F4, F5) (F0, F1, F2, F3, F4, F5)
(F0, F1, F2, F3, F4, F5, F6) (F0, F1, F2, F3, F4, F5, F6)
and 51 others and 52 others
note: required by a bound in `_::assert_readonly` note: required by a bound in `_::assert_readonly`
--> tests/ui/world_query_derive.rs:7:10 --> tests/ui/world_query_derive.rs:7:10
| |
@ -36,7 +36,7 @@ error[E0277]: the trait bound `MutableMarked: ReadOnlyWorldQuery` is not satisfi
(F0, F1, F2, F3, F4) (F0, F1, F2, F3, F4)
(F0, F1, F2, F3, F4, F5) (F0, F1, F2, F3, F4, F5)
(F0, F1, F2, F3, F4, F5, F6) (F0, F1, F2, F3, F4, F5, F6)
and 51 others and 52 others
note: required by a bound in `_::assert_readonly` note: required by a bound in `_::assert_readonly`
--> tests/ui/world_query_derive.rs:18:10 --> tests/ui/world_query_derive.rs:18:10
| |