Migrate the rest of the engine to UnsafeWorldCell (#8833)
# Objective Follow-up to #6404 and #8292. Mutating the world through a shared reference is surprising, and it makes the meaning of `&World` unclear: sometimes it gives read-only access to the entire world, and sometimes it gives interior mutable access to only part of it. This is an up-to-date version of #6972. ## Solution Use `UnsafeWorldCell` for all interior mutability. Now, `&World` *always* gives you read-only access to the entire world. --- ## Changelog TODO - do we still care about changelogs? ## Migration Guide Mutating any world data using `&World` is now considered unsound -- the type `UnsafeWorldCell` must be used to achieve interior mutability. The following methods now accept `UnsafeWorldCell` instead of `&World`: - `QueryState`: `get_unchecked`, `iter_unchecked`, `iter_combinations_unchecked`, `for_each_unchecked`, `get_single_unchecked`, `get_single_unchecked_manual`. - `SystemState`: `get_unchecked_manual` ```rust let mut world = World::new(); let mut query = world.query::<&mut T>(); // Before: let t1 = query.get_unchecked(&world, entity_1); let t2 = query.get_unchecked(&world, entity_2); // After: let world_cell = world.as_unsafe_world_cell(); let t1 = query.get_unchecked(world_cell, entity_1); let t2 = query.get_unchecked(world_cell, entity_2); ``` The methods `QueryState::validate_world` and `SystemState::matches_world` now take a `WorldId` instead of `&World`: ```rust // Before: query_state.validate_world(&world); // After: query_state.validate_world(world.id()); ``` The methods `QueryState::update_archetypes` and `SystemState::update_archetypes` now take `UnsafeWorldCell` instead of `&World`: ```rust // Before: query_state.update_archetypes(&world); // After: query_state.update_archetypes(world.as_unsafe_world_cell_readonly()); ```
This commit is contained in:
parent
f7aa83a247
commit
db8d3651e0
@ -271,9 +271,10 @@ pub fn query_get_component_simple(criterion: &mut Criterion) {
|
|||||||
let entity = world.spawn(A(0.0)).id();
|
let entity = world.spawn(A(0.0)).id();
|
||||||
let mut query = world.query::<&mut A>();
|
let mut query = world.query::<&mut A>();
|
||||||
|
|
||||||
|
let world_cell = world.as_unsafe_world_cell();
|
||||||
bencher.iter(|| {
|
bencher.iter(|| {
|
||||||
for _x in 0..100000 {
|
for _x in 0..100000 {
|
||||||
let mut a = unsafe { query.get_unchecked(&world, entity).unwrap() };
|
let mut a = unsafe { query.get_unchecked(world_cell, entity).unwrap() };
|
||||||
a.0 += 1.0;
|
a.0 += 1.0;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -257,7 +257,7 @@ pub fn derive_world_query_impl(input: TokenStream) -> TokenStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn init_fetch<'__w>(
|
unsafe fn init_fetch<'__w>(
|
||||||
_world: &'__w #path::world::World,
|
_world: #path::world::unsafe_world_cell::UnsafeWorldCell<'__w>,
|
||||||
state: &Self::State,
|
state: &Self::State,
|
||||||
_last_run: #path::component::Tick,
|
_last_run: #path::component::Tick,
|
||||||
_this_run: #path::component::Tick,
|
_this_run: #path::component::Tick,
|
||||||
|
|||||||
@ -5,7 +5,7 @@ use crate::{
|
|||||||
entity::Entity,
|
entity::Entity,
|
||||||
query::{Access, DebugCheckedUnwrap, FilteredAccess},
|
query::{Access, DebugCheckedUnwrap, FilteredAccess},
|
||||||
storage::{ComponentSparseSet, Table, TableRow},
|
storage::{ComponentSparseSet, Table, TableRow},
|
||||||
world::{Mut, Ref, World},
|
world::{unsafe_world_cell::UnsafeWorldCell, Mut, Ref, World},
|
||||||
};
|
};
|
||||||
pub use bevy_ecs_macros::WorldQuery;
|
pub use bevy_ecs_macros::WorldQuery;
|
||||||
use bevy_ptr::{ThinSlicePtr, UnsafeCellDeref};
|
use bevy_ptr::{ThinSlicePtr, UnsafeCellDeref};
|
||||||
@ -335,10 +335,11 @@ pub unsafe trait WorldQuery {
|
|||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// `state` must have been initialized (via [`WorldQuery::init_state`]) using the same `world` passed
|
/// - `world` must have permission to access any of the components specified in `Self::update_archetype_component_access`.
|
||||||
|
/// - `state` must have been initialized (via [`WorldQuery::init_state`]) using the same `world` passed
|
||||||
/// in to this function.
|
/// in to this function.
|
||||||
unsafe fn init_fetch<'w>(
|
unsafe fn init_fetch<'w>(
|
||||||
world: &'w World,
|
world: UnsafeWorldCell<'w>,
|
||||||
state: &Self::State,
|
state: &Self::State,
|
||||||
last_run: Tick,
|
last_run: Tick,
|
||||||
this_run: Tick,
|
this_run: Tick,
|
||||||
@ -372,8 +373,10 @@ pub unsafe trait WorldQuery {
|
|||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// `archetype` and `tables` must be from the [`World`] [`WorldQuery::init_state`] was called on. `state` must
|
/// - `archetype` and `tables` must be from the same [`World`] that [`WorldQuery::init_state`] was called on.
|
||||||
/// be the [`Self::State`] this was initialized with.
|
/// - [`Self::update_archetype_component_access`] must have been previously called with `archetype`.
|
||||||
|
/// - `table` must correspond to `archetype`.
|
||||||
|
/// - `state` must be the [`State`](Self::State) that `fetch` was initialized with.
|
||||||
unsafe fn set_archetype<'w>(
|
unsafe fn set_archetype<'w>(
|
||||||
fetch: &mut Self::Fetch<'w>,
|
fetch: &mut Self::Fetch<'w>,
|
||||||
state: &Self::State,
|
state: &Self::State,
|
||||||
@ -386,8 +389,10 @@ pub unsafe trait WorldQuery {
|
|||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// `table` must be from the [`World`] [`WorldQuery::init_state`] was called on. `state` must be the
|
/// - `table` must be from the same [`World`] that [`WorldQuery::init_state`] was called on.
|
||||||
/// [`Self::State`] this was initialized with.
|
/// - `table` must belong to an archetype that was previously registered with
|
||||||
|
/// [`Self::update_archetype_component_access`].
|
||||||
|
/// - `state` must be the [`State`](Self::State) that `fetch` was initialized with.
|
||||||
unsafe fn set_table<'w>(fetch: &mut Self::Fetch<'w>, state: &Self::State, table: &'w Table);
|
unsafe fn set_table<'w>(fetch: &mut Self::Fetch<'w>, state: &Self::State, table: &'w Table);
|
||||||
|
|
||||||
/// Fetch [`Self::Item`](`WorldQuery::Item`) for either the given `entity` in the current [`Table`],
|
/// Fetch [`Self::Item`](`WorldQuery::Item`) for either the given `entity` in the current [`Table`],
|
||||||
@ -475,7 +480,7 @@ unsafe impl WorldQuery for Entity {
|
|||||||
const IS_ARCHETYPAL: bool = true;
|
const IS_ARCHETYPAL: bool = true;
|
||||||
|
|
||||||
unsafe fn init_fetch<'w>(
|
unsafe fn init_fetch<'w>(
|
||||||
_world: &'w World,
|
_world: UnsafeWorldCell<'w>,
|
||||||
_state: &Self::State,
|
_state: &Self::State,
|
||||||
_last_run: Tick,
|
_last_run: Tick,
|
||||||
_this_run: Tick,
|
_this_run: Tick,
|
||||||
@ -558,7 +563,7 @@ unsafe impl<T: Component> WorldQuery for &T {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn init_fetch<'w>(
|
unsafe fn init_fetch<'w>(
|
||||||
world: &'w World,
|
world: UnsafeWorldCell<'w>,
|
||||||
&component_id: &ComponentId,
|
&component_id: &ComponentId,
|
||||||
_last_run: Tick,
|
_last_run: Tick,
|
||||||
_this_run: Tick,
|
_this_run: Tick,
|
||||||
@ -567,6 +572,11 @@ unsafe impl<T: Component> WorldQuery for &T {
|
|||||||
table_components: None,
|
table_components: None,
|
||||||
sparse_set: (T::Storage::STORAGE_TYPE == StorageType::SparseSet).then(|| {
|
sparse_set: (T::Storage::STORAGE_TYPE == StorageType::SparseSet).then(|| {
|
||||||
world
|
world
|
||||||
|
// SAFETY: The underlying type associated with `component_id` is `T`,
|
||||||
|
// which we are allowed to access since we registered it in `update_archetype_component_access`.
|
||||||
|
// Note that we do not actually access any components in this function, we just get a shared
|
||||||
|
// reference to the sparse set, which is used to access the components in `Self::fetch`.
|
||||||
|
.unsafe_world()
|
||||||
.storages()
|
.storages()
|
||||||
.sparse_sets
|
.sparse_sets
|
||||||
.get(component_id)
|
.get(component_id)
|
||||||
@ -704,7 +714,7 @@ unsafe impl<'__w, T: Component> WorldQuery for Ref<'__w, T> {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn init_fetch<'w>(
|
unsafe fn init_fetch<'w>(
|
||||||
world: &'w World,
|
world: UnsafeWorldCell<'w>,
|
||||||
&component_id: &ComponentId,
|
&component_id: &ComponentId,
|
||||||
last_run: Tick,
|
last_run: Tick,
|
||||||
this_run: Tick,
|
this_run: Tick,
|
||||||
@ -713,6 +723,8 @@ unsafe impl<'__w, T: Component> WorldQuery for Ref<'__w, T> {
|
|||||||
table_data: None,
|
table_data: None,
|
||||||
sparse_set: (T::Storage::STORAGE_TYPE == StorageType::SparseSet).then(|| {
|
sparse_set: (T::Storage::STORAGE_TYPE == StorageType::SparseSet).then(|| {
|
||||||
world
|
world
|
||||||
|
// SAFETY: See &T::init_fetch.
|
||||||
|
.unsafe_world()
|
||||||
.storages()
|
.storages()
|
||||||
.sparse_sets
|
.sparse_sets
|
||||||
.get(component_id)
|
.get(component_id)
|
||||||
@ -866,7 +878,7 @@ unsafe impl<'__w, T: Component> WorldQuery for &'__w mut T {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn init_fetch<'w>(
|
unsafe fn init_fetch<'w>(
|
||||||
world: &'w World,
|
world: UnsafeWorldCell<'w>,
|
||||||
&component_id: &ComponentId,
|
&component_id: &ComponentId,
|
||||||
last_run: Tick,
|
last_run: Tick,
|
||||||
this_run: Tick,
|
this_run: Tick,
|
||||||
@ -875,6 +887,8 @@ unsafe impl<'__w, T: Component> WorldQuery for &'__w mut T {
|
|||||||
table_data: None,
|
table_data: None,
|
||||||
sparse_set: (T::Storage::STORAGE_TYPE == StorageType::SparseSet).then(|| {
|
sparse_set: (T::Storage::STORAGE_TYPE == StorageType::SparseSet).then(|| {
|
||||||
world
|
world
|
||||||
|
// SAFETY: See &T::init_fetch.
|
||||||
|
.unsafe_world()
|
||||||
.storages()
|
.storages()
|
||||||
.sparse_sets
|
.sparse_sets
|
||||||
.get(component_id)
|
.get(component_id)
|
||||||
@ -1011,7 +1025,7 @@ unsafe impl<T: WorldQuery> WorldQuery for Option<T> {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn init_fetch<'w>(
|
unsafe fn init_fetch<'w>(
|
||||||
world: &'w World,
|
world: UnsafeWorldCell<'w>,
|
||||||
state: &T::State,
|
state: &T::State,
|
||||||
last_run: Tick,
|
last_run: Tick,
|
||||||
this_run: Tick,
|
this_run: Tick,
|
||||||
@ -1116,7 +1130,7 @@ macro_rules! impl_tuple_fetch {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
#[allow(clippy::unused_unit)]
|
#[allow(clippy::unused_unit)]
|
||||||
unsafe fn init_fetch<'w>(_world: &'w World, state: &Self::State, _last_run: Tick, _this_run: Tick) -> Self::Fetch<'w> {
|
unsafe fn init_fetch<'w>(_world: UnsafeWorldCell<'w>, state: &Self::State, _last_run: Tick, _this_run: Tick) -> Self::Fetch<'w> {
|
||||||
let ($($name,)*) = state;
|
let ($($name,)*) = state;
|
||||||
($($name::init_fetch(_world, $name, _last_run, _this_run),)*)
|
($($name::init_fetch(_world, $name, _last_run, _this_run),)*)
|
||||||
}
|
}
|
||||||
@ -1226,7 +1240,7 @@ macro_rules! impl_anytuple_fetch {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
#[allow(clippy::unused_unit)]
|
#[allow(clippy::unused_unit)]
|
||||||
unsafe fn init_fetch<'w>(_world: &'w World, state: &Self::State, _last_run: Tick, _this_run: Tick) -> Self::Fetch<'w> {
|
unsafe fn init_fetch<'w>(_world: UnsafeWorldCell<'w>, state: &Self::State, _last_run: Tick, _this_run: Tick) -> Self::Fetch<'w> {
|
||||||
let ($($name,)*) = state;
|
let ($($name,)*) = state;
|
||||||
($(($name::init_fetch(_world, $name, _last_run, _this_run), false),)*)
|
($(($name::init_fetch(_world, $name, _last_run, _this_run), false),)*)
|
||||||
}
|
}
|
||||||
@ -1350,7 +1364,13 @@ unsafe impl<Q: WorldQuery> WorldQuery for NopWorldQuery<Q> {
|
|||||||
const IS_ARCHETYPAL: bool = true;
|
const IS_ARCHETYPAL: bool = true;
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
unsafe fn init_fetch(_world: &World, _state: &Q::State, _last_run: Tick, _this_run: Tick) {}
|
unsafe fn init_fetch(
|
||||||
|
_world: UnsafeWorldCell,
|
||||||
|
_state: &Q::State,
|
||||||
|
_last_run: Tick,
|
||||||
|
_this_run: Tick,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
unsafe fn clone_fetch<'w>(_fetch: &Self::Fetch<'w>) -> Self::Fetch<'w> {}
|
unsafe fn clone_fetch<'w>(_fetch: &Self::Fetch<'w>) -> Self::Fetch<'w> {}
|
||||||
|
|
||||||
@ -1408,7 +1428,7 @@ unsafe impl<T: ?Sized> WorldQuery for PhantomData<T> {
|
|||||||
fn shrink<'wlong: 'wshort, 'wshort>(_item: Self::Item<'wlong>) -> Self::Item<'wshort> {}
|
fn shrink<'wlong: 'wshort, 'wshort>(_item: Self::Item<'wlong>) -> Self::Item<'wshort> {}
|
||||||
|
|
||||||
unsafe fn init_fetch<'w>(
|
unsafe fn init_fetch<'w>(
|
||||||
_world: &'w World,
|
_world: UnsafeWorldCell<'w>,
|
||||||
_state: &Self::State,
|
_state: &Self::State,
|
||||||
_last_run: Tick,
|
_last_run: Tick,
|
||||||
_this_run: Tick,
|
_this_run: Tick,
|
||||||
|
|||||||
@ -4,7 +4,7 @@ use crate::{
|
|||||||
entity::Entity,
|
entity::Entity,
|
||||||
query::{Access, DebugCheckedUnwrap, FilteredAccess, WorldQuery},
|
query::{Access, DebugCheckedUnwrap, FilteredAccess, WorldQuery},
|
||||||
storage::{Column, ComponentSparseSet, Table, TableRow},
|
storage::{Column, ComponentSparseSet, Table, TableRow},
|
||||||
world::World,
|
world::{unsafe_world_cell::UnsafeWorldCell, World},
|
||||||
};
|
};
|
||||||
use bevy_ptr::{ThinSlicePtr, UnsafeCellDeref};
|
use bevy_ptr::{ThinSlicePtr, UnsafeCellDeref};
|
||||||
use bevy_utils::all_tuples;
|
use bevy_utils::all_tuples;
|
||||||
@ -51,7 +51,13 @@ unsafe impl<T: Component> WorldQuery for With<T> {
|
|||||||
fn shrink<'wlong: 'wshort, 'wshort>(_: Self::Item<'wlong>) -> Self::Item<'wshort> {}
|
fn shrink<'wlong: 'wshort, 'wshort>(_: Self::Item<'wlong>) -> Self::Item<'wshort> {}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn init_fetch(_world: &World, _state: &ComponentId, _last_run: Tick, _this_run: Tick) {}
|
unsafe fn init_fetch(
|
||||||
|
_world: UnsafeWorldCell,
|
||||||
|
_state: &ComponentId,
|
||||||
|
_last_run: Tick,
|
||||||
|
_this_run: Tick,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
unsafe fn clone_fetch<'w>(_fetch: &Self::Fetch<'w>) -> Self::Fetch<'w> {}
|
unsafe fn clone_fetch<'w>(_fetch: &Self::Fetch<'w>) -> Self::Fetch<'w> {}
|
||||||
|
|
||||||
@ -148,7 +154,13 @@ unsafe impl<T: Component> WorldQuery for Without<T> {
|
|||||||
fn shrink<'wlong: 'wshort, 'wshort>(_: Self::Item<'wlong>) -> Self::Item<'wshort> {}
|
fn shrink<'wlong: 'wshort, 'wshort>(_: Self::Item<'wlong>) -> Self::Item<'wshort> {}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn init_fetch(_world: &World, _state: &ComponentId, _last_run: Tick, _this_run: Tick) {}
|
unsafe fn init_fetch(
|
||||||
|
_world: UnsafeWorldCell,
|
||||||
|
_state: &ComponentId,
|
||||||
|
_last_run: Tick,
|
||||||
|
_this_run: Tick,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
unsafe fn clone_fetch<'w>(_fetch: &Self::Fetch<'w>) -> Self::Fetch<'w> {}
|
unsafe fn clone_fetch<'w>(_fetch: &Self::Fetch<'w>) -> Self::Fetch<'w> {}
|
||||||
|
|
||||||
@ -268,7 +280,7 @@ macro_rules! impl_query_filter_tuple {
|
|||||||
const IS_ARCHETYPAL: bool = true $(&& $filter::IS_ARCHETYPAL)*;
|
const IS_ARCHETYPAL: bool = true $(&& $filter::IS_ARCHETYPAL)*;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn init_fetch<'w>(world: &'w World, state: &Self::State, last_run: Tick, this_run: Tick) -> Self::Fetch<'w> {
|
unsafe fn init_fetch<'w>(world: UnsafeWorldCell<'w>, state: &Self::State, last_run: Tick, this_run: Tick) -> Self::Fetch<'w> {
|
||||||
let ($($filter,)*) = state;
|
let ($($filter,)*) = state;
|
||||||
($(OrFetch {
|
($(OrFetch {
|
||||||
fetch: $filter::init_fetch(world, $filter, last_run, this_run),
|
fetch: $filter::init_fetch(world, $filter, last_run, this_run),
|
||||||
@ -412,12 +424,18 @@ macro_rules! impl_tick_filter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn init_fetch<'w>(world: &'w World, &id: &ComponentId, last_run: Tick, this_run: Tick) -> Self::Fetch<'w> {
|
unsafe fn init_fetch<'w>(
|
||||||
|
world: UnsafeWorldCell<'w>,
|
||||||
|
&id: &ComponentId,
|
||||||
|
last_run: Tick,
|
||||||
|
this_run: Tick
|
||||||
|
) -> Self::Fetch<'w> {
|
||||||
Self::Fetch::<'w> {
|
Self::Fetch::<'w> {
|
||||||
table_ticks: None,
|
table_ticks: None,
|
||||||
sparse_set: (T::Storage::STORAGE_TYPE == StorageType::SparseSet)
|
sparse_set: (T::Storage::STORAGE_TYPE == StorageType::SparseSet)
|
||||||
.then(|| {
|
.then(|| {
|
||||||
world.storages()
|
world.unsafe_world()
|
||||||
|
.storages()
|
||||||
.sparse_sets
|
.sparse_sets
|
||||||
.get(id)
|
.get(id)
|
||||||
.debug_checked_unwrap()
|
.debug_checked_unwrap()
|
||||||
|
|||||||
@ -2,9 +2,9 @@ use crate::{
|
|||||||
archetype::{ArchetypeEntity, ArchetypeId, Archetypes},
|
archetype::{ArchetypeEntity, ArchetypeId, Archetypes},
|
||||||
component::Tick,
|
component::Tick,
|
||||||
entity::{Entities, Entity},
|
entity::{Entities, Entity},
|
||||||
prelude::World,
|
|
||||||
query::{ArchetypeFilter, DebugCheckedUnwrap, QueryState, WorldQuery},
|
query::{ArchetypeFilter, DebugCheckedUnwrap, QueryState, WorldQuery},
|
||||||
storage::{TableId, TableRow, Tables},
|
storage::{TableId, TableRow, Tables},
|
||||||
|
world::unsafe_world_cell::UnsafeWorldCell,
|
||||||
};
|
};
|
||||||
use std::{borrow::Borrow, iter::FusedIterator, marker::PhantomData, mem::MaybeUninit};
|
use std::{borrow::Borrow, iter::FusedIterator, marker::PhantomData, mem::MaybeUninit};
|
||||||
|
|
||||||
@ -23,20 +23,19 @@ pub struct QueryIter<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> {
|
|||||||
|
|
||||||
impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> QueryIter<'w, 's, Q, F> {
|
impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> QueryIter<'w, 's, Q, F> {
|
||||||
/// # Safety
|
/// # Safety
|
||||||
/// This does not check for mutable query correctness. To be safe, make sure mutable queries
|
/// - `world` must have permission to access any of the components registered in `query_state`.
|
||||||
/// have unique access to the components they query.
|
/// - `world` must be the same one used to initialize `query_state`.
|
||||||
/// This does not validate that `world.id()` matches `query_state.world_id`. Calling this on a `world`
|
|
||||||
/// with a mismatched [`WorldId`](crate::world::WorldId) is unsound.
|
|
||||||
pub(crate) unsafe fn new(
|
pub(crate) unsafe fn new(
|
||||||
world: &'w World,
|
world: UnsafeWorldCell<'w>,
|
||||||
query_state: &'s QueryState<Q, F>,
|
query_state: &'s QueryState<Q, F>,
|
||||||
last_run: Tick,
|
last_run: Tick,
|
||||||
this_run: Tick,
|
this_run: Tick,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
QueryIter {
|
QueryIter {
|
||||||
query_state,
|
query_state,
|
||||||
tables: &world.storages().tables,
|
// SAFETY: We only access table data that has been registered in `query_state`.
|
||||||
archetypes: &world.archetypes,
|
tables: &world.unsafe_world().storages().tables,
|
||||||
|
archetypes: world.archetypes(),
|
||||||
cursor: QueryIterationCursor::init(world, query_state, last_run, this_run),
|
cursor: QueryIterationCursor::init(world, query_state, last_run, this_run),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -91,12 +90,10 @@ where
|
|||||||
I::Item: Borrow<Entity>,
|
I::Item: Borrow<Entity>,
|
||||||
{
|
{
|
||||||
/// # Safety
|
/// # Safety
|
||||||
/// This does not check for mutable query correctness. To be safe, make sure mutable queries
|
/// - `world` must have permission to access any of the components registered in `query_state`.
|
||||||
/// have unique access to the components they query.
|
/// - `world` must be the same one used to initialize `query_state`.
|
||||||
/// This does not validate that `world.id()` matches `query_state.world_id`. Calling this on a `world`
|
|
||||||
/// with a mismatched [`WorldId`](crate::world::WorldId) is unsound.
|
|
||||||
pub(crate) unsafe fn new<EntityList: IntoIterator<IntoIter = I>>(
|
pub(crate) unsafe fn new<EntityList: IntoIterator<IntoIter = I>>(
|
||||||
world: &'w World,
|
world: UnsafeWorldCell<'w>,
|
||||||
query_state: &'s QueryState<Q, F>,
|
query_state: &'s QueryState<Q, F>,
|
||||||
entity_list: EntityList,
|
entity_list: EntityList,
|
||||||
last_run: Tick,
|
last_run: Tick,
|
||||||
@ -106,9 +103,11 @@ where
|
|||||||
let filter = F::init_fetch(world, &query_state.filter_state, last_run, this_run);
|
let filter = F::init_fetch(world, &query_state.filter_state, last_run, this_run);
|
||||||
QueryManyIter {
|
QueryManyIter {
|
||||||
query_state,
|
query_state,
|
||||||
entities: &world.entities,
|
entities: world.entities(),
|
||||||
archetypes: &world.archetypes,
|
archetypes: world.archetypes(),
|
||||||
tables: &world.storages.tables,
|
// SAFETY: We only access table data that has been registered in `query_state`.
|
||||||
|
// This means `world` has permission to access the data we use.
|
||||||
|
tables: &world.unsafe_world().storages.tables,
|
||||||
fetch,
|
fetch,
|
||||||
filter,
|
filter,
|
||||||
entity_iter: entity_list.into_iter(),
|
entity_iter: entity_list.into_iter(),
|
||||||
@ -282,12 +281,10 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery, const K: usize>
|
|||||||
QueryCombinationIter<'w, 's, Q, F, K>
|
QueryCombinationIter<'w, 's, Q, F, K>
|
||||||
{
|
{
|
||||||
/// # Safety
|
/// # Safety
|
||||||
/// This does not check for mutable query correctness. To be safe, make sure mutable queries
|
/// - `world` must have permission to access any of the components registered in `query_state`.
|
||||||
/// have unique access to the components they query.
|
/// - `world` must be the same one used to initialize `query_state`.
|
||||||
/// This does not validate that `world.id()` matches `query_state.world_id`. Calling this on a
|
|
||||||
/// `world` with a mismatched [`WorldId`](crate::world::WorldId) is unsound.
|
|
||||||
pub(crate) unsafe fn new(
|
pub(crate) unsafe fn new(
|
||||||
world: &'w World,
|
world: UnsafeWorldCell<'w>,
|
||||||
query_state: &'s QueryState<Q, F>,
|
query_state: &'s QueryState<Q, F>,
|
||||||
last_run: Tick,
|
last_run: Tick,
|
||||||
this_run: Tick,
|
this_run: Tick,
|
||||||
@ -318,8 +315,9 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery, const K: usize>
|
|||||||
|
|
||||||
QueryCombinationIter {
|
QueryCombinationIter {
|
||||||
query_state,
|
query_state,
|
||||||
tables: &world.storages().tables,
|
// SAFETY: We only access table data that has been registered in `query_state`.
|
||||||
archetypes: &world.archetypes,
|
tables: &world.unsafe_world().storages().tables,
|
||||||
|
archetypes: world.archetypes(),
|
||||||
cursors: array.assume_init(),
|
cursors: array.assume_init(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -485,7 +483,7 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> QueryIterationCursor<'w, 's,
|
|||||||
const IS_DENSE: bool = Q::IS_DENSE && F::IS_DENSE;
|
const IS_DENSE: bool = Q::IS_DENSE && F::IS_DENSE;
|
||||||
|
|
||||||
unsafe fn init_empty(
|
unsafe fn init_empty(
|
||||||
world: &'w World,
|
world: UnsafeWorldCell<'w>,
|
||||||
query_state: &'s QueryState<Q, F>,
|
query_state: &'s QueryState<Q, F>,
|
||||||
last_run: Tick,
|
last_run: Tick,
|
||||||
this_run: Tick,
|
this_run: Tick,
|
||||||
@ -497,8 +495,11 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> QueryIterationCursor<'w, 's,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// # Safety
|
||||||
|
/// - `world` must have permission to access any of the components registered in `query_state`.
|
||||||
|
/// - `world` must be the same one used to initialize `query_state`.
|
||||||
unsafe fn init(
|
unsafe fn init(
|
||||||
world: &'w World,
|
world: UnsafeWorldCell<'w>,
|
||||||
query_state: &'s QueryState<Q, F>,
|
query_state: &'s QueryState<Q, F>,
|
||||||
last_run: Tick,
|
last_run: Tick,
|
||||||
this_run: Tick,
|
this_run: Tick,
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
use crate::{component::Tick, world::World};
|
use crate::{component::Tick, world::unsafe_world_cell::UnsafeWorldCell};
|
||||||
use bevy_tasks::ComputeTaskPool;
|
use bevy_tasks::ComputeTaskPool;
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
||||||
@ -82,7 +82,7 @@ impl BatchingStrategy {
|
|||||||
/// This struct is created by the [`Query::par_iter`](crate::system::Query::par_iter) and
|
/// This struct is created by the [`Query::par_iter`](crate::system::Query::par_iter) and
|
||||||
/// [`Query::par_iter_mut`](crate::system::Query::par_iter_mut) methods.
|
/// [`Query::par_iter_mut`](crate::system::Query::par_iter_mut) methods.
|
||||||
pub struct QueryParIter<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> {
|
pub struct QueryParIter<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> {
|
||||||
pub(crate) world: &'w World,
|
pub(crate) world: UnsafeWorldCell<'w>,
|
||||||
pub(crate) state: &'s QueryState<Q, F>,
|
pub(crate) state: &'s QueryState<Q, F>,
|
||||||
pub(crate) last_run: Tick,
|
pub(crate) last_run: Tick,
|
||||||
pub(crate) this_run: Tick,
|
pub(crate) this_run: Tick,
|
||||||
@ -178,7 +178,8 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> QueryParIter<'w, 's, Q, F> {
|
|||||||
"Attempted to run parallel iteration over a query with an empty TaskPool"
|
"Attempted to run parallel iteration over a query with an empty TaskPool"
|
||||||
);
|
);
|
||||||
let max_size = if Q::IS_DENSE && F::IS_DENSE {
|
let max_size = if Q::IS_DENSE && F::IS_DENSE {
|
||||||
let tables = &self.world.storages().tables;
|
// SAFETY: We only access table metadata.
|
||||||
|
let tables = unsafe { &self.world.world_metadata().storages().tables };
|
||||||
self.state
|
self.state
|
||||||
.matched_table_ids
|
.matched_table_ids
|
||||||
.iter()
|
.iter()
|
||||||
|
|||||||
@ -8,7 +8,7 @@ use crate::{
|
|||||||
QueryIter, QueryParIter, WorldQuery,
|
QueryIter, QueryParIter, WorldQuery,
|
||||||
},
|
},
|
||||||
storage::{TableId, TableRow},
|
storage::{TableId, TableRow},
|
||||||
world::{World, WorldId},
|
world::{unsafe_world_cell::UnsafeWorldCell, World, WorldId},
|
||||||
};
|
};
|
||||||
use bevy_tasks::ComputeTaskPool;
|
use bevy_tasks::ComputeTaskPool;
|
||||||
#[cfg(feature = "trace")]
|
#[cfg(feature = "trace")]
|
||||||
@ -134,20 +134,45 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
|||||||
// SAFETY: NopFetch does not access any members while &self ensures no one has exclusive access
|
// SAFETY: NopFetch does not access any members while &self ensures no one has exclusive access
|
||||||
unsafe {
|
unsafe {
|
||||||
self.as_nop()
|
self.as_nop()
|
||||||
.iter_unchecked_manual(world, last_run, this_run)
|
.iter_unchecked_manual(world.as_unsafe_world_cell_readonly(), last_run, this_run)
|
||||||
.next()
|
.next()
|
||||||
.is_none()
|
.is_none()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Takes a query for the given [`World`], checks if the given world is the same as the query, and
|
/// Updates the state's internal view of the [`World`]'s archetypes. If this is not called before querying data,
|
||||||
/// updates the [`QueryState`]'s view of the [`World`] with any newly-added archetypes.
|
/// the results may not accurately reflect what is in the `world`.
|
||||||
|
///
|
||||||
|
/// This is only required if a `manual` method (such as [`Self::get_manual`]) is being called, and it only needs to
|
||||||
|
/// be called if the `world` has been structurally mutated (i.e. added/removed a component or resource). Users using
|
||||||
|
/// non-`manual` methods such as [`QueryState::get`] do not need to call this as it will be automatically called for them.
|
||||||
|
///
|
||||||
|
/// If you have an [`UnsafeWorldCell`] instead of `&World`, consider using [`QueryState::update_archetypes_unsafe_world_cell`].
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// If `world` does not match the one used to call `QueryState::new` for this instance.
|
/// If `world` does not match the one used to call `QueryState::new` for this instance.
|
||||||
|
#[inline]
|
||||||
pub fn update_archetypes(&mut self, world: &World) {
|
pub fn update_archetypes(&mut self, world: &World) {
|
||||||
self.validate_world(world);
|
self.update_archetypes_unsafe_world_cell(world.as_unsafe_world_cell_readonly());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Updates the state's internal view of the `world`'s archetypes. If this is not called before querying data,
|
||||||
|
/// the results may not accurately reflect what is in the `world`.
|
||||||
|
///
|
||||||
|
/// This is only required if a `manual` method (such as [`Self::get_manual`]) is being called, and it only needs to
|
||||||
|
/// be called if the `world` has been structurally mutated (i.e. added/removed a component or resource). Users using
|
||||||
|
/// non-`manual` methods such as [`QueryState::get`] do not need to call this as it will be automatically called for them.
|
||||||
|
///
|
||||||
|
/// # Note
|
||||||
|
///
|
||||||
|
/// This method only accesses world metadata.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// If `world` does not match the one used to call `QueryState::new` for this instance.
|
||||||
|
pub fn update_archetypes_unsafe_world_cell(&mut self, world: UnsafeWorldCell) {
|
||||||
|
self.validate_world(world.id());
|
||||||
let archetypes = world.archetypes();
|
let archetypes = world.archetypes();
|
||||||
let new_generation = archetypes.generation();
|
let new_generation = archetypes.generation();
|
||||||
let old_generation = std::mem::replace(&mut self.archetype_generation, new_generation);
|
let old_generation = std::mem::replace(&mut self.archetype_generation, new_generation);
|
||||||
@ -160,14 +185,14 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
|||||||
|
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// If `world` does not match the one used to call `QueryState::new` for this instance.
|
/// If `world_id` does not match the [`World`] used to call `QueryState::new` for this instance.
|
||||||
///
|
///
|
||||||
/// Many unsafe query methods require the world to match for soundness. This function is the easiest
|
/// Many unsafe query methods require the world to match for soundness. This function is the easiest
|
||||||
/// way of ensuring that it matches.
|
/// way of ensuring that it matches.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn validate_world(&self, world: &World) {
|
pub fn validate_world(&self, world_id: WorldId) {
|
||||||
assert!(
|
assert!(
|
||||||
world.id() == self.world_id,
|
world_id == self.world_id,
|
||||||
"Attempted to use {} with a mismatched World. QueryStates can only be used with the World they were created from.",
|
"Attempted to use {} with a mismatched World. QueryStates can only be used with the World they were created from.",
|
||||||
std::any::type_name::<Self>(),
|
std::any::type_name::<Self>(),
|
||||||
);
|
);
|
||||||
@ -217,7 +242,7 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
|||||||
// SAFETY: query is read only
|
// SAFETY: query is read only
|
||||||
unsafe {
|
unsafe {
|
||||||
self.as_readonly().get_unchecked_manual(
|
self.as_readonly().get_unchecked_manual(
|
||||||
world,
|
world.as_unsafe_world_cell_readonly(),
|
||||||
entity,
|
entity,
|
||||||
world.last_change_tick(),
|
world.last_change_tick(),
|
||||||
world.read_change_tick(),
|
world.read_change_tick(),
|
||||||
@ -285,8 +310,16 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
|||||||
) -> Result<Q::Item<'w>, QueryEntityError> {
|
) -> Result<Q::Item<'w>, QueryEntityError> {
|
||||||
self.update_archetypes(world);
|
self.update_archetypes(world);
|
||||||
let change_tick = world.change_tick();
|
let change_tick = world.change_tick();
|
||||||
|
let last_change_tick = world.last_change_tick();
|
||||||
// SAFETY: query has unique world access
|
// SAFETY: query has unique world access
|
||||||
unsafe { self.get_unchecked_manual(world, entity, world.last_change_tick(), change_tick) }
|
unsafe {
|
||||||
|
self.get_unchecked_manual(
|
||||||
|
world.as_unsafe_world_cell(),
|
||||||
|
entity,
|
||||||
|
last_change_tick,
|
||||||
|
change_tick,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the query results for the given array of [`Entity`].
|
/// Returns the query results for the given array of [`Entity`].
|
||||||
@ -336,10 +369,16 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
|||||||
self.update_archetypes(world);
|
self.update_archetypes(world);
|
||||||
|
|
||||||
let change_tick = world.change_tick();
|
let change_tick = world.change_tick();
|
||||||
|
let last_change_tick = world.last_change_tick();
|
||||||
// SAFETY: method requires exclusive world access
|
// SAFETY: method requires exclusive world access
|
||||||
// and world has been validated via update_archetypes
|
// and world has been validated via update_archetypes
|
||||||
unsafe {
|
unsafe {
|
||||||
self.get_many_unchecked_manual(world, entities, world.last_change_tick(), change_tick)
|
self.get_many_unchecked_manual(
|
||||||
|
world.as_unsafe_world_cell(),
|
||||||
|
entities,
|
||||||
|
last_change_tick,
|
||||||
|
change_tick,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -360,11 +399,11 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
|||||||
world: &'w World,
|
world: &'w World,
|
||||||
entity: Entity,
|
entity: Entity,
|
||||||
) -> Result<ROQueryItem<'w, Q>, QueryEntityError> {
|
) -> Result<ROQueryItem<'w, Q>, QueryEntityError> {
|
||||||
self.validate_world(world);
|
self.validate_world(world.id());
|
||||||
// SAFETY: query is read only and world is validated
|
// SAFETY: query is read only and world is validated
|
||||||
unsafe {
|
unsafe {
|
||||||
self.as_readonly().get_unchecked_manual(
|
self.as_readonly().get_unchecked_manual(
|
||||||
world,
|
world.as_unsafe_world_cell_readonly(),
|
||||||
entity,
|
entity,
|
||||||
world.last_change_tick(),
|
world.last_change_tick(),
|
||||||
world.read_change_tick(),
|
world.read_change_tick(),
|
||||||
@ -381,16 +420,11 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn get_unchecked<'w>(
|
pub unsafe fn get_unchecked<'w>(
|
||||||
&mut self,
|
&mut self,
|
||||||
world: &'w World,
|
world: UnsafeWorldCell<'w>,
|
||||||
entity: Entity,
|
entity: Entity,
|
||||||
) -> Result<Q::Item<'w>, QueryEntityError> {
|
) -> Result<Q::Item<'w>, QueryEntityError> {
|
||||||
self.update_archetypes(world);
|
self.update_archetypes_unsafe_world_cell(world);
|
||||||
self.get_unchecked_manual(
|
self.get_unchecked_manual(world, entity, world.last_change_tick(), world.change_tick())
|
||||||
world,
|
|
||||||
entity,
|
|
||||||
world.last_change_tick(),
|
|
||||||
world.read_change_tick(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the query result for the given [`World`] and [`Entity`], where the last change and
|
/// Gets the query result for the given [`World`] and [`Entity`], where the last change and
|
||||||
@ -405,13 +439,13 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
|||||||
/// use `QueryState::validate_world` to verify this.
|
/// use `QueryState::validate_world` to verify this.
|
||||||
pub(crate) unsafe fn get_unchecked_manual<'w>(
|
pub(crate) unsafe fn get_unchecked_manual<'w>(
|
||||||
&self,
|
&self,
|
||||||
world: &'w World,
|
world: UnsafeWorldCell<'w>,
|
||||||
entity: Entity,
|
entity: Entity,
|
||||||
last_run: Tick,
|
last_run: Tick,
|
||||||
this_run: Tick,
|
this_run: Tick,
|
||||||
) -> Result<Q::Item<'w>, QueryEntityError> {
|
) -> Result<Q::Item<'w>, QueryEntityError> {
|
||||||
let location = world
|
let location = world
|
||||||
.entities
|
.entities()
|
||||||
.get(entity)
|
.get(entity)
|
||||||
.ok_or(QueryEntityError::NoSuchEntity(entity))?;
|
.ok_or(QueryEntityError::NoSuchEntity(entity))?;
|
||||||
if !self
|
if !self
|
||||||
@ -421,13 +455,14 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
|||||||
return Err(QueryEntityError::QueryDoesNotMatch(entity));
|
return Err(QueryEntityError::QueryDoesNotMatch(entity));
|
||||||
}
|
}
|
||||||
let archetype = world
|
let archetype = world
|
||||||
.archetypes
|
.archetypes()
|
||||||
.get(location.archetype_id)
|
.get(location.archetype_id)
|
||||||
.debug_checked_unwrap();
|
.debug_checked_unwrap();
|
||||||
let mut fetch = Q::init_fetch(world, &self.fetch_state, last_run, this_run);
|
let mut fetch = Q::init_fetch(world, &self.fetch_state, last_run, this_run);
|
||||||
let mut filter = F::init_fetch(world, &self.filter_state, last_run, this_run);
|
let mut filter = F::init_fetch(world, &self.filter_state, last_run, this_run);
|
||||||
|
|
||||||
let table = world
|
let table = world
|
||||||
|
.unsafe_world()
|
||||||
.storages()
|
.storages()
|
||||||
.tables
|
.tables
|
||||||
.get(location.table_id)
|
.get(location.table_id)
|
||||||
@ -461,9 +496,12 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
|||||||
for (value, entity) in std::iter::zip(&mut values, entities) {
|
for (value, entity) in std::iter::zip(&mut values, entities) {
|
||||||
// SAFETY: fetch is read-only
|
// SAFETY: fetch is read-only
|
||||||
// and world must be validated
|
// and world must be validated
|
||||||
let item = self
|
let item = self.as_readonly().get_unchecked_manual(
|
||||||
.as_readonly()
|
world.as_unsafe_world_cell_readonly(),
|
||||||
.get_unchecked_manual(world, entity, last_run, this_run)?;
|
entity,
|
||||||
|
last_run,
|
||||||
|
this_run,
|
||||||
|
)?;
|
||||||
*value = MaybeUninit::new(item);
|
*value = MaybeUninit::new(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -483,7 +521,7 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
|||||||
/// use `QueryState::validate_world` to verify this.
|
/// use `QueryState::validate_world` to verify this.
|
||||||
pub(crate) unsafe fn get_many_unchecked_manual<'w, const N: usize>(
|
pub(crate) unsafe fn get_many_unchecked_manual<'w, const N: usize>(
|
||||||
&self,
|
&self,
|
||||||
world: &'w World,
|
world: UnsafeWorldCell<'w>,
|
||||||
entities: [Entity; N],
|
entities: [Entity; N],
|
||||||
last_run: Tick,
|
last_run: Tick,
|
||||||
this_run: Tick,
|
this_run: Tick,
|
||||||
@ -520,7 +558,7 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
|||||||
// SAFETY: query is read only
|
// SAFETY: query is read only
|
||||||
unsafe {
|
unsafe {
|
||||||
self.as_readonly().iter_unchecked_manual(
|
self.as_readonly().iter_unchecked_manual(
|
||||||
world,
|
world.as_unsafe_world_cell_readonly(),
|
||||||
world.last_change_tick(),
|
world.last_change_tick(),
|
||||||
world.read_change_tick(),
|
world.read_change_tick(),
|
||||||
)
|
)
|
||||||
@ -530,10 +568,13 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
|||||||
/// Returns an [`Iterator`] over the query results for the given [`World`].
|
/// Returns an [`Iterator`] over the query results for the given [`World`].
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn iter_mut<'w, 's>(&'s mut self, world: &'w mut World) -> QueryIter<'w, 's, Q, F> {
|
pub fn iter_mut<'w, 's>(&'s mut self, world: &'w mut World) -> QueryIter<'w, 's, Q, F> {
|
||||||
let change_tick = world.change_tick();
|
|
||||||
self.update_archetypes(world);
|
self.update_archetypes(world);
|
||||||
|
let change_tick = world.change_tick();
|
||||||
|
let last_change_tick = world.last_change_tick();
|
||||||
// SAFETY: query has unique world access
|
// SAFETY: query has unique world access
|
||||||
unsafe { self.iter_unchecked_manual(world, world.last_change_tick(), change_tick) }
|
unsafe {
|
||||||
|
self.iter_unchecked_manual(world.as_unsafe_world_cell(), last_change_tick, change_tick)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an [`Iterator`] over the query results for the given [`World`] without updating the query's archetypes.
|
/// Returns an [`Iterator`] over the query results for the given [`World`] without updating the query's archetypes.
|
||||||
@ -545,11 +586,11 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
|||||||
&'s self,
|
&'s self,
|
||||||
world: &'w World,
|
world: &'w World,
|
||||||
) -> QueryIter<'w, 's, Q::ReadOnly, F::ReadOnly> {
|
) -> QueryIter<'w, 's, Q::ReadOnly, F::ReadOnly> {
|
||||||
self.validate_world(world);
|
self.validate_world(world.id());
|
||||||
// SAFETY: query is read only and world is validated
|
// SAFETY: query is read only and world is validated
|
||||||
unsafe {
|
unsafe {
|
||||||
self.as_readonly().iter_unchecked_manual(
|
self.as_readonly().iter_unchecked_manual(
|
||||||
world,
|
world.as_unsafe_world_cell_readonly(),
|
||||||
world.last_change_tick(),
|
world.last_change_tick(),
|
||||||
world.read_change_tick(),
|
world.read_change_tick(),
|
||||||
)
|
)
|
||||||
@ -586,7 +627,7 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
|||||||
// SAFETY: query is read only
|
// SAFETY: query is read only
|
||||||
unsafe {
|
unsafe {
|
||||||
self.as_readonly().iter_combinations_unchecked_manual(
|
self.as_readonly().iter_combinations_unchecked_manual(
|
||||||
world,
|
world.as_unsafe_world_cell_readonly(),
|
||||||
world.last_change_tick(),
|
world.last_change_tick(),
|
||||||
world.read_change_tick(),
|
world.read_change_tick(),
|
||||||
)
|
)
|
||||||
@ -615,11 +656,16 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
|||||||
&'s mut self,
|
&'s mut self,
|
||||||
world: &'w mut World,
|
world: &'w mut World,
|
||||||
) -> QueryCombinationIter<'w, 's, Q, F, K> {
|
) -> QueryCombinationIter<'w, 's, Q, F, K> {
|
||||||
let change_tick = world.change_tick();
|
|
||||||
self.update_archetypes(world);
|
self.update_archetypes(world);
|
||||||
|
let change_tick = world.change_tick();
|
||||||
|
let last_change_tick = world.last_change_tick();
|
||||||
// SAFETY: query has unique world access
|
// SAFETY: query has unique world access
|
||||||
unsafe {
|
unsafe {
|
||||||
self.iter_combinations_unchecked_manual(world, world.last_change_tick(), change_tick)
|
self.iter_combinations_unchecked_manual(
|
||||||
|
world.as_unsafe_world_cell(),
|
||||||
|
last_change_tick,
|
||||||
|
change_tick,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -645,7 +691,7 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
|||||||
unsafe {
|
unsafe {
|
||||||
self.as_readonly().iter_many_unchecked_manual(
|
self.as_readonly().iter_many_unchecked_manual(
|
||||||
entities,
|
entities,
|
||||||
world,
|
world.as_unsafe_world_cell_readonly(),
|
||||||
world.last_change_tick(),
|
world.last_change_tick(),
|
||||||
world.read_change_tick(),
|
world.read_change_tick(),
|
||||||
)
|
)
|
||||||
@ -675,12 +721,12 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
|||||||
where
|
where
|
||||||
EntityList::Item: Borrow<Entity>,
|
EntityList::Item: Borrow<Entity>,
|
||||||
{
|
{
|
||||||
self.validate_world(world);
|
self.validate_world(world.id());
|
||||||
// SAFETY: query is read only, world id is validated
|
// SAFETY: query is read only, world id is validated
|
||||||
unsafe {
|
unsafe {
|
||||||
self.as_readonly().iter_many_unchecked_manual(
|
self.as_readonly().iter_many_unchecked_manual(
|
||||||
entities,
|
entities,
|
||||||
world,
|
world.as_unsafe_world_cell_readonly(),
|
||||||
world.last_change_tick(),
|
world.last_change_tick(),
|
||||||
world.read_change_tick(),
|
world.read_change_tick(),
|
||||||
)
|
)
|
||||||
@ -702,9 +748,15 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
|||||||
{
|
{
|
||||||
self.update_archetypes(world);
|
self.update_archetypes(world);
|
||||||
let change_tick = world.change_tick();
|
let change_tick = world.change_tick();
|
||||||
|
let last_change_tick = world.last_change_tick();
|
||||||
// SAFETY: Query has unique world access.
|
// SAFETY: Query has unique world access.
|
||||||
unsafe {
|
unsafe {
|
||||||
self.iter_many_unchecked_manual(entities, world, world.last_change_tick(), change_tick)
|
self.iter_many_unchecked_manual(
|
||||||
|
entities,
|
||||||
|
world.as_unsafe_world_cell(),
|
||||||
|
last_change_tick,
|
||||||
|
change_tick,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -717,10 +769,10 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn iter_unchecked<'w, 's>(
|
pub unsafe fn iter_unchecked<'w, 's>(
|
||||||
&'s mut self,
|
&'s mut self,
|
||||||
world: &'w World,
|
world: UnsafeWorldCell<'w>,
|
||||||
) -> QueryIter<'w, 's, Q, F> {
|
) -> QueryIter<'w, 's, Q, F> {
|
||||||
self.update_archetypes(world);
|
self.update_archetypes_unsafe_world_cell(world);
|
||||||
self.iter_unchecked_manual(world, world.last_change_tick(), world.read_change_tick())
|
self.iter_unchecked_manual(world, world.last_change_tick(), world.change_tick())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an [`Iterator`] over all possible combinations of `K` query results for the
|
/// Returns an [`Iterator`] over all possible combinations of `K` query results for the
|
||||||
@ -734,13 +786,13 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn iter_combinations_unchecked<'w, 's, const K: usize>(
|
pub unsafe fn iter_combinations_unchecked<'w, 's, const K: usize>(
|
||||||
&'s mut self,
|
&'s mut self,
|
||||||
world: &'w World,
|
world: UnsafeWorldCell<'w>,
|
||||||
) -> QueryCombinationIter<'w, 's, Q, F, K> {
|
) -> QueryCombinationIter<'w, 's, Q, F, K> {
|
||||||
self.update_archetypes(world);
|
self.update_archetypes_unsafe_world_cell(world);
|
||||||
self.iter_combinations_unchecked_manual(
|
self.iter_combinations_unchecked_manual(
|
||||||
world,
|
world,
|
||||||
world.last_change_tick(),
|
world.last_change_tick(),
|
||||||
world.read_change_tick(),
|
world.change_tick(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -756,7 +808,7 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) unsafe fn iter_unchecked_manual<'w, 's>(
|
pub(crate) unsafe fn iter_unchecked_manual<'w, 's>(
|
||||||
&'s self,
|
&'s self,
|
||||||
world: &'w World,
|
world: UnsafeWorldCell<'w>,
|
||||||
last_run: Tick,
|
last_run: Tick,
|
||||||
this_run: Tick,
|
this_run: Tick,
|
||||||
) -> QueryIter<'w, 's, Q, F> {
|
) -> QueryIter<'w, 's, Q, F> {
|
||||||
@ -777,7 +829,7 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
|||||||
pub(crate) unsafe fn iter_many_unchecked_manual<'w, 's, EntityList: IntoIterator>(
|
pub(crate) unsafe fn iter_many_unchecked_manual<'w, 's, EntityList: IntoIterator>(
|
||||||
&'s self,
|
&'s self,
|
||||||
entities: EntityList,
|
entities: EntityList,
|
||||||
world: &'w World,
|
world: UnsafeWorldCell<'w>,
|
||||||
last_run: Tick,
|
last_run: Tick,
|
||||||
this_run: Tick,
|
this_run: Tick,
|
||||||
) -> QueryManyIter<'w, 's, Q, F, EntityList::IntoIter>
|
) -> QueryManyIter<'w, 's, Q, F, EntityList::IntoIter>
|
||||||
@ -800,7 +852,7 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) unsafe fn iter_combinations_unchecked_manual<'w, 's, const K: usize>(
|
pub(crate) unsafe fn iter_combinations_unchecked_manual<'w, 's, const K: usize>(
|
||||||
&'s self,
|
&'s self,
|
||||||
world: &'w World,
|
world: UnsafeWorldCell<'w>,
|
||||||
last_run: Tick,
|
last_run: Tick,
|
||||||
this_run: Tick,
|
this_run: Tick,
|
||||||
) -> QueryCombinationIter<'w, 's, Q, F, K> {
|
) -> QueryCombinationIter<'w, 's, Q, F, K> {
|
||||||
@ -817,7 +869,7 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
|||||||
// SAFETY: query is read only
|
// SAFETY: query is read only
|
||||||
unsafe {
|
unsafe {
|
||||||
self.as_readonly().for_each_unchecked_manual(
|
self.as_readonly().for_each_unchecked_manual(
|
||||||
world,
|
world.as_unsafe_world_cell_readonly(),
|
||||||
func,
|
func,
|
||||||
world.last_change_tick(),
|
world.last_change_tick(),
|
||||||
world.read_change_tick(),
|
world.read_change_tick(),
|
||||||
@ -829,11 +881,17 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
|||||||
/// `iter_mut()` method, but cannot be chained like a normal [`Iterator`].
|
/// `iter_mut()` method, but cannot be chained like a normal [`Iterator`].
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn for_each_mut<'w, FN: FnMut(Q::Item<'w>)>(&mut self, world: &'w mut World, func: FN) {
|
pub fn for_each_mut<'w, FN: FnMut(Q::Item<'w>)>(&mut self, world: &'w mut World, func: FN) {
|
||||||
let change_tick = world.change_tick();
|
|
||||||
self.update_archetypes(world);
|
self.update_archetypes(world);
|
||||||
|
let change_tick = world.change_tick();
|
||||||
|
let last_change_tick = world.last_change_tick();
|
||||||
// SAFETY: query has unique world access
|
// SAFETY: query has unique world access
|
||||||
unsafe {
|
unsafe {
|
||||||
self.for_each_unchecked_manual(world, func, world.last_change_tick(), change_tick);
|
self.for_each_unchecked_manual(
|
||||||
|
world.as_unsafe_world_cell(),
|
||||||
|
func,
|
||||||
|
last_change_tick,
|
||||||
|
change_tick,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -847,16 +905,11 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn for_each_unchecked<'w, FN: FnMut(Q::Item<'w>)>(
|
pub unsafe fn for_each_unchecked<'w, FN: FnMut(Q::Item<'w>)>(
|
||||||
&mut self,
|
&mut self,
|
||||||
world: &'w World,
|
world: UnsafeWorldCell<'w>,
|
||||||
func: FN,
|
func: FN,
|
||||||
) {
|
) {
|
||||||
self.update_archetypes(world);
|
self.update_archetypes_unsafe_world_cell(world);
|
||||||
self.for_each_unchecked_manual(
|
self.for_each_unchecked_manual(world, func, world.last_change_tick(), world.change_tick());
|
||||||
world,
|
|
||||||
func,
|
|
||||||
world.last_change_tick(),
|
|
||||||
world.read_change_tick(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a parallel iterator over the query results for the given [`World`].
|
/// Returns a parallel iterator over the query results for the given [`World`].
|
||||||
@ -871,7 +924,7 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
|||||||
) -> QueryParIter<'w, 's, Q::ReadOnly, F::ReadOnly> {
|
) -> QueryParIter<'w, 's, Q::ReadOnly, F::ReadOnly> {
|
||||||
self.update_archetypes(world);
|
self.update_archetypes(world);
|
||||||
QueryParIter {
|
QueryParIter {
|
||||||
world,
|
world: world.as_unsafe_world_cell_readonly(),
|
||||||
state: self.as_readonly(),
|
state: self.as_readonly(),
|
||||||
last_run: world.last_change_tick(),
|
last_run: world.last_change_tick(),
|
||||||
this_run: world.read_change_tick(),
|
this_run: world.read_change_tick(),
|
||||||
@ -888,10 +941,11 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
|||||||
pub fn par_iter_mut<'w, 's>(&'s mut self, world: &'w mut World) -> QueryParIter<'w, 's, Q, F> {
|
pub fn par_iter_mut<'w, 's>(&'s mut self, world: &'w mut World) -> QueryParIter<'w, 's, Q, F> {
|
||||||
self.update_archetypes(world);
|
self.update_archetypes(world);
|
||||||
let this_run = world.change_tick();
|
let this_run = world.change_tick();
|
||||||
|
let last_run = world.last_change_tick();
|
||||||
QueryParIter {
|
QueryParIter {
|
||||||
world,
|
world: world.as_unsafe_world_cell(),
|
||||||
state: self,
|
state: self,
|
||||||
last_run: world.last_change_tick(),
|
last_run,
|
||||||
this_run,
|
this_run,
|
||||||
batching_strategy: BatchingStrategy::new(),
|
batching_strategy: BatchingStrategy::new(),
|
||||||
}
|
}
|
||||||
@ -909,7 +963,7 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
|||||||
/// with a mismatched [`WorldId`] is unsound.
|
/// with a mismatched [`WorldId`] is unsound.
|
||||||
pub(crate) unsafe fn for_each_unchecked_manual<'w, FN: FnMut(Q::Item<'w>)>(
|
pub(crate) unsafe fn for_each_unchecked_manual<'w, FN: FnMut(Q::Item<'w>)>(
|
||||||
&self,
|
&self,
|
||||||
world: &'w World,
|
world: UnsafeWorldCell<'w>,
|
||||||
mut func: FN,
|
mut func: FN,
|
||||||
last_run: Tick,
|
last_run: Tick,
|
||||||
this_run: Tick,
|
this_run: Tick,
|
||||||
@ -919,7 +973,7 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
|||||||
let mut fetch = Q::init_fetch(world, &self.fetch_state, last_run, this_run);
|
let mut fetch = Q::init_fetch(world, &self.fetch_state, last_run, this_run);
|
||||||
let mut filter = F::init_fetch(world, &self.filter_state, last_run, this_run);
|
let mut filter = F::init_fetch(world, &self.filter_state, last_run, this_run);
|
||||||
|
|
||||||
let tables = &world.storages().tables;
|
let tables = &world.unsafe_world().storages().tables;
|
||||||
if Q::IS_DENSE && F::IS_DENSE {
|
if Q::IS_DENSE && F::IS_DENSE {
|
||||||
for table_id in &self.matched_table_ids {
|
for table_id in &self.matched_table_ids {
|
||||||
let table = tables.get(*table_id).debug_checked_unwrap();
|
let table = tables.get(*table_id).debug_checked_unwrap();
|
||||||
@ -937,7 +991,7 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let archetypes = &world.archetypes;
|
let archetypes = world.archetypes();
|
||||||
for archetype_id in &self.matched_archetype_ids {
|
for archetype_id in &self.matched_archetype_ids {
|
||||||
let archetype = archetypes.get(*archetype_id).debug_checked_unwrap();
|
let archetype = archetypes.get(*archetype_id).debug_checked_unwrap();
|
||||||
let table = tables.get(archetype.table_id()).debug_checked_unwrap();
|
let table = tables.get(archetype.table_id()).debug_checked_unwrap();
|
||||||
@ -983,7 +1037,7 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
|||||||
FN: Fn(Q::Item<'w>) + Send + Sync + Clone,
|
FN: Fn(Q::Item<'w>) + Send + Sync + Clone,
|
||||||
>(
|
>(
|
||||||
&self,
|
&self,
|
||||||
world: &'w World,
|
world: UnsafeWorldCell<'w>,
|
||||||
batch_size: usize,
|
batch_size: usize,
|
||||||
func: FN,
|
func: FN,
|
||||||
last_run: Tick,
|
last_run: Tick,
|
||||||
@ -993,7 +1047,8 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
|||||||
// QueryIter, QueryIterationCursor, QueryManyIter, QueryCombinationIter, QueryState::for_each_unchecked_manual, QueryState::par_for_each_unchecked_manual
|
// QueryIter, QueryIterationCursor, QueryManyIter, QueryCombinationIter, QueryState::for_each_unchecked_manual, QueryState::par_for_each_unchecked_manual
|
||||||
ComputeTaskPool::get().scope(|scope| {
|
ComputeTaskPool::get().scope(|scope| {
|
||||||
if Q::IS_DENSE && F::IS_DENSE {
|
if Q::IS_DENSE && F::IS_DENSE {
|
||||||
let tables = &world.storages().tables;
|
// SAFETY: We only access table data that has been registered in `self.archetype_component_access`.
|
||||||
|
let tables = &world.unsafe_world().storages().tables;
|
||||||
for table_id in &self.matched_table_ids {
|
for table_id in &self.matched_table_ids {
|
||||||
let table = &tables[*table_id];
|
let table = &tables[*table_id];
|
||||||
if table.is_empty() {
|
if table.is_empty() {
|
||||||
@ -1009,7 +1064,7 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
|||||||
Q::init_fetch(world, &self.fetch_state, last_run, this_run);
|
Q::init_fetch(world, &self.fetch_state, last_run, this_run);
|
||||||
let mut filter =
|
let mut filter =
|
||||||
F::init_fetch(world, &self.filter_state, last_run, this_run);
|
F::init_fetch(world, &self.filter_state, last_run, this_run);
|
||||||
let tables = &world.storages().tables;
|
let tables = &world.unsafe_world().storages().tables;
|
||||||
let table = tables.get(*table_id).debug_checked_unwrap();
|
let table = tables.get(*table_id).debug_checked_unwrap();
|
||||||
let entities = table.entities();
|
let entities = table.entities();
|
||||||
Q::set_table(&mut fetch, &self.fetch_state, table);
|
Q::set_table(&mut fetch, &self.fetch_state, table);
|
||||||
@ -1037,7 +1092,7 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let archetypes = &world.archetypes;
|
let archetypes = world.archetypes();
|
||||||
for archetype_id in &self.matched_archetype_ids {
|
for archetype_id in &self.matched_archetype_ids {
|
||||||
let mut offset = 0;
|
let mut offset = 0;
|
||||||
let archetype = &archetypes[*archetype_id];
|
let archetype = &archetypes[*archetype_id];
|
||||||
@ -1053,9 +1108,9 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
|||||||
Q::init_fetch(world, &self.fetch_state, last_run, this_run);
|
Q::init_fetch(world, &self.fetch_state, last_run, this_run);
|
||||||
let mut filter =
|
let mut filter =
|
||||||
F::init_fetch(world, &self.filter_state, last_run, this_run);
|
F::init_fetch(world, &self.filter_state, last_run, this_run);
|
||||||
let tables = &world.storages().tables;
|
let tables = &world.unsafe_world().storages().tables;
|
||||||
let archetype =
|
let archetype =
|
||||||
world.archetypes.get(*archetype_id).debug_checked_unwrap();
|
world.archetypes().get(*archetype_id).debug_checked_unwrap();
|
||||||
let table = tables.get(archetype.table_id()).debug_checked_unwrap();
|
let table = tables.get(archetype.table_id()).debug_checked_unwrap();
|
||||||
Q::set_archetype(&mut fetch, &self.fetch_state, archetype, table);
|
Q::set_archetype(&mut fetch, &self.fetch_state, archetype, table);
|
||||||
F::set_archetype(&mut filter, &self.filter_state, archetype, table);
|
F::set_archetype(&mut filter, &self.filter_state, archetype, table);
|
||||||
@ -1130,7 +1185,7 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
|||||||
// SAFETY: query is read only
|
// SAFETY: query is read only
|
||||||
unsafe {
|
unsafe {
|
||||||
self.as_readonly().get_single_unchecked_manual(
|
self.as_readonly().get_single_unchecked_manual(
|
||||||
world,
|
world.as_unsafe_world_cell_readonly(),
|
||||||
world.last_change_tick(),
|
world.last_change_tick(),
|
||||||
world.read_change_tick(),
|
world.read_change_tick(),
|
||||||
)
|
)
|
||||||
@ -1164,8 +1219,15 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
|||||||
self.update_archetypes(world);
|
self.update_archetypes(world);
|
||||||
|
|
||||||
let change_tick = world.change_tick();
|
let change_tick = world.change_tick();
|
||||||
|
let last_change_tick = world.last_change_tick();
|
||||||
// SAFETY: query has unique world access
|
// SAFETY: query has unique world access
|
||||||
unsafe { self.get_single_unchecked_manual(world, world.last_change_tick(), change_tick) }
|
unsafe {
|
||||||
|
self.get_single_unchecked_manual(
|
||||||
|
world.as_unsafe_world_cell(),
|
||||||
|
last_change_tick,
|
||||||
|
change_tick,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a query result when there is exactly one entity matching the query.
|
/// Returns a query result when there is exactly one entity matching the query.
|
||||||
@ -1180,10 +1242,10 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn get_single_unchecked<'w>(
|
pub unsafe fn get_single_unchecked<'w>(
|
||||||
&mut self,
|
&mut self,
|
||||||
world: &'w World,
|
world: UnsafeWorldCell<'w>,
|
||||||
) -> Result<Q::Item<'w>, QuerySingleError> {
|
) -> Result<Q::Item<'w>, QuerySingleError> {
|
||||||
self.update_archetypes(world);
|
self.update_archetypes_unsafe_world_cell(world);
|
||||||
self.get_single_unchecked_manual(world, world.last_change_tick(), world.read_change_tick())
|
self.get_single_unchecked_manual(world, world.last_change_tick(), world.change_tick())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a query result when there is exactly one entity matching the query,
|
/// Returns a query result when there is exactly one entity matching the query,
|
||||||
@ -1199,7 +1261,7 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn get_single_unchecked_manual<'w>(
|
pub unsafe fn get_single_unchecked_manual<'w>(
|
||||||
&self,
|
&self,
|
||||||
world: &'w World,
|
world: UnsafeWorldCell<'w>,
|
||||||
last_run: Tick,
|
last_run: Tick,
|
||||||
this_run: Tick,
|
this_run: Tick,
|
||||||
) -> Result<Q::Item<'w>, QuerySingleError> {
|
) -> Result<Q::Item<'w>, QuerySingleError> {
|
||||||
@ -1269,11 +1331,11 @@ mod tests {
|
|||||||
// as it is shared and unsafe
|
// as it is shared and unsafe
|
||||||
// We don't care about aliased mutability for the read-only equivalent
|
// We don't care about aliased mutability for the read-only equivalent
|
||||||
|
|
||||||
// SAFETY: mutable access is not checked, but we own the world and don't use the query results
|
// SAFETY: Query does not access world data.
|
||||||
assert!(unsafe {
|
assert!(unsafe {
|
||||||
query_state
|
query_state
|
||||||
.get_many_unchecked_manual::<10>(
|
.get_many_unchecked_manual::<10>(
|
||||||
&world,
|
world.as_unsafe_world_cell_readonly(),
|
||||||
entities.clone().try_into().unwrap(),
|
entities.clone().try_into().unwrap(),
|
||||||
last_change_tick,
|
last_change_tick,
|
||||||
change_tick,
|
change_tick,
|
||||||
@ -1282,11 +1344,11 @@ mod tests {
|
|||||||
});
|
});
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
// SAFETY: mutable access is not checked, but we own the world and don't use the query results
|
// SAFETY: Query does not access world data.
|
||||||
unsafe {
|
unsafe {
|
||||||
query_state
|
query_state
|
||||||
.get_many_unchecked_manual(
|
.get_many_unchecked_manual(
|
||||||
&world,
|
world.as_unsafe_world_cell_readonly(),
|
||||||
[entities[0], entities[0]],
|
[entities[0], entities[0]],
|
||||||
last_change_tick,
|
last_change_tick,
|
||||||
change_tick,
|
change_tick,
|
||||||
@ -1297,11 +1359,11 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
// SAFETY: mutable access is not checked, but we own the world and don't use the query results
|
// SAFETY: Query does not access world data.
|
||||||
unsafe {
|
unsafe {
|
||||||
query_state
|
query_state
|
||||||
.get_many_unchecked_manual(
|
.get_many_unchecked_manual(
|
||||||
&world,
|
world.as_unsafe_world_cell_readonly(),
|
||||||
[entities[0], entities[1], entities[0]],
|
[entities[0], entities[1], entities[0]],
|
||||||
last_change_tick,
|
last_change_tick,
|
||||||
change_tick,
|
change_tick,
|
||||||
@ -1312,11 +1374,11 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
// SAFETY: mutable access is not checked, but we own the world and don't use the query results
|
// SAFETY: Query does not access world data.
|
||||||
unsafe {
|
unsafe {
|
||||||
query_state
|
query_state
|
||||||
.get_many_unchecked_manual(
|
.get_many_unchecked_manual(
|
||||||
&world,
|
world.as_unsafe_world_cell_readonly(),
|
||||||
[entities[9], entities[9]],
|
[entities[9], entities[9]],
|
||||||
last_change_tick,
|
last_change_tick,
|
||||||
change_tick,
|
change_tick,
|
||||||
|
|||||||
@ -183,19 +183,20 @@ impl<Param: SystemParam> SystemState<Param> {
|
|||||||
where
|
where
|
||||||
Param: ReadOnlySystemParam,
|
Param: ReadOnlySystemParam,
|
||||||
{
|
{
|
||||||
self.validate_world(world);
|
self.validate_world(world.id());
|
||||||
self.update_archetypes(world);
|
self.update_archetypes(world);
|
||||||
// SAFETY: Param is read-only and doesn't allow mutable access to World. It also matches the World this SystemState was created with.
|
// SAFETY: Param is read-only and doesn't allow mutable access to World.
|
||||||
unsafe { self.get_unchecked_manual(world) }
|
// It also matches the World this SystemState was created with.
|
||||||
|
unsafe { self.get_unchecked_manual(world.as_unsafe_world_cell_readonly()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieve the mutable [`SystemParam`] values.
|
/// Retrieve the mutable [`SystemParam`] values.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_mut<'w, 's>(&'s mut self, world: &'w mut World) -> SystemParamItem<'w, 's, Param> {
|
pub fn get_mut<'w, 's>(&'s mut self, world: &'w mut World) -> SystemParamItem<'w, 's, Param> {
|
||||||
self.validate_world(world);
|
self.validate_world(world.id());
|
||||||
self.update_archetypes(world);
|
self.update_archetypes(world);
|
||||||
// SAFETY: World is uniquely borrowed and matches the World this SystemState was created with.
|
// SAFETY: World is uniquely borrowed and matches the World this SystemState was created with.
|
||||||
unsafe { self.get_unchecked_manual(world) }
|
unsafe { self.get_unchecked_manual(world.as_unsafe_world_cell()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Applies all state queued up for [`SystemParam`] values. For example, this will apply commands queued up
|
/// Applies all state queued up for [`SystemParam`] values. For example, this will apply commands queued up
|
||||||
@ -206,17 +207,28 @@ impl<Param: SystemParam> SystemState<Param> {
|
|||||||
Param::apply(&mut self.param_state, &self.meta, world);
|
Param::apply(&mut self.param_state, &self.meta, world);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if `world` is the same one that was used to call [`SystemState::new`].
|
/// Returns `true` if `world_id` matches the [`World`] that was used to call [`SystemState::new`].
|
||||||
/// Otherwise, this returns false.
|
/// Otherwise, this returns false.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn matches_world(&self, world: &World) -> bool {
|
pub fn matches_world(&self, world_id: WorldId) -> bool {
|
||||||
self.world_id == world.id()
|
self.world_id == world_id
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Asserts that the [`SystemState`] matches the provided [`World`].
|
/// Asserts that the [`SystemState`] matches the provided world.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn validate_world(&self, world: &World) {
|
fn validate_world(&self, world_id: WorldId) {
|
||||||
assert!(self.matches_world(world), "Encountered a mismatched World. A SystemState cannot be used with Worlds other than the one it was created with.");
|
assert!(self.matches_world(world_id), "Encountered a mismatched World. A SystemState cannot be used with Worlds other than the one it was created with.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Updates the state's internal view of the [`World`]'s archetypes. If this is not called before fetching the parameters,
|
||||||
|
/// the results may not accurately reflect what is in the `world`.
|
||||||
|
///
|
||||||
|
/// This is only required if [`SystemState::get_manual`] or [`SystemState::get_manual_mut`] is being called, and it only needs to
|
||||||
|
/// be called if the `world` has been structurally mutated (i.e. added/removed a component or resource). Users using
|
||||||
|
/// [`SystemState::get`] or [`SystemState::get_mut`] do not need to call this as it will be automatically called for them.
|
||||||
|
#[inline]
|
||||||
|
pub fn update_archetypes(&mut self, world: &World) {
|
||||||
|
self.update_archetypes_unsafe_world_cell(world.as_unsafe_world_cell_readonly());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Updates the state's internal view of the `world`'s archetypes. If this is not called before fetching the parameters,
|
/// Updates the state's internal view of the `world`'s archetypes. If this is not called before fetching the parameters,
|
||||||
@ -225,8 +237,12 @@ impl<Param: SystemParam> SystemState<Param> {
|
|||||||
/// This is only required if [`SystemState::get_manual`] or [`SystemState::get_manual_mut`] is being called, and it only needs to
|
/// This is only required if [`SystemState::get_manual`] or [`SystemState::get_manual_mut`] is being called, and it only needs to
|
||||||
/// be called if the `world` has been structurally mutated (i.e. added/removed a component or resource). Users using
|
/// be called if the `world` has been structurally mutated (i.e. added/removed a component or resource). Users using
|
||||||
/// [`SystemState::get`] or [`SystemState::get_mut`] do not need to call this as it will be automatically called for them.
|
/// [`SystemState::get`] or [`SystemState::get_mut`] do not need to call this as it will be automatically called for them.
|
||||||
|
///
|
||||||
|
/// # Note
|
||||||
|
///
|
||||||
|
/// This method only accesses world metadata.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn update_archetypes(&mut self, world: &World) {
|
pub fn update_archetypes_unsafe_world_cell(&mut self, world: UnsafeWorldCell) {
|
||||||
let archetypes = world.archetypes();
|
let archetypes = world.archetypes();
|
||||||
let new_generation = archetypes.generation();
|
let new_generation = archetypes.generation();
|
||||||
let old_generation = std::mem::replace(&mut self.archetype_generation, new_generation);
|
let old_generation = std::mem::replace(&mut self.archetype_generation, new_generation);
|
||||||
@ -254,10 +270,11 @@ impl<Param: SystemParam> SystemState<Param> {
|
|||||||
where
|
where
|
||||||
Param: ReadOnlySystemParam,
|
Param: ReadOnlySystemParam,
|
||||||
{
|
{
|
||||||
self.validate_world(world);
|
self.validate_world(world.id());
|
||||||
let change_tick = world.read_change_tick();
|
let change_tick = world.read_change_tick();
|
||||||
// SAFETY: Param is read-only and doesn't allow mutable access to World. It also matches the World this SystemState was created with.
|
// SAFETY: Param is read-only and doesn't allow mutable access to World.
|
||||||
unsafe { self.fetch(world, change_tick) }
|
// It also matches the World this SystemState was created with.
|
||||||
|
unsafe { self.fetch(world.as_unsafe_world_cell_readonly(), change_tick) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieve the mutable [`SystemParam`] values. This will not update the state's view of the world's archetypes
|
/// Retrieve the mutable [`SystemParam`] values. This will not update the state's view of the world's archetypes
|
||||||
@ -272,10 +289,10 @@ impl<Param: SystemParam> SystemState<Param> {
|
|||||||
&'s mut self,
|
&'s mut self,
|
||||||
world: &'w mut World,
|
world: &'w mut World,
|
||||||
) -> SystemParamItem<'w, 's, Param> {
|
) -> SystemParamItem<'w, 's, Param> {
|
||||||
self.validate_world(world);
|
self.validate_world(world.id());
|
||||||
let change_tick = world.change_tick();
|
let change_tick = world.change_tick();
|
||||||
// SAFETY: World is uniquely borrowed and matches the World this SystemState was created with.
|
// SAFETY: World is uniquely borrowed and matches the World this SystemState was created with.
|
||||||
unsafe { self.fetch(world, change_tick) }
|
unsafe { self.fetch(world.as_unsafe_world_cell(), change_tick) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieve the [`SystemParam`] values. This will not update archetypes automatically.
|
/// Retrieve the [`SystemParam`] values. This will not update archetypes automatically.
|
||||||
@ -287,7 +304,7 @@ impl<Param: SystemParam> SystemState<Param> {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn get_unchecked_manual<'w, 's>(
|
pub unsafe fn get_unchecked_manual<'w, 's>(
|
||||||
&'s mut self,
|
&'s mut self,
|
||||||
world: &'w World,
|
world: UnsafeWorldCell<'w>,
|
||||||
) -> SystemParamItem<'w, 's, Param> {
|
) -> SystemParamItem<'w, 's, Param> {
|
||||||
let change_tick = world.increment_change_tick();
|
let change_tick = world.increment_change_tick();
|
||||||
self.fetch(world, change_tick)
|
self.fetch(world, change_tick)
|
||||||
@ -300,15 +317,10 @@ impl<Param: SystemParam> SystemState<Param> {
|
|||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn fetch<'w, 's>(
|
unsafe fn fetch<'w, 's>(
|
||||||
&'s mut self,
|
&'s mut self,
|
||||||
world: &'w World,
|
world: UnsafeWorldCell<'w>,
|
||||||
change_tick: Tick,
|
change_tick: Tick,
|
||||||
) -> SystemParamItem<'w, 's, Param> {
|
) -> SystemParamItem<'w, 's, Param> {
|
||||||
let param = Param::get_param(
|
let param = Param::get_param(&mut self.param_state, &self.meta, world, change_tick);
|
||||||
&mut self.param_state,
|
|
||||||
&self.meta,
|
|
||||||
world.as_unsafe_world_cell_migration_internal(),
|
|
||||||
change_tick,
|
|
||||||
);
|
|
||||||
self.meta.last_run = change_tick;
|
self.meta.last_run = change_tick;
|
||||||
param
|
param
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1727,7 +1727,15 @@ mod tests {
|
|||||||
let world2 = World::new();
|
let world2 = World::new();
|
||||||
let qstate = world1.query::<()>();
|
let qstate = world1.query::<()>();
|
||||||
// SAFETY: doesnt access anything
|
// SAFETY: doesnt access anything
|
||||||
let query = unsafe { Query::new(&world2, &qstate, Tick::new(0), Tick::new(0), false) };
|
let query = unsafe {
|
||||||
|
Query::new(
|
||||||
|
world2.as_unsafe_world_cell_readonly(),
|
||||||
|
&qstate,
|
||||||
|
Tick::new(0),
|
||||||
|
Tick::new(0),
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
};
|
||||||
query.iter();
|
query.iter();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,7 @@ use crate::{
|
|||||||
BatchingStrategy, QueryCombinationIter, QueryEntityError, QueryIter, QueryManyIter,
|
BatchingStrategy, QueryCombinationIter, QueryEntityError, QueryIter, QueryManyIter,
|
||||||
QueryParIter, QuerySingleError, QueryState, ROQueryItem, ReadOnlyWorldQuery, WorldQuery,
|
QueryParIter, QuerySingleError, QueryState, ROQueryItem, ReadOnlyWorldQuery, WorldQuery,
|
||||||
},
|
},
|
||||||
world::{Mut, World},
|
world::{unsafe_world_cell::UnsafeWorldCell, Mut},
|
||||||
};
|
};
|
||||||
use std::{any::TypeId, borrow::Borrow, fmt::Debug};
|
use std::{any::TypeId, borrow::Borrow, fmt::Debug};
|
||||||
|
|
||||||
@ -24,6 +24,8 @@ use std::{any::TypeId, borrow::Borrow, fmt::Debug};
|
|||||||
/// A set of conditions that determines whether query items should be kept or discarded.
|
/// A set of conditions that determines whether query items should be kept or discarded.
|
||||||
/// This type parameter is optional.
|
/// This type parameter is optional.
|
||||||
///
|
///
|
||||||
|
/// [`World`]: crate::world::World
|
||||||
|
///
|
||||||
/// # System parameter declaration
|
/// # System parameter declaration
|
||||||
///
|
///
|
||||||
/// A query should always be declared as a system parameter.
|
/// A query should always be declared as a system parameter.
|
||||||
@ -274,7 +276,8 @@ use std::{any::TypeId, borrow::Borrow, fmt::Debug};
|
|||||||
/// [`With`]: crate::query::With
|
/// [`With`]: crate::query::With
|
||||||
/// [`Without`]: crate::query::Without
|
/// [`Without`]: crate::query::Without
|
||||||
pub struct Query<'world, 'state, Q: WorldQuery, F: ReadOnlyWorldQuery = ()> {
|
pub struct Query<'world, 'state, Q: WorldQuery, F: ReadOnlyWorldQuery = ()> {
|
||||||
world: &'world World,
|
// SAFETY: Must have access to the components registered in `state`.
|
||||||
|
world: UnsafeWorldCell<'world>,
|
||||||
state: &'state QueryState<Q, F>,
|
state: &'state QueryState<Q, F>,
|
||||||
last_run: Tick,
|
last_run: Tick,
|
||||||
this_run: Tick,
|
this_run: Tick,
|
||||||
@ -288,7 +291,12 @@ pub struct Query<'world, 'state, Q: WorldQuery, F: ReadOnlyWorldQuery = ()> {
|
|||||||
|
|
||||||
impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> std::fmt::Debug for Query<'w, 's, Q, F> {
|
impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> std::fmt::Debug for Query<'w, 's, Q, F> {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(f, "Query {{ matched entities: {}, world: {:?}, state: {:?}, last_run: {:?}, this_run: {:?} }}", self.iter().count(), self.world, self.state, self.last_run, self.this_run)
|
write!(
|
||||||
|
f, "Query {{ matched entities: {}, world: {:?}, state: {:?}, last_run: {:?}, this_run: {:?} }}",
|
||||||
|
self.iter().count(),
|
||||||
|
// SAFETY: World's Debug implementation only accesses metadata.
|
||||||
|
unsafe { self.world.world_metadata() },
|
||||||
|
self.state, self.last_run, self.this_run)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -305,13 +313,13 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
|
|||||||
/// called in ways that ensure the queries have unique mutable access.
|
/// called in ways that ensure the queries have unique mutable access.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) unsafe fn new(
|
pub(crate) unsafe fn new(
|
||||||
world: &'w World,
|
world: UnsafeWorldCell<'w>,
|
||||||
state: &'s QueryState<Q, F>,
|
state: &'s QueryState<Q, F>,
|
||||||
last_run: Tick,
|
last_run: Tick,
|
||||||
this_run: Tick,
|
this_run: Tick,
|
||||||
force_read_only_component_access: bool,
|
force_read_only_component_access: bool,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
state.validate_world(world);
|
state.validate_world(world.id());
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
force_read_only_component_access,
|
force_read_only_component_access,
|
||||||
@ -369,8 +377,9 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
|
|||||||
/// - [`for_each`](Self::for_each) for the closure based alternative.
|
/// - [`for_each`](Self::for_each) for the closure based alternative.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn iter(&self) -> QueryIter<'_, 's, Q::ReadOnly, F::ReadOnly> {
|
pub fn iter(&self) -> QueryIter<'_, 's, Q::ReadOnly, F::ReadOnly> {
|
||||||
// SAFETY: system runs without conflicts with other systems.
|
// SAFETY:
|
||||||
// same-system queries have runtime borrow checks when they conflict
|
// - `self.world` has permission to access the required components.
|
||||||
|
// - The query is read-only, so it can be aliased even if it was originaly mutable.
|
||||||
unsafe {
|
unsafe {
|
||||||
self.state
|
self.state
|
||||||
.as_readonly()
|
.as_readonly()
|
||||||
@ -404,8 +413,7 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
|
|||||||
/// - [`for_each_mut`](Self::for_each_mut) for the closure based alternative.
|
/// - [`for_each_mut`](Self::for_each_mut) for the closure based alternative.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn iter_mut(&mut self) -> QueryIter<'_, 's, Q, F> {
|
pub fn iter_mut(&mut self) -> QueryIter<'_, 's, Q, F> {
|
||||||
// SAFETY: system runs without conflicts with other systems.
|
// SAFETY: `self.world` has permission to access the required components.
|
||||||
// same-system queries have runtime borrow checks when they conflict
|
|
||||||
unsafe {
|
unsafe {
|
||||||
self.state
|
self.state
|
||||||
.iter_unchecked_manual(self.world, self.last_run, self.this_run)
|
.iter_unchecked_manual(self.world, self.last_run, self.this_run)
|
||||||
@ -435,8 +443,9 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
|
|||||||
pub fn iter_combinations<const K: usize>(
|
pub fn iter_combinations<const K: usize>(
|
||||||
&self,
|
&self,
|
||||||
) -> QueryCombinationIter<'_, 's, Q::ReadOnly, F::ReadOnly, K> {
|
) -> QueryCombinationIter<'_, 's, Q::ReadOnly, F::ReadOnly, K> {
|
||||||
// SAFETY: system runs without conflicts with other systems.
|
// SAFETY:
|
||||||
// same-system queries have runtime borrow checks when they conflict
|
// - `self.world` has permission to access the required components.
|
||||||
|
// - The query is read-only, so it can be aliased even if it was originaly mutable.
|
||||||
unsafe {
|
unsafe {
|
||||||
self.state.as_readonly().iter_combinations_unchecked_manual(
|
self.state.as_readonly().iter_combinations_unchecked_manual(
|
||||||
self.world,
|
self.world,
|
||||||
@ -469,8 +478,7 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
|
|||||||
pub fn iter_combinations_mut<const K: usize>(
|
pub fn iter_combinations_mut<const K: usize>(
|
||||||
&mut self,
|
&mut self,
|
||||||
) -> QueryCombinationIter<'_, 's, Q, F, K> {
|
) -> QueryCombinationIter<'_, 's, Q, F, K> {
|
||||||
// SAFETY: system runs without conflicts with other systems.
|
// SAFETY: `self.world` has permission to access the required components.
|
||||||
// same-system queries have runtime borrow checks when they conflict
|
|
||||||
unsafe {
|
unsafe {
|
||||||
self.state
|
self.state
|
||||||
.iter_combinations_unchecked_manual(self.world, self.last_run, self.this_run)
|
.iter_combinations_unchecked_manual(self.world, self.last_run, self.this_run)
|
||||||
@ -521,8 +529,9 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
|
|||||||
where
|
where
|
||||||
EntityList::Item: Borrow<Entity>,
|
EntityList::Item: Borrow<Entity>,
|
||||||
{
|
{
|
||||||
// SAFETY: system runs without conflicts with other systems.
|
// SAFETY:
|
||||||
// same-system queries have runtime borrow checks when they conflict
|
// - `self.world` has permission to access the required components.
|
||||||
|
// - The query is read-only, so it can be aliased even if it was originaly mutable.
|
||||||
unsafe {
|
unsafe {
|
||||||
self.state.as_readonly().iter_many_unchecked_manual(
|
self.state.as_readonly().iter_many_unchecked_manual(
|
||||||
entities,
|
entities,
|
||||||
@ -574,8 +583,7 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
|
|||||||
where
|
where
|
||||||
EntityList::Item: Borrow<Entity>,
|
EntityList::Item: Borrow<Entity>,
|
||||||
{
|
{
|
||||||
// SAFETY: system runs without conflicts with other systems.
|
// SAFETY: `self.world` has permission to access the required components.
|
||||||
// same-system queries have runtime borrow checks when they conflict
|
|
||||||
unsafe {
|
unsafe {
|
||||||
self.state.iter_many_unchecked_manual(
|
self.state.iter_many_unchecked_manual(
|
||||||
entities,
|
entities,
|
||||||
@ -598,8 +606,9 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
|
|||||||
/// - [`iter`](Self::iter) and [`iter_mut`](Self::iter_mut) for the safe versions.
|
/// - [`iter`](Self::iter) and [`iter_mut`](Self::iter_mut) for the safe versions.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn iter_unsafe(&self) -> QueryIter<'_, 's, Q, F> {
|
pub unsafe fn iter_unsafe(&self) -> QueryIter<'_, 's, Q, F> {
|
||||||
// SEMI-SAFETY: system runs without conflicts with other systems.
|
// SAFETY:
|
||||||
// same-system queries have runtime borrow checks when they conflict
|
// - `self.world` has permission to access the required components.
|
||||||
|
// - The caller ensures that this operation will not result in any aliased mutable accesses.
|
||||||
self.state
|
self.state
|
||||||
.iter_unchecked_manual(self.world, self.last_run, self.this_run)
|
.iter_unchecked_manual(self.world, self.last_run, self.this_run)
|
||||||
}
|
}
|
||||||
@ -618,8 +627,9 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
|
|||||||
pub unsafe fn iter_combinations_unsafe<const K: usize>(
|
pub unsafe fn iter_combinations_unsafe<const K: usize>(
|
||||||
&self,
|
&self,
|
||||||
) -> QueryCombinationIter<'_, 's, Q, F, K> {
|
) -> QueryCombinationIter<'_, 's, Q, F, K> {
|
||||||
// SEMI-SAFETY: system runs without conflicts with other systems.
|
// SAFETY:
|
||||||
// same-system queries have runtime borrow checks when they conflict
|
// - `self.world` has permission to access the required components.
|
||||||
|
// - The caller ensures that this operation will not result in any aliased mutable accesses.
|
||||||
self.state
|
self.state
|
||||||
.iter_combinations_unchecked_manual(self.world, self.last_run, self.this_run)
|
.iter_combinations_unchecked_manual(self.world, self.last_run, self.this_run)
|
||||||
}
|
}
|
||||||
@ -642,6 +652,9 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
|
|||||||
where
|
where
|
||||||
EntityList::Item: Borrow<Entity>,
|
EntityList::Item: Borrow<Entity>,
|
||||||
{
|
{
|
||||||
|
// SAFETY:
|
||||||
|
// - `self.world` has permission to access the required components.
|
||||||
|
// - The caller ensures that this operation will not result in any aliased mutable accesses.
|
||||||
self.state
|
self.state
|
||||||
.iter_many_unchecked_manual(entities, self.world, self.last_run, self.this_run)
|
.iter_many_unchecked_manual(entities, self.world, self.last_run, self.this_run)
|
||||||
}
|
}
|
||||||
@ -672,8 +685,9 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
|
|||||||
/// - [`iter`](Self::iter) for the iterator based alternative.
|
/// - [`iter`](Self::iter) for the iterator based alternative.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn for_each<'this>(&'this self, f: impl FnMut(ROQueryItem<'this, Q>)) {
|
pub fn for_each<'this>(&'this self, f: impl FnMut(ROQueryItem<'this, Q>)) {
|
||||||
// SAFETY: system runs without conflicts with other systems.
|
// SAFETY:
|
||||||
// same-system queries have runtime borrow checks when they conflict
|
// - `self.world` has permission to access the required components.
|
||||||
|
// - The query is read-only, so it can be aliased even if it was originaly mutable.
|
||||||
unsafe {
|
unsafe {
|
||||||
self.state.as_readonly().for_each_unchecked_manual(
|
self.state.as_readonly().for_each_unchecked_manual(
|
||||||
self.world,
|
self.world,
|
||||||
@ -710,8 +724,7 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
|
|||||||
/// - [`iter_mut`](Self::iter_mut) for the iterator based alternative.
|
/// - [`iter_mut`](Self::iter_mut) for the iterator based alternative.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn for_each_mut<'a>(&'a mut self, f: impl FnMut(Q::Item<'a>)) {
|
pub fn for_each_mut<'a>(&'a mut self, f: impl FnMut(Q::Item<'a>)) {
|
||||||
// SAFETY: system runs without conflicts with other systems. same-system queries have runtime
|
// SAFETY: `self.world` has permission to access the required components.
|
||||||
// borrow checks when they conflict
|
|
||||||
unsafe {
|
unsafe {
|
||||||
self.state
|
self.state
|
||||||
.for_each_unchecked_manual(self.world, f, self.last_run, self.this_run);
|
.for_each_unchecked_manual(self.world, f, self.last_run, self.this_run);
|
||||||
@ -723,6 +736,7 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
|
|||||||
/// This can only be called for read-only queries, see [`par_iter_mut`] for write-queries.
|
/// This can only be called for read-only queries, see [`par_iter_mut`] for write-queries.
|
||||||
///
|
///
|
||||||
/// [`par_iter_mut`]: Self::par_iter_mut
|
/// [`par_iter_mut`]: Self::par_iter_mut
|
||||||
|
/// [`World`]: crate::world::World
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn par_iter(&self) -> QueryParIter<'_, '_, Q::ReadOnly, F::ReadOnly> {
|
pub fn par_iter(&self) -> QueryParIter<'_, '_, Q::ReadOnly, F::ReadOnly> {
|
||||||
QueryParIter {
|
QueryParIter {
|
||||||
@ -739,6 +753,7 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
|
|||||||
/// This can only be called for mutable queries, see [`par_iter`] for read-only-queries.
|
/// This can only be called for mutable queries, see [`par_iter`] for read-only-queries.
|
||||||
///
|
///
|
||||||
/// [`par_iter`]: Self::par_iter
|
/// [`par_iter`]: Self::par_iter
|
||||||
|
/// [`World`]: crate::world::World
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn par_iter_mut(&mut self) -> QueryParIter<'_, '_, Q, F> {
|
pub fn par_iter_mut(&mut self) -> QueryParIter<'_, '_, Q, F> {
|
||||||
QueryParIter {
|
QueryParIter {
|
||||||
@ -812,8 +827,12 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
|
|||||||
) -> Result<[ROQueryItem<'_, Q>; N], QueryEntityError> {
|
) -> Result<[ROQueryItem<'_, Q>; N], QueryEntityError> {
|
||||||
// SAFETY: it is the scheduler's responsibility to ensure that `Query` is never handed out on the wrong `World`.
|
// SAFETY: it is the scheduler's responsibility to ensure that `Query` is never handed out on the wrong `World`.
|
||||||
unsafe {
|
unsafe {
|
||||||
self.state
|
self.state.get_many_read_only_manual(
|
||||||
.get_many_read_only_manual(self.world, entities, self.last_run, self.this_run)
|
self.world.unsafe_world(),
|
||||||
|
entities,
|
||||||
|
self.last_run,
|
||||||
|
self.this_run,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1044,9 +1063,9 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
|
|||||||
.archetype_component_access
|
.archetype_component_access
|
||||||
.has_read(archetype_component)
|
.has_read(archetype_component)
|
||||||
{
|
{
|
||||||
entity_ref
|
// SAFETY: `self.world` must have access to the component `T` for this entity,
|
||||||
.get::<T>()
|
// since it was registered in `self.state`'s archetype component access set.
|
||||||
.ok_or(QueryComponentError::MissingComponent)
|
unsafe { entity_ref.get::<T>() }.ok_or(QueryComponentError::MissingComponent)
|
||||||
} else {
|
} else {
|
||||||
Err(QueryComponentError::MissingReadAccess)
|
Err(QueryComponentError::MissingReadAccess)
|
||||||
}
|
}
|
||||||
@ -1112,7 +1131,6 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
|
|||||||
}
|
}
|
||||||
let world = self.world;
|
let world = self.world;
|
||||||
let entity_ref = world
|
let entity_ref = world
|
||||||
.as_unsafe_world_cell_migration_internal()
|
|
||||||
.get_entity(entity)
|
.get_entity(entity)
|
||||||
.ok_or(QueryComponentError::NoSuchEntity)?;
|
.ok_or(QueryComponentError::NoSuchEntity)?;
|
||||||
let component_id = world
|
let component_id = world
|
||||||
@ -1301,8 +1319,12 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
|
|||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.state
|
self.state.is_empty(
|
||||||
.is_empty(self.world, self.last_run, self.this_run)
|
// SAFETY: `QueryState::is_empty` does not access world data.
|
||||||
|
unsafe { self.world.unsafe_world() },
|
||||||
|
self.last_run,
|
||||||
|
self.this_run,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if the given [`Entity`] matches the query.
|
/// Returns `true` if the given [`Entity`] matches the query.
|
||||||
|
|||||||
@ -198,16 +198,10 @@ unsafe impl<Q: WorldQuery + 'static, F: ReadOnlyWorldQuery + 'static> SystemPara
|
|||||||
world: UnsafeWorldCell<'w>,
|
world: UnsafeWorldCell<'w>,
|
||||||
change_tick: Tick,
|
change_tick: Tick,
|
||||||
) -> Self::Item<'w, 's> {
|
) -> Self::Item<'w, 's> {
|
||||||
Query::new(
|
|
||||||
// SAFETY: We have registered all of the query's world accesses,
|
// SAFETY: We have registered all of the query's world accesses,
|
||||||
// so the caller ensures that `world` has permission to access any
|
// so the caller ensures that `world` has permission to access any
|
||||||
// world data that the query needs.
|
// world data that the query needs.
|
||||||
world.unsafe_world(),
|
Query::new(world, state, system_meta.last_run, change_tick, false)
|
||||||
state,
|
|
||||||
system_meta.last_run,
|
|
||||||
change_tick,
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -122,14 +122,6 @@ impl World {
|
|||||||
UnsafeWorldCell::new_readonly(self)
|
UnsafeWorldCell::new_readonly(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new [`UnsafeWorldCell`] with read+write access from a [&World](World).
|
|
||||||
/// This is only a temporary measure until every `&World` that is semantically a [`UnsafeWorldCell`]
|
|
||||||
/// has been replaced.
|
|
||||||
#[inline]
|
|
||||||
pub(crate) fn as_unsafe_world_cell_migration_internal(&self) -> UnsafeWorldCell<'_> {
|
|
||||||
UnsafeWorldCell::new_readonly(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Retrieves this world's [Entities] collection
|
/// Retrieves this world's [Entities] collection
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn entities(&self) -> &Entities {
|
pub fn entities(&self) -> &Entities {
|
||||||
|
|||||||
@ -443,7 +443,9 @@ impl<'w> UnsafeWorldCell<'w> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Some(MutUntyped {
|
Some(MutUntyped {
|
||||||
// SAFETY: This function has exclusive access to the world so nothing aliases `ptr`.
|
// SAFETY:
|
||||||
|
// - caller ensures that `self` has permission to access the resource
|
||||||
|
// - caller ensures that the resource is unaliased
|
||||||
value: unsafe { ptr.assert_unique() },
|
value: unsafe { ptr.assert_unique() },
|
||||||
ticks,
|
ticks,
|
||||||
})
|
})
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user