mirror of
https://github.com/bevyengine/bevy.git
synced 2026-05-06 06:06:42 -04:00
Streaming iteration for non-IterQueryData (#23218)
# Objective Follow-up to #21557 Support streaming iteration (a.k.a. lending iteration) for `QueryIter` and `QuerySortedIter` so that it's possible to iterate `Query<Parent<&mut T>>`. Double-check that all the `IterQueryData` bounds are correct and that the safety comments are correct. A few were not! ## Solution Offer a `fetch_next` method on `QueryIter` and `QuerySortedIter` that borrows the entire iterator to prevent aliasing, similar to `QueryManyIter::QueryManyIter`. Offer a `Query::iter_inner` method to produce `QueryIter` even when it is not an `Iterator`. We cannot rely on `IntoIterator` in that case, and Clippy objects to an inherent method called `into_iter()` that is not the standard trait method. This supersedes the existing `iter_inner` method that only worked on `ReadOnlyQueryData`. Add a missing `IterQueryData` bound to `iter_combinations_mut`. It yields multiple entities concurrently, so is never sound to use with non-`IterQueryData`. I think the reason I missed this originally is that it already has a `fetch_next` method and conditional `Iterator` impl. But even `fetch_next` yields multiple entities at once for `QueryCombinationIter`! Add a `ContiguousQueryData: IterQueryData` supertrait bound. `QueryContiguousIter` also yields multiple entities concurrently, so it does not make sense on non-iterable data. This was not actually unsound, though, as `QueryContiguousIter` does not call `fetch`. Finally, update some missing or incorrect safety comments. ### Verify bounds on the other iterator types To verify I didn't miss any bounds on iterator types, here is a list of every `Query*Iter` type, and whether they support non-`IterQueryData`: | Type | Supports non-`Iter`? | | --- | --- | |`CombinationIter`|No, added missing bound| |`ContiguousIter`|No, added missing bound| |`Iter`|Yes, added support| |`ManyIter`|Yes, existing support| |`ManyUniqueIter`|No, and existing bound*| |`ParIter`|No, and existing bound| |`ParManyIter`|No, and existing bound| |`ParManyUniqueIter`|No, and existing bound| |`SortedIter`|Yes, added support| |`SortedManyIter`|Yes, existing support| `Iter` and `SortedIter` were changed in this PR to support streaming iteration for all `QueryData`, while only implementing `Iterator` for `IterQueryData`. `ManyIter` and `SortedManyIter` already had streaming iteration, and only implement `Iterator` with a stricter `ReadOnlyQueryData` bound, since they may yield the same entity multiple times. `ManyUniqueIter` could theoretically be used with non-`IterQueryData`... but if you need to do streaming iteration anyway then you can call `iter_many_mut()` instead of `iter_many_unique_mut()`. `CombinationIter`, `ContiguousIter`, and the `Par*Iter` types are all fundamentally about accessing multiple entities concurrently, and should always require `IterQueryData`. `CombinationIter` and `ContiguousIter` did not have `IterQueryData` bounds, so fix that! ## Showcase This is cheating a bit because we don't yet have `Parent<&mut T>`, but once we do it would look like: ```rust fn system(query: Query<Parent<&mut Component>>) { let mut iter = query.iter_mut(); while let Some(mut parent_component) = iter.fetch_next() { // Use `parent_component` here } } ```
This commit is contained in:
@@ -406,7 +406,7 @@ pub unsafe trait QueryData: WorldQuery {
|
||||
label = "invalid contiguous `Query` data",
|
||||
note = "if `{Self}` is a custom query type, using `QueryData` derive macro, ensure that the `#[query_data(contiguous(target))]` attribute is added"
|
||||
)]
|
||||
pub trait ContiguousQueryData: ArchetypeQueryData {
|
||||
pub trait ContiguousQueryData: ArchetypeQueryData + IterQueryData {
|
||||
/// Item returned by [`ContiguousQueryData::fetch_contiguous`].
|
||||
/// Represents a contiguous chunk of memory.
|
||||
type Contiguous<'w, 's>;
|
||||
@@ -434,6 +434,9 @@ pub trait ContiguousQueryData: ArchetypeQueryData {
|
||||
/// This is how methods like [`Iterator::collect`] work.
|
||||
/// It is therefore unsound to offer an [`Iterator`] for a [`QueryData`] for which only one instance may be alive concurrently.
|
||||
///
|
||||
/// To iterate over a [`QueryData`] that does not implement [`IterQueryData`],
|
||||
/// use the [`QueryIter::fetch_next()`](crate::query::QueryIter::fetch_next) method.
|
||||
///
|
||||
/// For `QueryData` that implement this trait, [`QueryData::fetch`] may be called for one entity while an item is still alive for a different entity.
|
||||
///
|
||||
/// All [`SingleEntityQueryData`] types are [`IterQueryData`].
|
||||
|
||||
@@ -128,6 +128,44 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIter<'w, 's, D, F> {
|
||||
cursor: self.cursor.reborrow(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the next result from the query.
|
||||
///
|
||||
/// If the [`QueryData`] does not implement [`IterQueryData`],
|
||||
/// then it is not sound to yield multiple items concurrently
|
||||
/// and the resulting [`QueryIter`] will not implement [`Iterator`].
|
||||
/// In that case, this method can be used to iterate over the items
|
||||
/// while ensuring only one is alive at a time.
|
||||
///
|
||||
/// Most queries do implement [`IterQueryData`],
|
||||
/// and and can use the ordinary [`Iterator::next`]
|
||||
/// method or a `for` loop.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use bevy_ecs::prelude::*;
|
||||
/// # #[derive(Component)]
|
||||
/// # struct C;
|
||||
/// fn system(mut query: Query<&mut C>) {
|
||||
/// let mut iter = query.iter_mut();
|
||||
/// while let Some(mut c) = iter.fetch_next() {
|
||||
/// //
|
||||
/// }
|
||||
/// }
|
||||
/// # bevy_ecs::system::assert_is_system(system);
|
||||
/// ```
|
||||
pub fn fetch_next(&mut self) -> Option<D::Item<'_, 's>> {
|
||||
// SAFETY:
|
||||
// - `tables` and `archetypes` belong to the same world that the cursor was initialized for.
|
||||
// - `query_state` is the state that was passed to `QueryIterationCursor::init`.
|
||||
// - `self` is mutably borrowed, so there are no other items alive for any entity.
|
||||
unsafe {
|
||||
self.cursor
|
||||
.next(self.tables, self.archetypes, self.query_state)
|
||||
.map(D::shrink)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'w, 's, D: IterQueryData, F: QueryFilter> QueryIter<'w, 's, D, F> {
|
||||
@@ -428,6 +466,13 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIter<'w, 's, D, F> {
|
||||
///
|
||||
/// The sort is not cached across system runs.
|
||||
///
|
||||
/// If the [`QueryData`] does not implement [`IterQueryData`],
|
||||
/// then it is not sound to yield multiple items concurrently
|
||||
/// and the resulting [`QuerySortedIter`] will not implement [`Iterator`].
|
||||
/// To iterate over the items in that case,
|
||||
/// use the [`QuerySortedIter::fetch_next()`](crate::query::QuerySortedIter::fetch_next) method,
|
||||
/// which ensures only one item is alive at a time.
|
||||
///
|
||||
/// [allowed transmutes]: crate::system::Query#allowed-transmutes
|
||||
///
|
||||
/// # Panics
|
||||
@@ -559,6 +604,13 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIter<'w, 's, D, F> {
|
||||
///
|
||||
/// The sort is not cached across system runs.
|
||||
///
|
||||
/// If the [`QueryData`] does not implement [`IterQueryData`],
|
||||
/// then it is not sound to yield multiple items concurrently
|
||||
/// and the resulting [`QuerySortedIter`] will not implement [`Iterator`].
|
||||
/// To iterate over the items in that case,
|
||||
/// use the [`QuerySortedIter::fetch_next()`](crate::query::QuerySortedIter::fetch_next) method,
|
||||
/// which ensures only one item is alive at a time.
|
||||
///
|
||||
/// [allowed transmutes]: crate::system::Query#allowed-transmutes
|
||||
///
|
||||
/// # Panics
|
||||
@@ -620,6 +672,13 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIter<'w, 's, D, F> {
|
||||
///
|
||||
/// The sort is not cached across system runs.
|
||||
///
|
||||
/// If the [`QueryData`] does not implement [`IterQueryData`],
|
||||
/// then it is not sound to yield multiple items concurrently
|
||||
/// and the resulting [`QuerySortedIter`] will not implement [`Iterator`].
|
||||
/// To iterate over the items in that case,
|
||||
/// use the [`QuerySortedIter::fetch_next()`](crate::query::QuerySortedIter::fetch_next) method,
|
||||
/// which ensures only one item is alive at a time.
|
||||
///
|
||||
/// [allowed transmutes]: crate::system::Query#allowed-transmutes
|
||||
///
|
||||
/// # Panics
|
||||
@@ -688,6 +747,13 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIter<'w, 's, D, F> {
|
||||
///
|
||||
/// The sort is not cached across system runs.
|
||||
///
|
||||
/// If the [`QueryData`] does not implement [`IterQueryData`],
|
||||
/// then it is not sound to yield multiple items concurrently
|
||||
/// and the resulting [`QuerySortedIter`] will not implement [`Iterator`].
|
||||
/// To iterate over the items in that case,
|
||||
/// use the [`QuerySortedIter::fetch_next()`](crate::query::QuerySortedIter::fetch_next) method,
|
||||
/// which ensures only one item is alive at a time.
|
||||
///
|
||||
/// [allowed transmutes]: crate::system::Query#allowed-transmutes
|
||||
///
|
||||
/// # Panics
|
||||
@@ -724,6 +790,13 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIter<'w, 's, D, F> {
|
||||
///
|
||||
/// The sort is not cached across system runs.
|
||||
///
|
||||
/// If the [`QueryData`] does not implement [`IterQueryData`],
|
||||
/// then it is not sound to yield multiple items concurrently
|
||||
/// and the resulting [`QuerySortedIter`] will not implement [`Iterator`].
|
||||
/// To iterate over the items in that case,
|
||||
/// use the [`QuerySortedIter::fetch_next()`](crate::query::QuerySortedIter::fetch_next) method,
|
||||
/// which ensures only one item is alive at a time.
|
||||
///
|
||||
/// [allowed transmutes]: crate::system::Query#allowed-transmutes
|
||||
///
|
||||
/// # Panics
|
||||
@@ -821,6 +894,13 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIter<'w, 's, D, F> {
|
||||
///
|
||||
/// The sort is not cached across system runs.
|
||||
///
|
||||
/// If the [`QueryData`] does not implement [`IterQueryData`],
|
||||
/// then it is not sound to yield multiple items concurrently
|
||||
/// and the resulting [`QuerySortedIter`] will not implement [`Iterator`].
|
||||
/// To iterate over the items in that case,
|
||||
/// use the [`QuerySortedIter::fetch_next()`](crate::query::QuerySortedIter::fetch_next) method,
|
||||
/// which ensures only one item is alive at a time.
|
||||
///
|
||||
/// [allowed transmutes]: crate::system::Query#allowed-transmutes
|
||||
///
|
||||
/// # Panics
|
||||
@@ -860,6 +940,13 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIter<'w, 's, D, F> {
|
||||
///
|
||||
/// The sort is not cached across system runs.
|
||||
///
|
||||
/// If the [`QueryData`] does not implement [`IterQueryData`],
|
||||
/// then it is not sound to yield multiple items concurrently
|
||||
/// and the resulting [`QuerySortedIter`] will not implement [`Iterator`].
|
||||
/// To iterate over the items in that case,
|
||||
/// use the [`QuerySortedIter::fetch_next()`](crate::query::QuerySortedIter::fetch_next) method,
|
||||
/// which ensures only one item is alive at a time.
|
||||
///
|
||||
/// [allowed transmutes]: crate::system::Query#allowed-transmutes
|
||||
///
|
||||
/// # Panics
|
||||
@@ -894,6 +981,13 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIter<'w, 's, D, F> {
|
||||
///
|
||||
/// The sort is not cached across system runs.
|
||||
///
|
||||
/// If the [`QueryData`] does not implement [`IterQueryData`],
|
||||
/// then it is not sound to yield multiple items concurrently
|
||||
/// and the resulting [`QuerySortedIter`] will not implement [`Iterator`].
|
||||
/// To iterate over the items in that case,
|
||||
/// use the [`QuerySortedIter::fetch_next()`](crate::query::QuerySortedIter::fetch_next) method,
|
||||
/// which ensures only one item is alive at a time.
|
||||
///
|
||||
/// [allowed transmutes]: crate::system::Query#allowed-transmutes
|
||||
///
|
||||
/// # Panics
|
||||
@@ -956,8 +1050,9 @@ impl<'w, 's, D: IterQueryData, F: QueryFilter> Iterator for QueryIter<'w, 's, D,
|
||||
#[inline(always)]
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
// SAFETY:
|
||||
// `tables` and `archetypes` belong to the same world that the cursor was initialized for.
|
||||
// `query_state` is the state that was passed to `QueryIterationCursor::init`.
|
||||
// - `tables` and `archetypes` belong to the same world that the cursor was initialized for.
|
||||
// - `query_state` is the state that was passed to `QueryIterationCursor::init`.
|
||||
// - `D: IterQueryData`
|
||||
unsafe {
|
||||
self.cursor
|
||||
.next(self.tables, self.archetypes, self.query_state)
|
||||
@@ -1170,13 +1265,77 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the next result from the query.
|
||||
///
|
||||
/// If the [`QueryData`] does not implement [`IterQueryData`],
|
||||
/// then it is not sound to yield multiple items concurrently
|
||||
/// and the resulting [`QuerySortedIter`] will not implement [`Iterator`].
|
||||
/// In that case, this method can be used to iterate over the items
|
||||
/// while ensuring only one is alive at a time.
|
||||
///
|
||||
/// Most queries do implement [`IterQueryData`],
|
||||
/// and and can use the ordinary [`Iterator::next`]
|
||||
/// method or a `for` loop.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use bevy_ecs::prelude::*;
|
||||
/// # #[derive(Component, Ord, PartialOrd, Eq, PartialEq)]
|
||||
/// # struct C;
|
||||
/// fn system(mut query: Query<&mut C>) {
|
||||
/// let mut iter = query.iter_mut().sort::<&C>();
|
||||
/// while let Some(mut c) = iter.fetch_next() {
|
||||
/// //
|
||||
/// }
|
||||
/// }
|
||||
/// # bevy_ecs::system::assert_is_system(system);
|
||||
/// ```
|
||||
pub fn fetch_next(&mut self) -> Option<D::Item<'_, 's>> {
|
||||
while let Some(entity) = self.entity_iter.next() {
|
||||
// SAFETY:
|
||||
// - `entity` is passed from `entity_iter` the first time.
|
||||
// - `self` is mutably borrowed, so there are no other items alive for any entity.
|
||||
if let Some(item) = unsafe { self.fetch_next_impl(entity) } {
|
||||
return Some(D::shrink(item));
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Get the next result from the back of the query.
|
||||
///
|
||||
/// If the [`QueryData`] does not implement [`IterQueryData`],
|
||||
/// then it is not sound to yield multiple items concurrently
|
||||
/// and the resulting [`QuerySortedIter`] will not implement [`Iterator`].
|
||||
/// In that case, this method can be used to iterate over the items
|
||||
/// while ensuring only one is alive at a time.
|
||||
///
|
||||
/// Most queries do implement [`IterQueryData`],
|
||||
/// and and can use the ordinary [`Iterator::next`]
|
||||
/// method or a `for` loop.
|
||||
pub fn fetch_next_back(&mut self) -> Option<D::Item<'_, 's>>
|
||||
where
|
||||
I: DoubleEndedIterator,
|
||||
{
|
||||
while let Some(entity) = self.entity_iter.next_back() {
|
||||
// SAFETY:
|
||||
// - `entity` is passed from `entity_iter` the first time.
|
||||
// - `self` is mutably borrowed, so there are no other items alive for any entity.
|
||||
if let Some(item) = unsafe { self.fetch_next_impl(entity) } {
|
||||
return Some(D::shrink(item));
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// - `entity` must stem from `self.entity_iter`
|
||||
/// - If `Self` does not impl `ReadOnlyQueryData`, then there must not be any other `Item`s alive for the current entity
|
||||
/// - If `Self` does not impl `IterQueryData`, then there must not be any other `Item`s alive for *any* entity
|
||||
/// - If `D` does not impl `ReadOnlyQueryData`, then there must not be any other `Item`s alive for the current entity
|
||||
/// - If `D` does not impl `IterQueryData`, then there must not be any other `Item`s alive for *any* entity
|
||||
#[inline(always)]
|
||||
unsafe fn fetch_next(&mut self, entity: Entity) -> Option<D::Item<'w, 's>> {
|
||||
unsafe fn fetch_next_impl(&mut self, entity: Entity) -> Option<D::Item<'w, 's>> {
|
||||
let (location, archetype, table);
|
||||
// SAFETY:
|
||||
// `tables` and `archetypes` belong to the same world that the [`QueryIter`]
|
||||
@@ -1229,7 +1388,7 @@ where
|
||||
// SAFETY:
|
||||
// - `entity` is passed from `entity_iter` the first time.
|
||||
// - `D: IterQueryData`
|
||||
if let Some(item) = unsafe { self.fetch_next(entity) } {
|
||||
if let Some(item) = unsafe { self.fetch_next_impl(entity) } {
|
||||
return Some(item);
|
||||
}
|
||||
}
|
||||
@@ -1255,7 +1414,7 @@ where
|
||||
// SAFETY:
|
||||
// - `entity` is passed from `entity_iter` the first time.
|
||||
// - `D: IterQueryData`
|
||||
if let Some(item) = unsafe { self.fetch_next(entity) } {
|
||||
if let Some(item) = unsafe { self.fetch_next_impl(entity) } {
|
||||
return Some(item);
|
||||
}
|
||||
}
|
||||
@@ -1345,8 +1504,8 @@ impl<'w, 's, D: QueryData, F: QueryFilter, I: Iterator<Item: EntityEquivalent>>
|
||||
/// # Safety
|
||||
///
|
||||
/// - All arguments must stem from the same valid `QueryManyIter`.
|
||||
/// - If `Self` does not impl `ReadOnlyQueryData`, then there must not be any other `Item`s alive for the current entity
|
||||
/// - If `Self` does not impl `IterQueryData`, then there must not be any other `Item`s alive for *any* entity
|
||||
/// - If `D` does not impl `ReadOnlyQueryData`, then there must not be any other `Item`s alive for the current entity
|
||||
/// - If `D` does not impl `IterQueryData`, then there must not be any other `Item`s alive for *any* entity
|
||||
#[inline(always)]
|
||||
unsafe fn fetch_next_aliased_unchecked(
|
||||
entity_iter: impl Iterator<Item: EntityEquivalent>,
|
||||
@@ -1408,7 +1567,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter, I: Iterator<Item: EntityEquivalent>>
|
||||
None
|
||||
}
|
||||
|
||||
/// Get next result from the query
|
||||
/// Get the next result from the query
|
||||
#[inline(always)]
|
||||
pub fn fetch_next(&mut self) -> Option<D::Item<'_, 's>> {
|
||||
// SAFETY:
|
||||
@@ -1949,7 +2108,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter, I: Iterator<Item: EntityEquivalent>>
|
||||
impl<'w, 's, D: QueryData, F: QueryFilter, I: DoubleEndedIterator<Item: EntityEquivalent>>
|
||||
QueryManyIter<'w, 's, D, F, I>
|
||||
{
|
||||
/// Get next result from the back of the query
|
||||
/// Get the next result from the back of the query
|
||||
#[inline(always)]
|
||||
pub fn fetch_next_back(&mut self) -> Option<D::Item<'_, 's>> {
|
||||
// SAFETY:
|
||||
@@ -2181,8 +2340,8 @@ impl<'w, 's, D: QueryData, F: QueryFilter, I: Iterator<Item = Entity>>
|
||||
/// # Safety
|
||||
///
|
||||
/// - `entity` must stem from `self.entity_iter`
|
||||
/// - If `Self` does not impl `ReadOnlyQueryData`, then there must not be any other `Item`s alive for the current entity
|
||||
/// - If `Self` does not impl `IterQueryData`, then there must not be any other `Item`s alive for *any* entity
|
||||
/// - If `D` does not impl `ReadOnlyQueryData`, then there must not be any other `Item`s alive for the current entity
|
||||
/// - If `D` does not impl `IterQueryData`, then there must not be any other `Item`s alive for *any* entity
|
||||
#[inline(always)]
|
||||
unsafe fn fetch_next_aliased_unchecked(&mut self, entity: Entity) -> Option<D::Item<'w, 's>> {
|
||||
let (location, archetype, table);
|
||||
@@ -2223,7 +2382,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter, I: Iterator<Item = Entity>>
|
||||
}
|
||||
}
|
||||
|
||||
/// Get next result from the query
|
||||
/// Get the next result from the query
|
||||
#[inline(always)]
|
||||
pub fn fetch_next(&mut self) -> Option<D::Item<'_, 's>> {
|
||||
while let Some(entity) = self.entity_iter.next() {
|
||||
@@ -2245,7 +2404,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter, I: Iterator<Item = Entity>>
|
||||
impl<'w, 's, D: QueryData, F: QueryFilter, I: DoubleEndedIterator<Item = Entity>>
|
||||
QuerySortedManyIter<'w, 's, D, F, I>
|
||||
{
|
||||
/// Get next result from the query
|
||||
/// Get the next result from the query
|
||||
#[inline(always)]
|
||||
pub fn fetch_next_back(&mut self) -> Option<D::Item<'_, 's>> {
|
||||
while let Some(entity) = self.entity_iter.next_back() {
|
||||
@@ -2386,14 +2545,16 @@ impl<'w, 's, D: QueryData, F: QueryFilter, I: Iterator<Item = Entity>> Debug
|
||||
/// [`Query`]: crate::system::Query
|
||||
/// [`Query::iter_combinations`]: crate::system::Query::iter_combinations
|
||||
/// [`Query::iter_combinations_mut`]: crate::system::Query::iter_combinations_mut
|
||||
pub struct QueryCombinationIter<'w, 's, D: QueryData, F: QueryFilter, const K: usize> {
|
||||
pub struct QueryCombinationIter<'w, 's, D: IterQueryData, F: QueryFilter, const K: usize> {
|
||||
tables: &'w Tables,
|
||||
archetypes: &'w Archetypes,
|
||||
query_state: &'s QueryState<D, F>,
|
||||
cursors: [QueryIterationCursor<'w, 's, D, F>; K],
|
||||
}
|
||||
|
||||
impl<'w, 's, D: QueryData, F: QueryFilter, const K: usize> QueryCombinationIter<'w, 's, D, F, K> {
|
||||
impl<'w, 's, D: IterQueryData, F: QueryFilter, const K: usize>
|
||||
QueryCombinationIter<'w, 's, D, F, K>
|
||||
{
|
||||
/// # 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`.
|
||||
@@ -2552,7 +2713,7 @@ impl<'w, 's, D: ReadOnlyQueryData, F: QueryFilter, const K: usize> FusedIterator
|
||||
{
|
||||
}
|
||||
|
||||
impl<'w, 's, D: QueryData, F: QueryFilter, const K: usize> Debug
|
||||
impl<'w, 's, D: IterQueryData, F: QueryFilter, const K: usize> Debug
|
||||
for QueryCombinationIter<'w, 's, D, F, K>
|
||||
{
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
@@ -2647,7 +2808,10 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIterationCursor<'w, 's, D, F> {
|
||||
/// The result of `next` and any previous calls to `peek_last` with this row must have been
|
||||
/// dropped to prevent aliasing mutable references.
|
||||
#[inline]
|
||||
unsafe fn peek_last(&mut self, query_state: &'s QueryState<D, F>) -> Option<D::Item<'w, 's>> {
|
||||
unsafe fn peek_last(&mut self, query_state: &'s QueryState<D, F>) -> Option<D::Item<'w, 's>>
|
||||
where
|
||||
D: IterQueryData,
|
||||
{
|
||||
if self.current_row > 0 {
|
||||
let index = self.current_row - 1;
|
||||
if self.is_dense {
|
||||
@@ -2656,6 +2820,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIterationCursor<'w, 's, D, F> {
|
||||
// SAFETY:
|
||||
// - `set_table` must have been called previously either in `next` or before it.
|
||||
// - `*entity` and `index` are in the current table.
|
||||
// - `D: IterQueryData`
|
||||
unsafe {
|
||||
D::fetch(
|
||||
&query_state.fetch_state,
|
||||
@@ -2672,6 +2837,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIterationCursor<'w, 's, D, F> {
|
||||
// SAFETY:
|
||||
// - `set_archetype` must have been called previously either in `next` or before it.
|
||||
// - `archetype_entity.id()` and `archetype_entity.table_row()` are in the current archetype.
|
||||
// - `D: IterQueryData`
|
||||
unsafe {
|
||||
D::fetch(
|
||||
&query_state.fetch_state,
|
||||
@@ -2707,9 +2873,11 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIterationCursor<'w, 's, D, F> {
|
||||
// QueryState::par_fold_init_unchecked_manual, QueryState::par_many_fold_init_unchecked_manual,
|
||||
// QueryState::par_many_unique_fold_init_unchecked_manual, QueryContiguousIter::next
|
||||
/// # Safety
|
||||
/// `tables` and `archetypes` must belong to the same world that the [`QueryIterationCursor`]
|
||||
/// was initialized for.
|
||||
/// `query_state` must be the same [`QueryState`] that was passed to `init` or `init_empty`.
|
||||
/// - `tables` and `archetypes` must belong to the same world that the [`QueryIterationCursor`]
|
||||
/// was initialized for.
|
||||
/// - `query_state` must be the same [`QueryState`] that was passed to `init` or `init_empty`.
|
||||
/// - If `D` does not impl `ReadOnlyQueryData`, then there must not be any other `Item`s alive for the current entity
|
||||
/// - If `D` does not impl `IterQueryData`, then there must not be any other `Item`s alive for *any* entity
|
||||
#[inline(always)]
|
||||
unsafe fn next(
|
||||
&mut self,
|
||||
@@ -2756,6 +2924,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIterationCursor<'w, 's, D, F> {
|
||||
// - `current_row` must be a table row in range of the current table,
|
||||
// because if it was not, then the above would have been executed.
|
||||
// - fetch is only called once for each `entity`.
|
||||
// - caller ensures no conflicting `Item`s are alive
|
||||
let item =
|
||||
unsafe { D::fetch(&query_state.fetch_state, &mut self.fetch, *entity, row) };
|
||||
if let Some(item) = item {
|
||||
@@ -2814,6 +2983,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> QueryIterationCursor<'w, 's, D, F> {
|
||||
// - `current_row` must be an archetype index row in range of the current archetype,
|
||||
// because if it was not, then the if above would have been executed.
|
||||
// - fetch is only called once for each `archetype_entity`.
|
||||
// - caller ensures no conflicting `Item`s are alive
|
||||
let item = unsafe {
|
||||
D::fetch(
|
||||
&query_state.fetch_state,
|
||||
|
||||
@@ -1174,7 +1174,7 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
/// consider using [`Self::update_archetypes`] followed by multiple [`Self::iter_manual`] calls.
|
||||
#[inline]
|
||||
pub fn iter<'w, 's>(&'s mut self, world: &'w World) -> QueryIter<'w, 's, D::ReadOnly, F> {
|
||||
self.query(world).into_iter()
|
||||
self.query(world).iter_inner()
|
||||
}
|
||||
|
||||
/// Returns an [`Iterator`] over the query results for the given [`World`].
|
||||
@@ -1182,11 +1182,8 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
/// This iterator is always guaranteed to return results from each matching entity once and only once.
|
||||
/// Iteration order is not guaranteed.
|
||||
#[inline]
|
||||
pub fn iter_mut<'w, 's>(&'s mut self, world: &'w mut World) -> QueryIter<'w, 's, D, F>
|
||||
where
|
||||
D: IterQueryData,
|
||||
{
|
||||
self.query_mut(world).into_iter()
|
||||
pub fn iter_mut<'w, 's>(&'s mut self, world: &'w mut World) -> QueryIter<'w, 's, D, F> {
|
||||
self.query_mut(world).iter_inner()
|
||||
}
|
||||
|
||||
/// Returns an [`Iterator`] over the query results for the given [`World`] without updating the query's archetypes.
|
||||
@@ -1254,7 +1251,10 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
pub fn iter_combinations_mut<'w, 's, const K: usize>(
|
||||
&'s mut self,
|
||||
world: &'w mut World,
|
||||
) -> QueryCombinationIter<'w, 's, D, F, K> {
|
||||
) -> QueryCombinationIter<'w, 's, D, F, K>
|
||||
where
|
||||
D: IterQueryData,
|
||||
{
|
||||
self.query_mut(world).iter_combinations_inner()
|
||||
}
|
||||
|
||||
@@ -1383,12 +1383,9 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
pub unsafe fn iter_unchecked<'w, 's>(
|
||||
&'s mut self,
|
||||
world: UnsafeWorldCell<'w>,
|
||||
) -> QueryIter<'w, 's, D, F>
|
||||
where
|
||||
D: IterQueryData,
|
||||
{
|
||||
) -> QueryIter<'w, 's, D, F> {
|
||||
// SAFETY: Upheld by caller
|
||||
unsafe { self.query_unchecked(world) }.into_iter()
|
||||
unsafe { self.query_unchecked(world) }.iter_inner()
|
||||
}
|
||||
|
||||
/// Returns an [`Iterator`] over all possible combinations of `K` query results for the
|
||||
@@ -1406,7 +1403,10 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> {
|
||||
pub unsafe fn iter_combinations_unchecked<'w, 's, const K: usize>(
|
||||
&'s mut self,
|
||||
world: UnsafeWorldCell<'w>,
|
||||
) -> QueryCombinationIter<'w, 's, D, F, K> {
|
||||
) -> QueryCombinationIter<'w, 's, D, F, K>
|
||||
where
|
||||
D: IterQueryData,
|
||||
{
|
||||
// SAFETY: Upheld by caller
|
||||
unsafe { self.query_unchecked(world) }.iter_combinations_inner()
|
||||
}
|
||||
|
||||
@@ -684,6 +684,13 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
||||
/// This iterator is always guaranteed to return results from each matching entity once and only once.
|
||||
/// Iteration order is not guaranteed.
|
||||
///
|
||||
/// If the [`QueryData`] does not implement [`IterQueryData`],
|
||||
/// then it is not sound to yield multiple items concurrently
|
||||
/// and the resulting [`QueryIter`] will not implement [`Iterator`].
|
||||
/// To iterate over the items in that case,
|
||||
/// use the [`QueryIter::fetch_next()`](crate::query::QueryIter::fetch_next) method,
|
||||
/// which ensures only one item is alive at a time.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// Here, the `gravity_system` updates the `Velocity` component of every entity that contains it:
|
||||
@@ -706,11 +713,47 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
||||
///
|
||||
/// [`iter`](Self::iter) for read-only query items.
|
||||
#[inline]
|
||||
pub fn iter_mut(&mut self) -> QueryIter<'_, 's, D, F>
|
||||
where
|
||||
D: IterQueryData,
|
||||
{
|
||||
self.reborrow().into_iter()
|
||||
pub fn iter_mut(&mut self) -> QueryIter<'_, 's, D, F> {
|
||||
self.reborrow().iter_inner()
|
||||
}
|
||||
|
||||
/// Returns an [`Iterator`] over the query items, with the actual "inner" world lifetime.
|
||||
///
|
||||
/// This iterator is always guaranteed to return results from each matching entity once and only once.
|
||||
/// Iteration order is not guaranteed.
|
||||
///
|
||||
/// If the [`QueryData`] does not implement [`IterQueryData`],
|
||||
/// then it is not sound to yield multiple items concurrently
|
||||
/// and the resulting [`QueryIter`] will not implement [`Iterator`].
|
||||
/// To iterate over the items in that case,
|
||||
/// use the [`QueryIter::fetch_next()`](crate::query::QueryIter::fetch_next) method,
|
||||
/// which ensures only one item is alive at a time.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// Here, the `report_names_system` iterates over the `Player` component of every entity
|
||||
/// that contains it:
|
||||
///
|
||||
/// ```
|
||||
/// # use bevy_ecs::prelude::*;
|
||||
/// #
|
||||
/// # #[derive(Component)]
|
||||
/// # struct Player { name: String }
|
||||
/// #
|
||||
/// fn report_names_system(query: Query<&Player>) {
|
||||
/// for player in &query {
|
||||
/// println!("Say hello to {}!", player.name);
|
||||
/// }
|
||||
/// }
|
||||
/// # bevy_ecs::system::assert_is_system(report_names_system);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn iter_inner(self) -> QueryIter<'w, 's, D, F> {
|
||||
// SAFETY:
|
||||
// - `self.world` has permission to access the required components.
|
||||
// - We consume the query, so mutable queries cannot alias.
|
||||
// Read-only queries are `Copy`, but may alias themselves.
|
||||
unsafe { QueryIter::new(self.world, self.state, self.last_run, self.this_run) }
|
||||
}
|
||||
|
||||
/// Returns a [`QueryCombinationIter`] over all combinations of `K` read-only query items without repetition.
|
||||
@@ -767,9 +810,10 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
||||
/// - [`iter_combinations`](Self::iter_combinations) for read-only query item combinations.
|
||||
/// - [`iter_combinations_inner`](Self::iter_combinations_inner) for mutable query item combinations with the full `'world` lifetime.
|
||||
#[inline]
|
||||
pub fn iter_combinations_mut<const K: usize>(
|
||||
&mut self,
|
||||
) -> QueryCombinationIter<'_, 's, D, F, K> {
|
||||
pub fn iter_combinations_mut<const K: usize>(&mut self) -> QueryCombinationIter<'_, 's, D, F, K>
|
||||
where
|
||||
D: IterQueryData,
|
||||
{
|
||||
self.reborrow().iter_combinations_inner()
|
||||
}
|
||||
|
||||
@@ -798,7 +842,10 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
||||
/// - [`iter_combinations`](Self::iter_combinations) for read-only query item combinations.
|
||||
/// - [`iter_combinations_mut`](Self::iter_combinations_mut) for mutable query item combinations.
|
||||
#[inline]
|
||||
pub fn iter_combinations_inner<const K: usize>(self) -> QueryCombinationIter<'w, 's, D, F, K> {
|
||||
pub fn iter_combinations_inner<const K: usize>(self) -> QueryCombinationIter<'w, 's, D, F, K>
|
||||
where
|
||||
D: IterQueryData,
|
||||
{
|
||||
// SAFETY: `self.world` has permission to access the required components.
|
||||
unsafe { QueryCombinationIter::new(self.world, self.state, self.last_run, self.this_run) }
|
||||
}
|
||||
@@ -1106,6 +1153,13 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
||||
/// This iterator is always guaranteed to return results from each matching entity once and only once.
|
||||
/// Iteration order is not guaranteed.
|
||||
///
|
||||
/// If the [`QueryData`] does not implement [`IterQueryData`],
|
||||
/// then it is not sound to yield multiple items concurrently
|
||||
/// and the resulting [`QueryIter`] will not implement [`Iterator`].
|
||||
/// To iterate over the items in that case,
|
||||
/// use the [`QueryIter::fetch_next()`](crate::query::QueryIter::fetch_next) method,
|
||||
/// which ensures only one item is alive at a time.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This function makes it possible to violate Rust's aliasing guarantees.
|
||||
@@ -1139,7 +1193,10 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
||||
#[inline]
|
||||
pub unsafe fn iter_combinations_unsafe<const K: usize>(
|
||||
&self,
|
||||
) -> QueryCombinationIter<'_, 's, D, F, K> {
|
||||
) -> QueryCombinationIter<'_, 's, D, F, K>
|
||||
where
|
||||
D: IterQueryData,
|
||||
{
|
||||
// SAFETY: The caller promises that this will not result in multiple mutable references.
|
||||
unsafe { self.reborrow_unsafe() }.iter_combinations_inner()
|
||||
}
|
||||
@@ -2668,11 +2725,7 @@ impl<'w, 's, D: IterQueryData, F: QueryFilter> IntoIterator for Query<'w, 's, D,
|
||||
type IntoIter = QueryIter<'w, 's, D, F>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
// SAFETY:
|
||||
// - `self.world` has permission to access the required components.
|
||||
// - We consume the query, so mutable queries cannot alias.
|
||||
// Read-only queries are `Copy`, but may alias themselves.
|
||||
unsafe { QueryIter::new(self.world, self.state, self.last_run, self.this_run) }
|
||||
self.iter_inner()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2694,36 +2747,6 @@ impl<'w, 's, D: IterQueryData, F: QueryFilter> IntoIterator for &'w mut Query<'_
|
||||
}
|
||||
}
|
||||
|
||||
impl<'w, 's, D: ReadOnlyQueryData, F: QueryFilter> Query<'w, 's, D, F> {
|
||||
/// Returns an [`Iterator`] over the query items, with the actual "inner" world lifetime.
|
||||
///
|
||||
/// This can only return immutable data (mutable data will be cast to an immutable form).
|
||||
/// See [`Self::iter_mut`] for queries that contain at least one mutable component.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// Here, the `report_names_system` iterates over the `Player` component of every entity
|
||||
/// that contains it:
|
||||
///
|
||||
/// ```
|
||||
/// # use bevy_ecs::prelude::*;
|
||||
/// #
|
||||
/// # #[derive(Component)]
|
||||
/// # struct Player { name: String }
|
||||
/// #
|
||||
/// fn report_names_system(query: Query<&Player>) {
|
||||
/// for player in &query {
|
||||
/// println!("Say hello to {}!", player.name);
|
||||
/// }
|
||||
/// }
|
||||
/// # bevy_ecs::system::assert_is_system(report_names_system);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn iter_inner(&self) -> QueryIter<'w, 's, D::ReadOnly, F> {
|
||||
(*self).into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
/// Type returned from [`Query::transmute_lens`] containing the new [`QueryState`].
|
||||
///
|
||||
/// Call [`query`](QueryLens::query) or [`into`](Into::into) to construct the resulting [`Query`]
|
||||
|
||||
@@ -12,13 +12,18 @@ and need additional trait bounds to ensure they are only used soundly.
|
||||
|
||||
An `IterQueryData` bound has been added to iteration methods on `Query`:
|
||||
|
||||
* `iter_mut`/ `iter_unsafe` / `into_iter`
|
||||
* `into_iter`
|
||||
* `iter_many_unique_mut` / `iter_many_unique_unsafe` / `iter_many_unique_inner`
|
||||
* `get_many_mut` / `get_many_inner` / `get_many_unique_mut` / `get_many_unique_inner`
|
||||
* `par_iter_mut` / `par_iter_inner` / `par_iter_many_unique_mut`
|
||||
* `single_mut` / `single_inner`
|
||||
* `iter_combinations_mut` / `iter_combinations_inner` / `iter_combinations_unsafe`
|
||||
|
||||
`iter`, `iter_many`, `par_iter`, and `single` have no extra bounds,
|
||||
`iter_mut`, `iter_unsafe`, and `iter_inner` may be called with non-iterable data,
|
||||
but the resulting `QueryIter` will not `impl Iterator`.
|
||||
It may be iterated using streaming or lending iteration by calling the new `fetch_next` method.
|
||||
|
||||
`iter`, `iter_many`, `par_iter`, `single`, and `iter_combinations` have no extra bounds,
|
||||
since read-only queries are always sound to iterate.
|
||||
`iter_many_mut` and `iter_many_inner` methods have no extra bounds, either,
|
||||
since they already prohibit concurrent access to multiple entities.
|
||||
@@ -41,6 +46,11 @@ fn generic_func<D: QueryData>(query: Query<D>) {
|
||||
fn generic_func<D: IterQueryData>(query: Query<D>) {
|
||||
for item in &mut query { ... }
|
||||
}
|
||||
// 0.18, but with support for non-iterable query types
|
||||
fn generic_func<D: QueryData>(mut query: Query<D>) {
|
||||
let mut iter = query.iter_mut();
|
||||
while let Some(item) = iter.fetch_next() { ... }
|
||||
}
|
||||
```
|
||||
|
||||
Conversely, manual implementations of `QueryData` may want to implement `IterQueryData` and `SingleEntityQueryData` if appropriate.
|
||||
|
||||
Reference in New Issue
Block a user