mirror of
https://github.com/bevyengine/bevy
synced 2025-02-16 22:18:33 +00:00
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:
parent
4affc8cd93
commit
1ac8a476cf
8 changed files with 273 additions and 206 deletions
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
||||
|
|
Loading…
Add table
Reference in a new issue