Move Item and fetch to QueryData from WorldQuery (#17679)

# Objective

Fixes #17662

## Solution

Moved `Item` and `fetch` from `WorldQuery` to `QueryData`, and adjusted
their implementations accordingly.

Currently, documentation related to `fetch` is written under
`WorldQuery`. It would be more appropriate to move it to the `QueryData`
documentation for clarity.

I am not very experienced with making contributions. If there are any
mistakes or areas for improvement, I would appreciate any suggestions
you may have.

## Migration Guide

The `WorldQuery::Item` type and `WorldQuery::fetch` method have been
moved to `QueryData`, as they were not useful for `QueryFilter` types.

---------

Co-authored-by: Chris Russell <8494645+chescock@users.noreply.github.com>
This commit is contained in:
couyit 2025-02-06 03:46:18 +09:00 committed by GitHub
parent 6be11a8a42
commit 03af547c28
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 593 additions and 634 deletions

View File

@ -9,7 +9,7 @@ use bevy_ecs::{
archetype::Archetype,
component::{ComponentId, Tick},
prelude::{Entity, Resource, World},
query::{FilteredAccess, QueryFilter, QueryItem, ReadFetch, WorldQuery},
query::{FilteredAccess, QueryData, QueryFilter, ReadFetch, WorldQuery},
storage::{Table, TableRow},
world::unsafe_world_cell::UnsafeWorldCell,
};
@ -151,13 +151,10 @@ pub struct AssetChangedState<A: AsAssetId> {
#[expect(unsafe_code, reason = "WorldQuery is an unsafe trait.")]
/// SAFETY: `ROQueryFetch<Self>` is the same as `QueryFetch<Self>`
unsafe impl<A: AsAssetId> WorldQuery for AssetChanged<A> {
type Item<'w> = ();
type Fetch<'w> = AssetChangedFetch<'w, A>;
type State = AssetChangedState<A>;
fn shrink<'wlong: 'wshort, 'wshort>(_: QueryItem<'wlong, Self>) -> QueryItem<'wshort, Self> {}
fn shrink_fetch<'wlong: 'wshort, 'wshort>(fetch: Self::Fetch<'wlong>) -> Self::Fetch<'wshort> {
fetch
}
@ -228,8 +225,6 @@ unsafe impl<A: AsAssetId> WorldQuery for AssetChanged<A> {
}
}
unsafe fn fetch<'w>(_: &mut Self::Fetch<'w>, _: Entity, _: TableRow) -> Self::Item<'w> {}
#[inline]
fn update_component_access(state: &Self::State, access: &mut FilteredAccess<ComponentId>) {
<&A>::update_component_access(&state.asset_id, access);

View File

@ -176,12 +176,10 @@ pub fn derive_query_data_impl(input: TokenStream) -> TokenStream {
&path,
&struct_name,
&visibility,
&item_struct_name,
&fetch_struct_name,
&field_types,
&user_impl_generics,
&user_impl_generics_with_world,
&field_idents,
&user_ty_generics,
&user_ty_generics_with_world,
&named_field_idents,
@ -213,12 +211,10 @@ pub fn derive_query_data_impl(input: TokenStream) -> TokenStream {
&path,
&read_only_struct_name,
&visibility,
&read_only_item_struct_name,
&read_only_fetch_struct_name,
&read_only_field_types,
&user_impl_generics,
&user_impl_generics_with_world,
&field_idents,
&user_ty_generics,
&user_ty_generics_with_world,
&named_field_idents,
@ -259,6 +255,29 @@ pub fn derive_query_data_impl(input: TokenStream) -> TokenStream {
unsafe impl #user_impl_generics #path::query::QueryData
for #read_only_struct_name #user_ty_generics #user_where_clauses {
type ReadOnly = #read_only_struct_name #user_ty_generics;
type Item<'__w> = #read_only_item_struct_name #user_ty_generics_with_world;
fn shrink<'__wlong: '__wshort, '__wshort>(
item: Self::Item<'__wlong>
) -> Self::Item<'__wshort> {
#read_only_item_struct_name {
#(
#field_idents: <#read_only_field_types>::shrink(item.#field_idents),
)*
}
}
/// SAFETY: we call `fetch` for each member that implements `Fetch`.
#[inline(always)]
unsafe fn fetch<'__w>(
_fetch: &mut <Self as #path::query::WorldQuery>::Fetch<'__w>,
_entity: #path::entity::Entity,
_table_row: #path::storage::TableRow,
) -> Self::Item<'__w> {
Self::Item {
#(#field_idents: <#read_only_field_types>::fetch(&mut _fetch.#named_field_idents, _entity, _table_row),)*
}
}
}
}
} else {
@ -270,6 +289,29 @@ pub fn derive_query_data_impl(input: TokenStream) -> TokenStream {
unsafe impl #user_impl_generics #path::query::QueryData
for #struct_name #user_ty_generics #user_where_clauses {
type ReadOnly = #read_only_struct_name #user_ty_generics;
type Item<'__w> = #item_struct_name #user_ty_generics_with_world;
fn shrink<'__wlong: '__wshort, '__wshort>(
item: Self::Item<'__wlong>
) -> Self::Item<'__wshort> {
#item_struct_name {
#(
#field_idents: <#field_types>::shrink(item.#field_idents),
)*
}
}
/// SAFETY: we call `fetch` for each member that implements `Fetch`.
#[inline(always)]
unsafe fn fetch<'__w>(
_fetch: &mut <Self as #path::query::WorldQuery>::Fetch<'__w>,
_entity: #path::entity::Entity,
_table_row: #path::storage::TableRow,
) -> Self::Item<'__w> {
Self::Item {
#(#field_idents: <#field_types>::fetch(&mut _fetch.#named_field_idents, _entity, _table_row),)*
}
}
}
#read_only_data_impl

View File

@ -4,10 +4,7 @@ use proc_macro2::{Ident, Span};
use quote::{format_ident, quote};
use syn::{parse_macro_input, parse_quote, Data, DataStruct, DeriveInput, Index};
use crate::{
bevy_ecs_path,
world_query::{item_struct, world_query_impl},
};
use crate::{bevy_ecs_path, world_query::world_query_impl};
mod field_attr_keywords {
syn::custom_keyword!(ignore);
@ -33,8 +30,6 @@ pub fn derive_query_filter_impl(input: TokenStream) -> TokenStream {
let struct_name = ast.ident;
let item_struct_name = Ident::new(&format!("{struct_name}Item"), Span::call_site());
let fetch_struct_name = Ident::new(&format!("{struct_name}Fetch"), Span::call_site());
let fetch_struct_name = ensure_no_collision(fetch_struct_name, tokens.clone());
@ -81,35 +76,14 @@ pub fn derive_query_filter_impl(input: TokenStream) -> TokenStream {
field_types.push(quote!(#field_ty));
}
let derive_macro_call = quote!();
let item_struct = item_struct(
&path,
fields,
&derive_macro_call,
&struct_name,
&visibility,
&item_struct_name,
&field_types,
&user_impl_generics_with_world,
&field_attrs,
&field_visibilities,
&field_idents,
&user_ty_generics,
&user_ty_generics_with_world,
user_where_clauses_with_world,
);
let world_query_impl = world_query_impl(
&path,
&struct_name,
&visibility,
&item_struct_name,
&fetch_struct_name,
&field_types,
&user_impl_generics,
&user_impl_generics_with_world,
&field_idents,
&user_ty_generics,
&user_ty_generics_with_world,
&named_field_idents,
@ -142,8 +116,6 @@ pub fn derive_query_filter_impl(input: TokenStream) -> TokenStream {
};
TokenStream::from(quote! {
#item_struct
const _: () = {
#[doc(hidden)]
#[doc = concat!(

View File

@ -34,14 +34,14 @@ pub(crate) fn item_struct(
#derive_macro_call
#item_attrs
#visibility struct #item_struct_name #user_impl_generics_with_world #user_where_clauses_with_world {
#(#(#field_attrs)* #field_visibilities #field_idents: <#field_types as #path::query::WorldQuery>::Item<'__w>,)*
#(#(#field_attrs)* #field_visibilities #field_idents: <#field_types as #path::query::QueryData>::Item<'__w>,)*
}
},
Fields::Unnamed(_) => quote! {
#derive_macro_call
#item_attrs
#visibility struct #item_struct_name #user_impl_generics_with_world #user_where_clauses_with_world(
#( #field_visibilities <#field_types as #path::query::WorldQuery>::Item<'__w>, )*
#( #field_visibilities <#field_types as #path::query::QueryData>::Item<'__w>, )*
);
},
Fields::Unit => quote! {
@ -55,12 +55,10 @@ pub(crate) fn world_query_impl(
path: &syn::Path,
struct_name: &Ident,
visibility: &Visibility,
item_struct_name: &Ident,
fetch_struct_name: &Ident,
field_types: &Vec<proc_macro2::TokenStream>,
user_impl_generics: &ImplGenerics,
user_impl_generics_with_world: &ImplGenerics,
field_idents: &Vec<proc_macro2::TokenStream>,
user_ty_generics: &TypeGenerics,
user_ty_generics_with_world: &TypeGenerics,
named_field_idents: &Vec<Ident>,
@ -98,20 +96,9 @@ pub(crate) fn world_query_impl(
unsafe impl #user_impl_generics #path::query::WorldQuery
for #struct_name #user_ty_generics #user_where_clauses {
type Item<'__w> = #item_struct_name #user_ty_generics_with_world;
type Fetch<'__w> = #fetch_struct_name #user_ty_generics_with_world;
type State = #state_struct_name #user_ty_generics;
fn shrink<'__wlong: '__wshort, '__wshort>(
item: <#struct_name #user_ty_generics as #path::query::WorldQuery>::Item<'__wlong>
) -> <#struct_name #user_ty_generics as #path::query::WorldQuery>::Item<'__wshort> {
#item_struct_name {
#(
#field_idents: <#field_types>::shrink(item.#field_idents),
)*
}
}
fn shrink_fetch<'__wlong: '__wshort, '__wshort>(
fetch: <#struct_name #user_ty_generics as #path::query::WorldQuery>::Fetch<'__wlong>
) -> <#struct_name #user_ty_generics as #path::query::WorldQuery>::Fetch<'__wshort> {
@ -165,18 +152,6 @@ pub(crate) fn world_query_impl(
#(<#field_types>::set_table(&mut _fetch.#named_field_idents, &_state.#named_field_idents, _table);)*
}
/// SAFETY: we call `fetch` for each member that implements `Fetch`.
#[inline(always)]
unsafe fn fetch<'__w>(
_fetch: &mut <Self as #path::query::WorldQuery>::Fetch<'__w>,
_entity: #path::entity::Entity,
_table_row: #path::storage::TableRow,
) -> <Self as #path::query::WorldQuery>::Item<'__w> {
Self::Item {
#(#field_idents: <#field_types>::fetch(&mut _fetch.#named_field_idents, _entity, _table_row),)*
}
}
fn update_component_access(state: &Self::State, _access: &mut #path::query::FilteredAccess<#path::component::ComponentId>) {
#( <#field_types>::update_component_access(&state.#named_field_idents, _access); )*
}

File diff suppressed because it is too large Load Diff

View File

@ -66,7 +66,6 @@ use variadics_please::all_tuples;
/// # bevy_ecs::system::assert_is_system(my_system);
/// ```
///
/// [`fetch`]: Self::fetch
/// [`matches_component_set`]: Self::matches_component_set
/// [`Query`]: crate::system::Query
/// [`State`]: Self::State
@ -97,7 +96,7 @@ pub unsafe trait QueryFilter: WorldQuery {
/// ones that are compatible with the Filter's access.
///
/// Implementors of this method will generally either have a trivial `true` body (required for archetypal filters),
/// or call [`WorldQuery::fetch`] to access the raw data needed to make the final decision on filter inclusion.
/// or access the necessary data within this function to make the final decision on filter inclusion.
///
/// # Safety
///
@ -141,16 +140,13 @@ pub struct With<T>(PhantomData<T>);
/// SAFETY:
/// `update_component_access` does not add any accesses.
/// This is sound because `fetch` does not access any components.
/// This is sound because [`QueryFilter::filter_fetch`] does not access any components.
/// `update_component_access` adds a `With` filter for `T`.
/// This is sound because `matches_component_set` returns whether the set contains the component.
unsafe impl<T: Component> WorldQuery for With<T> {
type Item<'w> = ();
type Fetch<'w> = ();
type State = ComponentId;
fn shrink<'wlong: 'wshort, 'wshort>(_: Self::Item<'wlong>) -> Self::Item<'wshort> {}
fn shrink_fetch<'wlong: 'wshort, 'wshort>(_: Self::Fetch<'wlong>) -> Self::Fetch<'wshort> {}
#[inline]
@ -181,14 +177,6 @@ unsafe impl<T: Component> WorldQuery for With<T> {
#[inline]
unsafe fn set_table(_fetch: &mut (), _state: &ComponentId, _table: &Table) {}
#[inline(always)]
unsafe fn fetch<'w>(
_fetch: &mut Self::Fetch<'w>,
_entity: Entity,
_table_row: TableRow,
) -> Self::Item<'w> {
}
#[inline]
fn update_component_access(&id: &ComponentId, access: &mut FilteredAccess<ComponentId>) {
access.and_with(id);
@ -252,16 +240,13 @@ pub struct Without<T>(PhantomData<T>);
/// SAFETY:
/// `update_component_access` does not add any accesses.
/// This is sound because `fetch` does not access any components.
/// This is sound because [`QueryFilter::filter_fetch`] does not access any components.
/// `update_component_access` adds a `Without` filter for `T`.
/// This is sound because `matches_component_set` returns whether the set does not contain the component.
unsafe impl<T: Component> WorldQuery for Without<T> {
type Item<'w> = ();
type Fetch<'w> = ();
type State = ComponentId;
fn shrink<'wlong: 'wshort, 'wshort>(_: Self::Item<'wlong>) -> Self::Item<'wshort> {}
fn shrink_fetch<'wlong: 'wshort, 'wshort>(_: Self::Fetch<'wlong>) -> Self::Fetch<'wshort> {}
#[inline]
@ -292,14 +277,6 @@ unsafe impl<T: Component> WorldQuery for Without<T> {
#[inline]
unsafe fn set_table(_fetch: &mut (), _state: &Self::State, _table: &Table) {}
#[inline(always)]
unsafe fn fetch<'w>(
_fetch: &mut Self::Fetch<'w>,
_entity: Entity,
_table_row: TableRow,
) -> Self::Item<'w> {
}
#[inline]
fn update_component_access(&id: &ComponentId, access: &mut FilteredAccess<ComponentId>) {
access.and_without(id);
@ -402,19 +379,14 @@ macro_rules! impl_or_query_filter {
reason = "Zero-length tuples will generate some function bodies equivalent to `()`; however, this macro is meant for all applicable tuples, and as such it makes no sense to rewrite it just for that case."
)]
/// SAFETY:
/// `fetch` accesses are a subset of the subqueries' accesses
/// [`QueryFilter::filter_fetch`] accesses are a subset of the subqueries' accesses
/// This is sound because `update_component_access` adds accesses according to the implementations of all the subqueries.
/// `update_component_access` replace the filters with a disjunction where every element is a conjunction of the previous filters and the filters of one of the subqueries.
/// This is sound because `matches_component_set` returns a disjunction of the results of the subqueries' implementations.
unsafe impl<$($filter: QueryFilter),*> WorldQuery for Or<($($filter,)*)> {
type Fetch<'w> = ($(OrFetch<'w, $filter>,)*);
type Item<'w> = bool;
type State = ($($filter::State,)*);
fn shrink<'wlong: 'wshort, 'wshort>(item: Self::Item<'wlong>) -> Self::Item<'wshort> {
item
}
fn shrink_fetch<'wlong: 'wshort, 'wshort>(fetch: Self::Fetch<'wlong>) -> Self::Fetch<'wshort> {
let ($($filter,)*) = fetch;
($(
@ -468,17 +440,6 @@ macro_rules! impl_or_query_filter {
)*
}
#[inline(always)]
unsafe fn fetch<'w>(
fetch: &mut Self::Fetch<'w>,
entity: Entity,
table_row: TableRow
) -> Self::Item<'w> {
let ($($filter,)*) = fetch;
// SAFETY: The invariants are upheld by the caller.
false $(|| ($filter.matches && unsafe { $filter::filter_fetch(&mut $filter.fetch, entity, table_row) }))*
}
fn update_component_access(state: &Self::State, access: &mut FilteredAccess<ComponentId>) {
let ($($filter,)*) = state;
@ -515,6 +476,18 @@ macro_rules! impl_or_query_filter {
}
}
#[expect(
clippy::allow_attributes,
reason = "This is a tuple-related macro; as such the lints below may not always apply."
)]
#[allow(
non_snake_case,
reason = "The names of some variables are provided by the macro's caller, not by us."
)]
#[allow(
unused_variables,
reason = "Zero-length tuples won't use any of the parameters."
)]
$(#[$meta])*
// SAFETY: This only performs access that subqueries perform, and they impl `QueryFilter` and so perform no mutable access.
unsafe impl<$($filter: QueryFilter),*> QueryFilter for Or<($($filter,)*)> {
@ -526,8 +499,9 @@ macro_rules! impl_or_query_filter {
entity: Entity,
table_row: TableRow
) -> bool {
let ($($filter,)*) = fetch;
// SAFETY: The invariants are upheld by the caller.
unsafe { Self::fetch(fetch, entity, table_row) }
false $(|| ($filter.matches && unsafe { $filter::filter_fetch(&mut $filter.fetch, entity, table_row) }))*
}
}
};
@ -673,19 +647,14 @@ impl<T: Component> Clone for AddedFetch<'_, T> {
}
/// SAFETY:
/// `fetch` accesses a single component in a readonly way.
/// [`QueryFilter::filter_fetch`] accesses a single component in a readonly way.
/// This is sound because `update_component_access` adds read access for that component and panics when appropriate.
/// `update_component_access` adds a `With` filter for a component.
/// This is sound because `matches_component_set` returns whether the set contains that component.
unsafe impl<T: Component> WorldQuery for Added<T> {
type Item<'w> = bool;
type Fetch<'w> = AddedFetch<'w, T>;
type State = ComponentId;
fn shrink<'wlong: 'wshort, 'wshort>(item: Self::Item<'wlong>) -> Self::Item<'wshort> {
item
}
fn shrink_fetch<'wlong: 'wshort, 'wshort>(fetch: Self::Fetch<'wlong>) -> Self::Fetch<'wshort> {
fetch
}
@ -751,32 +720,6 @@ unsafe impl<T: Component> WorldQuery for Added<T> {
unsafe { fetch.ticks.set_table(table_ticks) };
}
#[inline(always)]
unsafe fn fetch<'w>(
fetch: &mut Self::Fetch<'w>,
entity: Entity,
table_row: TableRow,
) -> Self::Item<'w> {
fetch.ticks.extract(
|table| {
// SAFETY: set_table was previously called
let table = unsafe { table.debug_checked_unwrap() };
// SAFETY: The caller ensures `table_row` is in range.
let tick = unsafe { table.get(table_row.as_usize()) };
tick.deref().is_newer_than(fetch.last_run, fetch.this_run)
},
|sparse_set| {
// SAFETY: The caller ensures `entity` is in range.
let tick = unsafe {
ComponentSparseSet::get_added_tick(sparse_set, entity).debug_checked_unwrap()
};
tick.deref().is_newer_than(fetch.last_run, fetch.this_run)
},
)
}
#[inline]
fn update_component_access(&id: &ComponentId, access: &mut FilteredAccess<ComponentId>) {
if access.access().has_component_write(id) {
@ -811,7 +754,24 @@ unsafe impl<T: Component> QueryFilter for Added<T> {
table_row: TableRow,
) -> bool {
// SAFETY: The invariants are upheld by the caller.
unsafe { Self::fetch(fetch, entity, table_row) }
fetch.ticks.extract(
|table| {
// SAFETY: set_table was previously called
let table = unsafe { table.debug_checked_unwrap() };
// SAFETY: The caller ensures `table_row` is in range.
let tick = unsafe { table.get(table_row.as_usize()) };
tick.deref().is_newer_than(fetch.last_run, fetch.this_run)
},
|sparse_set| {
// SAFETY: The caller ensures `entity` is in range.
let tick = unsafe {
ComponentSparseSet::get_added_tick(sparse_set, entity).debug_checked_unwrap()
};
tick.deref().is_newer_than(fetch.last_run, fetch.this_run)
},
)
}
}
@ -911,14 +871,9 @@ impl<T: Component> Clone for ChangedFetch<'_, T> {
/// `update_component_access` adds a `With` filter for a component.
/// This is sound because `matches_component_set` returns whether the set contains that component.
unsafe impl<T: Component> WorldQuery for Changed<T> {
type Item<'w> = bool;
type Fetch<'w> = ChangedFetch<'w, T>;
type State = ComponentId;
fn shrink<'wlong: 'wshort, 'wshort>(item: Self::Item<'wlong>) -> Self::Item<'wshort> {
item
}
fn shrink_fetch<'wlong: 'wshort, 'wshort>(fetch: Self::Fetch<'wlong>) -> Self::Fetch<'wshort> {
fetch
}
@ -984,32 +939,6 @@ unsafe impl<T: Component> WorldQuery for Changed<T> {
unsafe { fetch.ticks.set_table(table_ticks) };
}
#[inline(always)]
unsafe fn fetch<'w>(
fetch: &mut Self::Fetch<'w>,
entity: Entity,
table_row: TableRow,
) -> Self::Item<'w> {
fetch.ticks.extract(
|table| {
// SAFETY: set_table was previously called
let table = unsafe { table.debug_checked_unwrap() };
// SAFETY: The caller ensures `table_row` is in range.
let tick = unsafe { table.get(table_row.as_usize()) };
tick.deref().is_newer_than(fetch.last_run, fetch.this_run)
},
|sparse_set| {
// SAFETY: The caller ensures `entity` is in range.
let tick = unsafe {
ComponentSparseSet::get_changed_tick(sparse_set, entity).debug_checked_unwrap()
};
tick.deref().is_newer_than(fetch.last_run, fetch.this_run)
},
)
}
#[inline]
fn update_component_access(&id: &ComponentId, access: &mut FilteredAccess<ComponentId>) {
if access.access().has_component_write(id) {
@ -1045,7 +974,24 @@ unsafe impl<T: Component> QueryFilter for Changed<T> {
table_row: TableRow,
) -> bool {
// SAFETY: The invariants are upheld by the caller.
unsafe { Self::fetch(fetch, entity, table_row) }
fetch.ticks.extract(
|table| {
// SAFETY: set_table was previously called
let table = unsafe { table.debug_checked_unwrap() };
// SAFETY: The caller ensures `table_row` is in range.
let tick = unsafe { table.get(table_row.as_usize()) };
tick.deref().is_newer_than(fetch.last_run, fetch.this_run)
},
|sparse_set| {
// SAFETY: The caller ensures `entity` is in range.
let tick = unsafe {
ComponentSparseSet::get_changed_tick(sparse_set, entity).debug_checked_unwrap()
};
tick.deref().is_newer_than(fetch.last_run, fetch.this_run)
},
)
}
}

View File

@ -809,12 +809,9 @@ mod tests {
/// `update_component_access` adds resource read access for `R`.
/// `update_archetype_component_access` does nothing, as this accesses no components.
unsafe impl WorldQuery for ReadsRData {
type Item<'w> = ();
type Fetch<'w> = ();
type State = ComponentId;
fn shrink<'wlong: 'wshort, 'wshort>(_item: Self::Item<'wlong>) -> Self::Item<'wshort> {}
fn shrink_fetch<'wlong: 'wshort, 'wshort>(_: Self::Fetch<'wlong>) -> Self::Fetch<'wshort> {}
unsafe fn init_fetch<'w>(
@ -844,14 +841,6 @@ mod tests {
) {
}
#[inline(always)]
unsafe fn fetch<'w>(
_fetch: &mut Self::Fetch<'w>,
_entity: Entity,
_table_row: TableRow,
) -> Self::Item<'w> {
}
fn update_component_access(
&component_id: &Self::State,
access: &mut FilteredAccess<ComponentId>,
@ -882,6 +871,17 @@ mod tests {
/// SAFETY: `Self` is the same as `Self::ReadOnly`
unsafe impl QueryData for ReadsRData {
type ReadOnly = Self;
type Item<'w> = ();
fn shrink<'wlong: 'wshort, 'wshort>(_item: Self::Item<'wlong>) -> Self::Item<'wshort> {}
#[inline(always)]
unsafe fn fetch<'w>(
_fetch: &mut Self::Fetch<'w>,
_entity: Entity,
_table_row: TableRow,
) -> Self::Item<'w> {
}
}
/// SAFETY: access is read only

View File

@ -1,9 +1,8 @@
use crate::{
archetype::Archetype,
component::{ComponentId, Components, Tick},
entity::Entity,
query::FilteredAccess,
storage::{Table, TableRow},
storage::Table,
world::{unsafe_world_cell::UnsafeWorldCell, World},
};
use variadics_please::all_tuples;
@ -14,11 +13,11 @@ use variadics_please::all_tuples;
/// # Safety
///
/// Implementor must ensure that
/// [`update_component_access`], [`matches_component_set`], [`fetch`] and [`init_fetch`]
/// [`update_component_access`], [`matches_component_set`], [`QueryData::fetch`], [`QueryFilter::filter_fetch`] and [`init_fetch`]
/// obey the following:
///
/// - For each component mutably accessed by [`fetch`], [`update_component_access`] should add write access unless read or write access has already been added, in which case it should panic.
/// - For each component readonly accessed by [`fetch`], [`update_component_access`] should add read access unless write access has already been added, in which case it should panic.
/// - For each component mutably accessed by [`QueryData::fetch`], [`update_component_access`] should add write access unless read or write access has already been added, in which case it should panic.
/// - For each component readonly accessed by [`QueryData::fetch`] or [`QueryFilter::filter_fetch`], [`update_component_access`] should add read access unless write access has already been added, in which case it should panic.
/// - If `fetch` mutably accesses the same component twice, [`update_component_access`] should panic.
/// - [`update_component_access`] may not add a `Without` filter for a component unless [`matches_component_set`] always returns `false` when the component set contains that component.
/// - [`update_component_access`] may not add a `With` filter for a component unless [`matches_component_set`] always returns `false` when the component set doesn't contain that component.
@ -31,7 +30,8 @@ use variadics_please::all_tuples;
///
/// When implementing [`update_component_access`], note that `add_read` and `add_write` both also add a `With` filter, whereas `extend_access` does not change the filters.
///
/// [`fetch`]: Self::fetch
/// [`QueryData::fetch`]: crate::query::QueryData::fetch
/// [`QueryFilter::filter_fetch`]: crate::query::QueryFilter::filter_fetch
/// [`init_fetch`]: Self::init_fetch
/// [`matches_component_set`]: Self::matches_component_set
/// [`Query`]: crate::system::Query
@ -39,19 +39,7 @@ use variadics_please::all_tuples;
/// [`QueryData`]: crate::query::QueryData
/// [`QueryFilter`]: crate::query::QueryFilter
pub unsafe trait WorldQuery {
/// The item returned by this [`WorldQuery`]
/// For `QueryData` this will be the data retrieved by the query,
/// and is visible to the end user when calling e.g. `Query<Self>::get`.
///
/// For `QueryFilter` this will be either `()`, or a `bool` indicating whether the entity should be included
/// or a tuple of such things.
/// Archetypal query filters (like `With`) set this to `()`,
/// as the filtering is done by selecting the archetypes to iterate over via [`WorldQuery::matches_component_set`],
/// while non-archetypal query filters (like `Changed`) set this to a `bool` and evaluate the filter for each entity,
/// after the set of possible archetypes has been narrowed down.
type Item<'a>;
/// Per archetype/table state retrieved by this [`WorldQuery`] to compute [`Self::Item`](WorldQuery::Item) for each entity.
/// Per archetype/table state retrieved by this [`WorldQuery`] to compute [`Self::Item`](crate::query::QueryData::Item) for each entity.
type Fetch<'a>: Clone;
/// State used to construct a [`Self::Fetch`](WorldQuery::Fetch). This will be cached inside [`QueryState`](crate::query::QueryState),
@ -59,9 +47,6 @@ pub unsafe trait WorldQuery {
/// constructing [`Self::Fetch`](WorldQuery::Fetch).
type State: Send + Sync + Sized;
/// This function manually implements subtyping for the query items.
fn shrink<'wlong: 'wshort, 'wshort>(item: Self::Item<'wlong>) -> Self::Item<'wshort>;
/// This function manually implements subtyping for the query fetches.
fn shrink_fetch<'wlong: 'wshort, 'wshort>(fetch: Self::Fetch<'wlong>) -> Self::Fetch<'wshort>;
@ -87,8 +72,8 @@ pub unsafe trait WorldQuery {
///
/// This is used to select a more efficient "table iterator"
/// for "dense" queries. If this returns true, [`WorldQuery::set_table`] must be used before
/// [`WorldQuery::fetch`] can be called for iterators. If this returns false,
/// [`WorldQuery::set_archetype`] must be used before [`WorldQuery::fetch`] can be called for
/// [`QueryData::fetch`](crate::query::QueryData::fetch) can be called for iterators. If this returns false,
/// [`WorldQuery::set_archetype`] must be used before [`QueryData::fetch`](crate::query::QueryData::fetch) can be called for
/// iterators.
const IS_DENSE: bool;
@ -122,23 +107,6 @@ pub unsafe trait WorldQuery {
/// Called when constructing a [`QueryLens`](crate::system::QueryLens) or calling [`QueryState::from_builder`](super::QueryState::from_builder)
fn set_access(_state: &mut Self::State, _access: &FilteredAccess<ComponentId>) {}
/// Fetch [`Self::Item`](`WorldQuery::Item`) for either the given `entity` in the current [`Table`],
/// or for the given `entity` in the current [`Archetype`]. This must always be called after
/// [`WorldQuery::set_table`] with a `table_row` in the range of the current [`Table`] or after
/// [`WorldQuery::set_archetype`] with an `entity` in the current archetype.
/// Accesses components registered in [`WorldQuery::update_component_access`].
///
/// # Safety
///
/// - Must always be called _after_ [`WorldQuery::set_table`] or [`WorldQuery::set_archetype`]. `entity` and
/// `table_row` must be in the range of the current table and archetype.
/// - There must not be simultaneous conflicting component access registered in `update_component_access`.
unsafe fn fetch<'w>(
fetch: &mut Self::Fetch<'w>,
entity: Entity,
table_row: TableRow,
) -> Self::Item<'w>;
/// Adds any component accesses used by this [`WorldQuery`] to `access`.
///
/// Used to check which queries are disjoint and can run in parallel
@ -191,15 +159,8 @@ macro_rules! impl_tuple_world_query {
/// This is sound because `matches_component_set` always returns `false` if any the subqueries' implementations return `false`.
unsafe impl<$($name: WorldQuery),*> WorldQuery for ($($name,)*) {
type Fetch<'w> = ($($name::Fetch<'w>,)*);
type Item<'w> = ($($name::Item<'w>,)*);
type State = ($($name::State,)*);
fn shrink<'wlong: 'wshort, 'wshort>(item: Self::Item<'wlong>) -> Self::Item<'wshort> {
let ($($name,)*) = item;
($(
$name::shrink($name),
)*)
}
fn shrink_fetch<'wlong: 'wshort, 'wshort>(fetch: Self::Fetch<'wlong>) -> Self::Fetch<'wshort> {
let ($($name,)*) = fetch;
@ -238,16 +199,6 @@ macro_rules! impl_tuple_world_query {
$(unsafe { $name::set_table($name, $state, table); })*
}
#[inline(always)]
unsafe fn fetch<'w>(
fetch: &mut Self::Fetch<'w>,
entity: Entity,
table_row: TableRow
) -> Self::Item<'w> {
let ($($name,)*) = fetch;
// SAFETY: The invariants are upheld by the caller.
($(unsafe { $name::fetch($name, entity, table_row) },)*)
}
fn update_component_access(state: &Self::State, access: &mut FilteredAccess<ComponentId>) {
let ($($name,)*) = state;

View File

@ -1,6 +1,6 @@
use crate::{
entity::Entity,
query::{QueryData, QueryFilter, WorldQuery},
query::{QueryData, QueryFilter},
relationship::{Relationship, RelationshipTarget},
system::Query,
};
@ -14,7 +14,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
/// target entity of that relationship.
pub fn related<R: Relationship>(&'w self, entity: Entity) -> Option<Entity>
where
<D as QueryData>::ReadOnly: WorldQuery<Item<'w> = &'w R>,
<D as QueryData>::ReadOnly: QueryData<Item<'w> = &'w R>,
{
self.get(entity).map(R::get).ok()
}
@ -26,7 +26,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
entity: Entity,
) -> impl Iterator<Item = Entity> + 'w
where
<D as QueryData>::ReadOnly: WorldQuery<Item<'w> = &'w S>,
<D as QueryData>::ReadOnly: QueryData<Item<'w> = &'w S>,
{
self.get(entity)
.into_iter()
@ -42,7 +42,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
/// If your relationship is not a tree (like Bevy's hierarchy), be sure to stop if you encounter a duplicate entity.
pub fn root_ancestor<R: Relationship>(&'w self, entity: Entity) -> Entity
where
<D as QueryData>::ReadOnly: WorldQuery<Item<'w> = &'w R>,
<D as QueryData>::ReadOnly: QueryData<Item<'w> = &'w R>,
{
// Recursively search up the tree until we're out of parents
match self.get(entity) {
@ -62,7 +62,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
entity: Entity,
) -> impl Iterator<Item = Entity> + 'w
where
<D as QueryData>::ReadOnly: WorldQuery<Item<'w> = &'w S>,
<D as QueryData>::ReadOnly: QueryData<Item<'w> = &'w S>,
SourceIter<'w, S>: DoubleEndedIterator,
{
self.iter_descendants_depth_first(entity).filter(|entity| {
@ -80,7 +80,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
entity: Entity,
) -> impl Iterator<Item = Entity> + 'w
where
D::ReadOnly: WorldQuery<Item<'w> = (Option<&'w R>, Option<&'w R::RelationshipTarget>)>,
D::ReadOnly: QueryData<Item<'w> = (Option<&'w R>, Option<&'w R::RelationshipTarget>)>,
{
self.get(entity)
.ok()
@ -103,7 +103,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
entity: Entity,
) -> DescendantIter<'w, 's, D, F, S>
where
D::ReadOnly: WorldQuery<Item<'w> = &'w S>,
D::ReadOnly: QueryData<Item<'w> = &'w S>,
{
DescendantIter::new(self, entity)
}
@ -120,7 +120,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
entity: Entity,
) -> DescendantDepthFirstIter<'w, 's, D, F, S>
where
D::ReadOnly: WorldQuery<Item<'w> = &'w S>,
D::ReadOnly: QueryData<Item<'w> = &'w S>,
SourceIter<'w, S>: DoubleEndedIterator,
{
DescendantDepthFirstIter::new(self, entity)
@ -137,7 +137,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
entity: Entity,
) -> AncestorIter<'w, 's, D, F, R>
where
D::ReadOnly: WorldQuery<Item<'w> = &'w R>,
D::ReadOnly: QueryData<Item<'w> = &'w R>,
{
AncestorIter::new(self, entity)
}
@ -148,7 +148,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
/// Traverses the hierarchy breadth-first.
pub struct DescendantIter<'w, 's, D: QueryData, F: QueryFilter, S: RelationshipTarget>
where
D::ReadOnly: WorldQuery<Item<'w> = &'w S>,
D::ReadOnly: QueryData<Item<'w> = &'w S>,
{
children_query: &'w Query<'w, 's, D, F>,
vecdeque: VecDeque<Entity>,
@ -156,7 +156,7 @@ where
impl<'w, 's, D: QueryData, F: QueryFilter, S: RelationshipTarget> DescendantIter<'w, 's, D, F, S>
where
D::ReadOnly: WorldQuery<Item<'w> = &'w S>,
D::ReadOnly: QueryData<Item<'w> = &'w S>,
{
/// Returns a new [`DescendantIter`].
pub fn new(children_query: &'w Query<'w, 's, D, F>, entity: Entity) -> Self {
@ -174,7 +174,7 @@ where
impl<'w, 's, D: QueryData, F: QueryFilter, S: RelationshipTarget> Iterator
for DescendantIter<'w, 's, D, F, S>
where
D::ReadOnly: WorldQuery<Item<'w> = &'w S>,
D::ReadOnly: QueryData<Item<'w> = &'w S>,
{
type Item = Entity;
@ -194,7 +194,7 @@ where
/// Traverses the hierarchy depth-first.
pub struct DescendantDepthFirstIter<'w, 's, D: QueryData, F: QueryFilter, S: RelationshipTarget>
where
D::ReadOnly: WorldQuery<Item<'w> = &'w S>,
D::ReadOnly: QueryData<Item<'w> = &'w S>,
{
children_query: &'w Query<'w, 's, D, F>,
stack: SmallVec<[Entity; 8]>,
@ -203,7 +203,7 @@ where
impl<'w, 's, D: QueryData, F: QueryFilter, S: RelationshipTarget>
DescendantDepthFirstIter<'w, 's, D, F, S>
where
D::ReadOnly: WorldQuery<Item<'w> = &'w S>,
D::ReadOnly: QueryData<Item<'w> = &'w S>,
SourceIter<'w, S>: DoubleEndedIterator,
{
/// Returns a new [`DescendantDepthFirstIter`].
@ -220,7 +220,7 @@ where
impl<'w, 's, D: QueryData, F: QueryFilter, S: RelationshipTarget> Iterator
for DescendantDepthFirstIter<'w, 's, D, F, S>
where
D::ReadOnly: WorldQuery<Item<'w> = &'w S>,
D::ReadOnly: QueryData<Item<'w> = &'w S>,
SourceIter<'w, S>: DoubleEndedIterator,
{
type Item = Entity;
@ -239,7 +239,7 @@ where
/// An [`Iterator`] of [`Entity`]s over the ancestors of an [`Entity`].
pub struct AncestorIter<'w, 's, D: QueryData, F: QueryFilter, R: Relationship>
where
D::ReadOnly: WorldQuery<Item<'w> = &'w R>,
D::ReadOnly: QueryData<Item<'w> = &'w R>,
{
parent_query: &'w Query<'w, 's, D, F>,
next: Option<Entity>,
@ -247,7 +247,7 @@ where
impl<'w, 's, D: QueryData, F: QueryFilter, R: Relationship> AncestorIter<'w, 's, D, F, R>
where
D::ReadOnly: WorldQuery<Item<'w> = &'w R>,
D::ReadOnly: QueryData<Item<'w> = &'w R>,
{
/// Returns a new [`AncestorIter`].
pub fn new(parent_query: &'w Query<'w, 's, D, F>, entity: Entity) -> Self {
@ -261,7 +261,7 @@ where
impl<'w, 's, D: QueryData, F: QueryFilter, R: Relationship> Iterator
for AncestorIter<'w, 's, D, F, R>
where
D::ReadOnly: WorldQuery<Item<'w> = &'w R>,
D::ReadOnly: QueryData<Item<'w> = &'w R>,
{
type Item = Entity;

View File

@ -285,14 +285,9 @@ mod render_entities_world_query_impls {
/// SAFETY: defers completely to `&RenderEntity` implementation,
/// and then only modifies the output safely.
unsafe impl WorldQuery for RenderEntity {
type Item<'w> = Entity;
type Fetch<'w> = <&'static RenderEntity as WorldQuery>::Fetch<'w>;
type State = <&'static RenderEntity as WorldQuery>::State;
fn shrink<'wlong: 'wshort, 'wshort>(item: Entity) -> Entity {
item
}
fn shrink_fetch<'wlong: 'wshort, 'wshort>(
fetch: Self::Fetch<'wlong>,
) -> Self::Fetch<'wshort> {
@ -337,18 +332,6 @@ mod render_entities_world_query_impls {
unsafe { <&RenderEntity as WorldQuery>::set_table(fetch, &component_id, table) }
}
#[inline(always)]
unsafe fn fetch<'w>(
fetch: &mut Self::Fetch<'w>,
entity: Entity,
table_row: TableRow,
) -> Self::Item<'w> {
// SAFETY: defers to the `&T` implementation, with T set to `RenderEntity`.
let component =
unsafe { <&RenderEntity as WorldQuery>::fetch(fetch, entity, table_row) };
component.id()
}
fn update_component_access(
&component_id: &ComponentId,
access: &mut FilteredAccess<ComponentId>,
@ -376,6 +359,23 @@ mod render_entities_world_query_impls {
// Self::ReadOnly matches exactly the same archetypes/tables as Self.
unsafe impl QueryData for RenderEntity {
type ReadOnly = RenderEntity;
type Item<'w> = Entity;
fn shrink<'wlong: 'wshort, 'wshort>(item: Entity) -> Entity {
item
}
#[inline(always)]
unsafe fn fetch<'w>(
fetch: &mut Self::Fetch<'w>,
entity: Entity,
table_row: TableRow,
) -> Self::Item<'w> {
// SAFETY: defers to the `&T` implementation, with T set to `RenderEntity`.
let component =
unsafe { <&RenderEntity as QueryData>::fetch(fetch, entity, table_row) };
component.id()
}
}
// SAFETY: the underlying `Entity` is copied, and no mutable access is provided.
@ -384,14 +384,9 @@ mod render_entities_world_query_impls {
/// SAFETY: defers completely to `&RenderEntity` implementation,
/// and then only modifies the output safely.
unsafe impl WorldQuery for MainEntity {
type Item<'w> = Entity;
type Fetch<'w> = <&'static MainEntity as WorldQuery>::Fetch<'w>;
type State = <&'static MainEntity as WorldQuery>::State;
fn shrink<'wlong: 'wshort, 'wshort>(item: Entity) -> Entity {
item
}
fn shrink_fetch<'wlong: 'wshort, 'wshort>(
fetch: Self::Fetch<'wlong>,
) -> Self::Fetch<'wshort> {
@ -436,17 +431,6 @@ mod render_entities_world_query_impls {
unsafe { <&MainEntity as WorldQuery>::set_table(fetch, &component_id, table) }
}
#[inline(always)]
unsafe fn fetch<'w>(
fetch: &mut Self::Fetch<'w>,
entity: Entity,
table_row: TableRow,
) -> Self::Item<'w> {
// SAFETY: defers to the `&T` implementation, with T set to `MainEntity`.
let component = unsafe { <&MainEntity as WorldQuery>::fetch(fetch, entity, table_row) };
component.id()
}
fn update_component_access(
&component_id: &ComponentId,
access: &mut FilteredAccess<ComponentId>,
@ -474,6 +458,22 @@ mod render_entities_world_query_impls {
// Self::ReadOnly matches exactly the same archetypes/tables as Self.
unsafe impl QueryData for MainEntity {
type ReadOnly = MainEntity;
type Item<'w> = Entity;
fn shrink<'wlong: 'wshort, 'wshort>(item: Entity) -> Entity {
item
}
#[inline(always)]
unsafe fn fetch<'w>(
fetch: &mut Self::Fetch<'w>,
entity: Entity,
table_row: TableRow,
) -> Self::Item<'w> {
// SAFETY: defers to the `&T` implementation, with T set to `MainEntity`.
let component = unsafe { <&MainEntity as QueryData>::fetch(fetch, entity, table_row) };
component.id()
}
}
// SAFETY: the underlying `Entity` is copied, and no mutable access is provided.