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
///
/// 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> {
type ReadOnly: ReadOnlyWorldQuery<State = Self::State>;
type State: FetchState;
@ -1608,6 +1609,25 @@ macro_rules! impl_anytuple_fetch {
all_tuples!(impl_tuple_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
///
/// 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
unsafe impl<'w, State: FetchState> Fetch<'w> for NopFetch<State> {
unsafe impl<'w, F: Fetch<'w>> Fetch<'w> for NopFetch<F> {
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;
#[inline(always)]
unsafe fn init(
_world: &'w World,
_state: &State,
_state: &F::State,
_last_change_tick: u32,
_change_tick: u32,
) -> 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
/// [`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,
archetypes: &'w Archetypes,
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>
where
QF: Fetch<'w, State = Q::State>,
{
impl<'w, 's, Q: WorldQuery, F: WorldQuery> QueryIter<'w, 's, Q, F> {
/// # Safety
/// This does not check for mutable query correctness. To be safe, make sure mutable queries
/// 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>
where
QF: Fetch<'w, State = Q::State>,
{
type Item = QF::Item;
impl<'w, 's, Q: WorldQuery, F: WorldQuery> Iterator for QueryIter<'w, 's, Q, F> {
type Item = QueryItem<'w, Q>;
#[inline(always)]
fn next(&mut self) -> Option<Self::Item> {
@ -69,42 +63,32 @@ where
.map(|id| self.archetypes[*id].len())
.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 };
(min_size, Some(max_size))
}
}
// 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
QF: Fetch<'w, State = Q::State>
{
}
impl<'w, 's, Q: WorldQuery, F: WorldQuery> FusedIterator for QueryIter<'w, 's, Q, F> {}
/// 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.
pub struct QueryManyIter<
'w,
's,
Q: WorldQuery,
QF: Fetch<'w, State = Q::State>,
F: WorldQuery,
I: Iterator,
> where
pub struct QueryManyIter<'w, 's, Q: WorldQuery, F: WorldQuery, I: Iterator>
where
I::Item: Borrow<Entity>,
{
entity_iter: I,
entities: &'w Entities,
tables: &'w Tables,
archetypes: &'w Archetypes,
fetch: QF,
fetch: QueryFetch<'w, Q>,
filter: QueryFetch<'w, F>,
query_state: &'s QueryState<Q, F>,
}
impl<'w, 's, Q: WorldQuery, QF: Fetch<'w, State = Q::State>, F: WorldQuery, I: Iterator>
QueryManyIter<'w, 's, Q, QF, F, I>
impl<'w, 's, Q: WorldQuery, F: WorldQuery, I: Iterator> QueryManyIter<'w, 's, Q, F, I>
where
I::Item: Borrow<Entity>,
{
@ -119,14 +103,14 @@ where
entity_list: EntityList,
last_change_tick: u32,
change_tick: u32,
) -> QueryManyIter<'w, 's, Q, QF, F, I> {
let fetch = QF::init(
) -> QueryManyIter<'w, 's, Q, F, I> {
let fetch = Q::Fetch::init(
world,
&query_state.fetch_state,
last_change_tick,
change_tick,
);
let filter = QueryFetch::<F>::init(
let filter = F::Fetch::init(
world,
&query_state.filter_state,
last_change_tick,
@ -144,12 +128,11 @@ where
}
}
impl<'w, 's, Q: WorldQuery, QF: Fetch<'w, State = Q::State>, F: WorldQuery, I: Iterator> Iterator
for QueryManyIter<'w, 's, Q, QF, F, I>
impl<'w, 's, Q: WorldQuery, F: WorldQuery, I: Iterator> Iterator for QueryManyIter<'w, 's, Q, F, I>
where
I::Item: Borrow<Entity>,
{
type Item = QF::Item;
type Item = QueryItem<'w, Q>;
#[inline(always)]
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,
archetypes: &'w Archetypes,
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> {
@ -219,11 +202,10 @@ impl<'w, 's, Q: WorldQuery, F: WorldQuery, const K: usize> QueryCombinationIter<
// Initialize array with cursors.
// 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]> =
MaybeUninit::uninit();
let mut array: MaybeUninit<[QueryIterationCursor<'w, 's, Q, F>; K]> = MaybeUninit::uninit();
let ptr = array
.as_mut_ptr()
.cast::<QueryIterationCursor<'w, 's, Q, QueryFetch<'w, Q>, F>>();
.cast::<QueryIterationCursor<'w, 's, Q, F>>();
if K != 0 {
ptr.write(QueryIterationCursor::init(
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
QF: Fetch<'w, State = Q::State>,
F: WorldQuery + ArchetypeFilter,
F: ArchetypeFilter,
{
fn len(&self) -> usize {
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>,
archetype_id_iter: std::slice::Iter<'s, ArchetypeId>,
fetch: QF,
fetch: QueryFetch<'w, Q>,
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
current_len: usize,
// either table row or archetype index, depending on whether both `Q`'s and `F`'s fetches are dense
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
QF: Fetch<'w, State = Q::State> + Clone,
QueryFetch<'w, Q>: Clone,
QueryFetch<'w, F>: Clone,
{
fn clone(&self) -> Self {
@ -435,11 +416,8 @@ where
}
}
impl<'w, 's, Q: WorldQuery, QF, F: WorldQuery> QueryIterationCursor<'w, 's, Q, QF, F>
where
QF: Fetch<'w, State = Q::State>,
{
const IS_DENSE: bool = QF::IS_DENSE && <QueryFetch<'static, F>>::IS_DENSE;
impl<'w, 's, Q: WorldQuery, F: WorldQuery> QueryIterationCursor<'w, 's, Q, F> {
const IS_DENSE: bool = Q::Fetch::IS_DENSE && F::Fetch::IS_DENSE;
unsafe fn init_empty(
world: &'w World,
@ -460,13 +438,13 @@ where
last_change_tick: u32,
change_tick: u32,
) -> Self {
let fetch = QF::init(
let fetch = Q::Fetch::init(
world,
&query_state.fetch_state,
last_change_tick,
change_tick,
);
let filter = QueryFetch::<F>::init(
let filter = F::Fetch::init(
world,
&query_state.filter_state,
last_change_tick,
@ -485,7 +463,7 @@ where
/// retrieve item returned from most recent `next` call again.
#[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::IS_DENSE {
Some(self.fetch.table_fetch(self.current_index - 1))
@ -509,7 +487,7 @@ where
tables: &'w Tables,
archetypes: &'w Archetypes,
query_state: &'s QueryState<Q, F>,
) -> Option<QF::Item> {
) -> Option<QueryItem<'w, Q>> {
if Self::IS_DENSE {
loop {
// 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 {
use super::WorldQuery;
use crate::prelude::{AnyOf, Entity, Or, QueryState, With, Without};
use crate::query::{ArchetypeFilter, QueryCombinationIter, QueryFetch, ReadOnlyWorldQuery};
use crate::system::{IntoSystem, Query, System};
use crate::query::{ArchetypeFilter, QueryCombinationIter, QueryFetch};
use crate::system::{IntoSystem, Query, System, SystemState};
use crate::{self as bevy_ecs, component::Component, world::World};
use std::any::type_name;
use std::collections::HashSet;
@ -67,10 +67,11 @@ mod tests {
}
fn assert_combination<Q, F, const K: usize>(world: &mut World, expected_size: usize)
where
Q: ReadOnlyWorldQuery,
F: ReadOnlyWorldQuery + ArchetypeFilter,
for<'w> QueryFetch<'w, Q>: Clone,
for<'w> QueryFetch<'w, F>: Clone,
Q: WorldQuery,
F: WorldQuery,
F::ReadOnly: ArchetypeFilter,
for<'w> QueryFetch<'w, Q::ReadOnly>: Clone,
for<'w> QueryFetch<'w, F::ReadOnly>: Clone,
{
let mut query = world.query_filtered::<Q, F>();
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)
where
Q: ReadOnlyWorldQuery,
F: ReadOnlyWorldQuery + ArchetypeFilter,
for<'w> QueryFetch<'w, Q>: Clone,
for<'w> QueryFetch<'w, F>: Clone,
Q: WorldQuery,
F: WorldQuery,
F::ReadOnly: ArchetypeFilter,
for<'w> QueryFetch<'w, Q::ReadOnly>: Clone,
for<'w> QueryFetch<'w, F::ReadOnly>: Clone,
{
let mut query = world.query_filtered::<Q, F>();
let iter = query.iter(world);
@ -653,4 +655,42 @@ count(): {count}"#
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,
prelude::FromWorld,
query::{
Access, Fetch, FetchState, FilteredAccess, NopFetch, QueryCombinationIter, QueryIter,
WorldQuery,
Access, Fetch, FetchState, FilteredAccess, QueryCombinationIter, QueryIter, WorldQuery,
},
storage::TableId,
world::{World, WorldId},
@ -16,9 +15,13 @@ use bevy_utils::tracing::Instrument;
use fixedbitset::FixedBitSet;
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.
#[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 = ()> {
world_id: WorldId,
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> {
/// Creates a new [`QueryState`] from a given [`World`] and inherits the result of `world.id()`.
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 {
// SAFETY: NopFetch does not access any members while &self ensures no one has exclusive access
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()
.is_none()
}
@ -162,7 +204,7 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
self.update_archetypes(world);
// SAFETY: query is read only
unsafe {
self.get_unchecked_manual::<ROQueryFetch<'w, Q>>(
self.as_readonly().get_unchecked_manual(
world,
entity,
world.last_change_tick(),
@ -232,7 +274,7 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
self.update_archetypes(world);
// SAFETY: query has unique world access
unsafe {
self.get_unchecked_manual::<QueryFetch<'w, Q>>(
self.get_unchecked_manual(
world,
entity,
world.last_change_tick(),
@ -308,7 +350,7 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
self.validate_world(world);
// SAFETY: query is read only and world is validated
unsafe {
self.get_unchecked_manual::<ROQueryFetch<'w, Q>>(
self.as_readonly().get_unchecked_manual(
world,
entity,
world.last_change_tick(),
@ -330,7 +372,7 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
entity: Entity,
) -> Result<QueryItem<'w, Q>, QueryEntityError> {
self.update_archetypes(world);
self.get_unchecked_manual::<QueryFetch<'w, Q>>(
self.get_unchecked_manual(
world,
entity,
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:
/// 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,
world: &'w World,
entity: Entity,
last_change_tick: u32,
change_tick: u32,
) -> Result<QF::Item, QueryEntityError> {
) -> Result<QueryItem<'w, Q>, QueryEntityError> {
let location = world
.entities
.get(entity)
@ -366,7 +408,8 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
return Err(QueryEntityError::QueryDoesNotMatch(entity));
}
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(
world,
&self.filter_state,
@ -400,12 +443,8 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
// SAFETY: fetch is read-only
// and world must be validated
let array_of_results = entities.map(|entity| {
self.get_unchecked_manual::<ROQueryFetch<'w, Q>>(
world,
entity,
last_change_tick,
change_tick,
)
self.as_readonly()
.get_unchecked_manual(world, entity, last_change_tick, change_tick)
});
// 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| {
self.get_unchecked_manual::<QueryFetch<'w, Q>>(
world,
entity,
last_change_tick,
change_tick,
)
});
let array_of_results = entities
.map(|entity| self.get_unchecked_manual(world, entity, last_change_tick, change_tick));
// If any of the get calls failed, bubble up the error
for result in &array_of_results {
@ -475,20 +508,21 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
pub fn iter<'w, 's>(
&'s mut self,
world: &'w World,
) -> QueryIter<'w, 's, Q, ROQueryFetch<'w, Q>, F> {
) -> QueryIter<'w, 's, Q::ReadOnly, F::ReadOnly> {
// SAFETY: query is read only
unsafe {
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`].
#[inline]
pub fn iter_mut<'w, 's>(
&'s mut self,
world: &'w mut World,
) -> QueryIter<'w, 's, Q, QueryFetch<'w, Q>, F> {
pub fn iter_mut<'w, 's>(&'s mut self, world: &'w mut World) -> QueryIter<'w, 's, Q, F> {
// SAFETY: query has unique world access
unsafe {
self.update_archetypes(world);
@ -504,11 +538,15 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
pub fn iter_manual<'w, 's>(
&'s self,
world: &'w World,
) -> QueryIter<'w, 's, Q, ROQueryFetch<'w, Q>, F> {
) -> QueryIter<'w, 's, Q::ReadOnly, F::ReadOnly> {
self.validate_world(world);
// SAFETY: query is read only and world is validated
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>(
&'s mut self,
world: &'w World,
) -> QueryCombinationIter<'w, 's, Q, F, K> {
) -> QueryCombinationIter<'w, 's, Q::ReadOnly, F::ReadOnly, K> {
// SAFETY: query is read only
unsafe {
self.update_archetypes(world);
self.iter_combinations_unchecked_manual(
self.as_readonly().iter_combinations_unchecked_manual(
world,
world.last_change_tick(),
world.read_change_tick(),
@ -571,14 +609,14 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
&'s mut self,
world: &'w World,
entities: EntityList,
) -> QueryManyIter<'w, 's, Q, ROQueryFetch<'w, Q>, F, EntityList::IntoIter>
) -> QueryManyIter<'w, 's, Q::ReadOnly, F::ReadOnly, EntityList::IntoIter>
where
EntityList::Item: Borrow<Entity>,
{
// SAFETY: query is read only
unsafe {
self.update_archetypes(world);
self.iter_many_unchecked_manual(
self.as_readonly().iter_many_unchecked_manual(
entities,
world,
world.last_change_tick(),
@ -597,7 +635,7 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
pub unsafe fn iter_unchecked<'w, 's>(
&'s mut self,
world: &'w World,
) -> QueryIter<'w, 's, Q, QueryFetch<'w, Q>, F> {
) -> QueryIter<'w, 's, Q, F> {
self.update_archetypes(world);
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`
/// with a mismatched [`WorldId`] is unsound.
#[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,
world: &'w World,
last_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)
}
@ -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
/// 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`
/// with a mismatched [`WorldId`] is unsound.
#[inline]
pub(crate) unsafe fn iter_many_unchecked_manual<
'w,
's,
QF: Fetch<'w, State = Q::State>,
EntityList: IntoIterator,
>(
pub(crate) unsafe fn iter_many_unchecked_manual<'w, 's, EntityList: IntoIterator>(
&'s self,
entities: EntityList,
world: &'w World,
last_change_tick: u32,
change_tick: u32,
) -> QueryManyIter<'w, 's, Q, QF, F, EntityList::IntoIter>
) -> QueryManyIter<'w, 's, Q, F, EntityList::IntoIter>
where
EntityList::Item: Borrow<Entity>,
{
@ -700,7 +733,7 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
// SAFETY: query is read only
unsafe {
self.update_archetypes(world);
self.for_each_unchecked_manual::<ROQueryFetch<Q>, FN>(
self.as_readonly().for_each_unchecked_manual(
world,
func,
world.last_change_tick(),
@ -720,7 +753,7 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
// SAFETY: query has unique world access
unsafe {
self.update_archetypes(world);
self.for_each_unchecked_manual::<QueryFetch<Q>, FN>(
self.for_each_unchecked_manual(
world,
func,
world.last_change_tick(),
@ -745,7 +778,7 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
func: FN,
) {
self.update_archetypes(world);
self.for_each_unchecked_manual::<QueryFetch<Q>, FN>(
self.for_each_unchecked_manual(
world,
func,
world.last_change_tick(),
@ -771,7 +804,7 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
// SAFETY: query is read only
unsafe {
self.update_archetypes(world);
self.par_for_each_unchecked_manual::<ROQueryFetch<Q>, FN>(
self.as_readonly().par_for_each_unchecked_manual(
world,
batch_size,
func,
@ -796,7 +829,7 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
// SAFETY: query has unique world access
unsafe {
self.update_archetypes(world);
self.par_for_each_unchecked_manual::<QueryFetch<Q>, FN>(
self.par_for_each_unchecked_manual(
world,
batch_size,
func,
@ -826,7 +859,7 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
func: FN,
) {
self.update_archetypes(world);
self.par_for_each_unchecked_manual::<QueryFetch<Q>, FN>(
self.par_for_each_unchecked_manual(
world,
batch_size,
func,
@ -868,11 +901,7 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
/// have unique access to the components they query.
/// This does not validate that `world.id()` matches `self.world_id`. Calling this on a `world`
/// with a mismatched [`WorldId`] is unsound.
pub(crate) unsafe fn for_each_unchecked_manual<
'w,
QF: Fetch<'w, State = Q::State>,
FN: FnMut(QF::Item),
>(
pub(crate) unsafe fn for_each_unchecked_manual<'w, FN: FnMut(QueryItem<'w, Q>)>(
&self,
world: &'w World,
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:
// 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(
world,
&self.filter_state,
@ -938,8 +968,7 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
/// with a mismatched [`WorldId`] is unsound.
pub(crate) unsafe fn par_for_each_unchecked_manual<
'w,
QF: Fetch<'w, State = Q::State>,
FN: Fn(QF::Item) + Send + Sync + Clone,
FN: Fn(QueryItem<'w, Q>) + Send + Sync + Clone,
>(
&self,
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:
// QueryIter, QueryIterationCursor, QueryState::for_each_unchecked_manual, QueryState::many_for_each_unchecked_manual, QueryState::par_for_each_unchecked_manual
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;
for table_id in &self.matched_table_ids {
let table = &tables[*table_id];
@ -960,8 +989,12 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
let func = func.clone();
let len = batch_size.min(table.len() - offset);
let task = async move {
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(
world,
&self.filter_state,
@ -1002,8 +1035,12 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
let func = func.clone();
let len = batch_size.min(archetype.len() - offset);
let task = async move {
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(
world,
&self.filter_state,
@ -1130,7 +1167,7 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
// SAFETY: query is read only
unsafe {
self.get_single_unchecked_manual::<ROQueryFetch<'w, Q>>(
self.as_readonly().get_single_unchecked_manual(
world,
world.last_change_tick(),
world.read_change_tick(),
@ -1166,7 +1203,7 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
// SAFETY: query has unique world access
unsafe {
self.get_single_unchecked_manual::<QueryFetch<'w, Q>>(
self.get_single_unchecked_manual(
world,
world.last_change_tick(),
world.read_change_tick(),
@ -1189,12 +1226,7 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
world: &'w World,
) -> Result<QueryItem<'w, Q>, QuerySingleError> {
self.update_archetypes(world);
self.get_single_unchecked_manual::<QueryFetch<'w, Q>>(
world,
world.last_change_tick(),
world.read_change_tick(),
)
self.get_single_unchecked_manual(world, world.last_change_tick(), world.read_change_tick())
}
/// 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
/// have unique access to the components they query.
#[inline]
pub unsafe fn get_single_unchecked_manual<'w, QF: Fetch<'w, State = Q::State>>(
pub unsafe fn get_single_unchecked_manual<'w>(
&self,
world: &'w World,
last_change_tick: u32,
change_tick: u32,
) -> Result<QF::Item, QuerySingleError> {
let mut query = self.iter_unchecked_manual::<QF>(world, last_change_tick, change_tick);
) -> Result<QueryItem<'w, Q>, QuerySingleError> {
let mut query = self.iter_unchecked_manual(world, last_change_tick, change_tick);
let first = query.next();
let extra = query.next().is_some();

View file

@ -2,9 +2,8 @@ use crate::{
component::Component,
entity::Entity,
query::{
NopFetch, QueryCombinationIter, QueryEntityError, QueryFetch, QueryItem, QueryIter,
QueryManyIter, QuerySingleError, QueryState, ROQueryFetch, ROQueryItem, ReadOnlyWorldQuery,
WorldQuery,
QueryCombinationIter, QueryEntityError, QueryItem, QueryIter, QueryManyIter,
QuerySingleError, QueryState, ROQueryItem, ReadOnlyWorldQuery, WorldQuery,
},
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);
/// ```
#[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.
// same-system queries have runtime borrow checks when they conflict
unsafe {
self.state
.iter_unchecked_manual(self.world, self.last_change_tick, self.change_tick)
self.state.as_readonly().iter_unchecked_manual(
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);
/// ```
#[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.
// same-system queries have runtime borrow checks when they conflict
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`: empty set (no `K`-sized combinations exist)
#[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.
// same-system queries have runtime borrow checks when they conflict
unsafe {
self.state.iter_combinations_unchecked_manual(
self.state.as_readonly().iter_combinations_unchecked_manual(
self.world,
self.last_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>(
&self,
entities: EntityList,
) -> QueryManyIter<'_, '_, Q, ROQueryFetch<'_, Q>, F, EntityList::IntoIter>
) -> QueryManyIter<'_, '_, Q::ReadOnly, F::ReadOnly, EntityList::IntoIter>
where
EntityList::Item: Borrow<Entity>,
{
// SAFETY: system runs without conflicts with other systems.
// same-system queries have runtime borrow checks when they conflict
unsafe {
self.state.iter_many_unchecked_manual(
self.state.as_readonly().iter_many_unchecked_manual(
entities,
self.world,
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 call does not result in multiple mutable references to the same component
#[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.
// same-system queries have runtime borrow checks when they conflict
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>(
&self,
entities: EntityList,
) -> QueryManyIter<'_, '_, Q, QueryFetch<'_, Q>, F, EntityList::IntoIter>
) -> QueryManyIter<'_, '_, Q, F, EntityList::IntoIter>
where
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.
// same-system queries have runtime borrow checks when they conflict
unsafe {
self.state.for_each_unchecked_manual::<ROQueryFetch<Q>, _>(
self.state.as_readonly().for_each_unchecked_manual(
self.world,
f,
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
// borrow checks when they conflict
unsafe {
self.state.for_each_unchecked_manual::<QueryFetch<Q>, FN>(
self.state.for_each_unchecked_manual(
self.world,
f,
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
// borrow checks when they conflict
unsafe {
self.state
.par_for_each_unchecked_manual::<ROQueryFetch<Q>, _>(
self.world,
batch_size,
f,
self.last_change_tick,
self.change_tick,
);
self.state.as_readonly().par_for_each_unchecked_manual(
self.world,
batch_size,
f,
self.last_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
// borrow checks when they conflict
unsafe {
self.state
.par_for_each_unchecked_manual::<QueryFetch<Q>, FN>(
self.world,
batch_size,
f,
self.last_change_tick,
self.change_tick,
);
self.state.par_for_each_unchecked_manual(
self.world,
batch_size,
f,
self.last_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.
// same-system queries have runtime borrow checks when they conflict
unsafe {
self.state.get_unchecked_manual::<ROQueryFetch<Q>>(
self.state.as_readonly().get_unchecked_manual(
self.world,
entity,
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.
// same-system queries have runtime borrow checks when they conflict
unsafe {
self.state.get_unchecked_manual::<QueryFetch<Q>>(
self.state.get_unchecked_manual(
self.world,
entity,
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> {
// SEMI-SAFETY: system runs without conflicts with other systems.
// same-system queries have runtime borrow checks when they conflict
self.state.get_unchecked_manual::<QueryFetch<Q>>(
self.world,
entity,
self.last_change_tick,
self.change_tick,
)
self.state
.get_unchecked_manual(self.world, entity, self.last_change_tick, self.change_tick)
}
/// 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
// and the query is read only.
unsafe {
self.state.get_single_unchecked_manual::<ROQueryFetch<Q>>(
self.state.as_readonly().get_single_unchecked_manual(
self.world,
self.last_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
// is uniquely borrowed
unsafe {
self.state.get_single_unchecked_manual::<QueryFetch<Q>>(
self.state.get_single_unchecked_manual(
self.world,
self.last_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
unsafe {
self.state
.get_unchecked_manual::<NopFetch<Q::State>>(
self.world,
entity,
self.last_change_tick,
self.change_tick,
)
.as_nop()
.get_unchecked_manual(self.world, entity, self.last_change_tick, self.change_tick)
.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> {
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 {
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 IntoIter = QueryIter<'w, 'w, Q, QueryFetch<'w, Q>, F>;
type IntoIter = QueryIter<'w, 's, Q, F>;
fn into_iter(self) -> Self::IntoIter {
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.
// same-system queries have runtime borrow checks when they conflict
unsafe {
self.state.get_unchecked_manual::<ROQueryFetch<'w, Q>>(
self.state.as_readonly().get_unchecked_manual(
self.world,
entity,
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);
/// ```
#[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.
// same-system queries have runtime borrow checks when they conflict
unsafe {
self.state
.iter_unchecked_manual(self.world, self.last_change_tick, self.change_tick)
self.state.as_readonly().iter_unchecked_manual(
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, F7)
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`
--> 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, F7)
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`
--> 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, F5)
(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: required because of the requirements on the impl of `ReadOnlySystemParamFetch` for `QueryState<&'static mut Foo>`
= 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, F5)
(F0, F1, F2, F3, F4, F5, F6)
and 51 others
and 52 others
note: required by a bound in `_::assert_readonly`
--> 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, F5)
(F0, F1, F2, F3, F4, F5, F6)
and 51 others
and 52 others
note: required by a bound in `_::assert_readonly`
--> tests/ui/world_query_derive.rs:18:10
|