mirror of
https://github.com/bevyengine/bevy
synced 2024-11-22 20:53:53 +00:00
make WorldQuery
very flat (#5205)
# Objective Simplify the worldquery trait hierarchy as much as possible by putting it all in one trait. If/when gats are stabilised this can be trivially migrated over to use them, although that's not why I made this PR, those reasons are: - Moves all of the conceptually related unsafe code for a worldquery next to eachother - Removes now unnecessary traits simplifying the "type system magic" in bevy_ecs --- ## Changelog All methods/functions/types/consts on `FetchState` and `Fetch` traits have been moved to the `WorldQuery` trait and the other traits removed. `WorldQueryGats` now only contains an `Item` and `Fetch` assoc type. ## Migration Guide Implementors should move items in impls to the `WorldQuery/Gats` traits and remove any `Fetch`/`FetchState` impls Any use sites of items in the `Fetch`/`FetchState` traits should be updated to use the `WorldQuery` trait items instead Co-authored-by: Carter Anderson <mcanders1@gmail.com>
This commit is contained in:
parent
07d576987a
commit
eabcd27d93
6 changed files with 1080 additions and 1230 deletions
|
@ -79,6 +79,8 @@ pub fn derive_world_query_impl(ast: DeriveInput) -> TokenStream {
|
|||
.unwrap_or_else(|_| panic!("Invalid `{}` attribute format", WORLD_QUERY_ATTRIBUTE_NAME));
|
||||
}
|
||||
|
||||
let path = bevy_ecs_path();
|
||||
|
||||
let user_generics = ast.generics.clone();
|
||||
let (user_impl_generics, user_ty_generics, user_where_clauses) = user_generics.split_for_impl();
|
||||
let user_generics_with_world = {
|
||||
|
@ -112,11 +114,6 @@ pub fn derive_world_query_impl(ast: DeriveInput) -> TokenStream {
|
|||
|
||||
let state_struct_name = Ident::new(&format!("{}State", struct_name), Span::call_site());
|
||||
|
||||
let fetch_type_alias = Ident::new("QueryFetch", Span::call_site());
|
||||
let read_only_fetch_type_alias = Ident::new("ROQueryFetch", Span::call_site());
|
||||
let item_type_alias = Ident::new("QueryItem", Span::call_site());
|
||||
let read_only_item_type_alias = Ident::new("ROQueryItem", Span::call_site());
|
||||
|
||||
let fields = match &ast.data {
|
||||
Data::Struct(DataStruct {
|
||||
fields: Fields::Named(fields),
|
||||
|
@ -133,6 +130,7 @@ pub fn derive_world_query_impl(ast: DeriveInput) -> TokenStream {
|
|||
let mut field_visibilities = Vec::new();
|
||||
let mut field_idents = Vec::new();
|
||||
let mut field_types = Vec::new();
|
||||
let mut read_only_field_types = Vec::new();
|
||||
|
||||
for field in fields {
|
||||
let WorldQueryFieldInfo { is_ignored, attrs } = read_world_query_field_info(field);
|
||||
|
@ -147,7 +145,9 @@ pub fn derive_world_query_impl(ast: DeriveInput) -> TokenStream {
|
|||
field_attrs.push(attrs);
|
||||
field_visibilities.push(field.vis.clone());
|
||||
field_idents.push(field_ident.clone());
|
||||
field_types.push(field.ty.clone());
|
||||
let field_ty = field.ty.clone();
|
||||
field_types.push(quote!(#field_ty));
|
||||
read_only_field_types.push(quote!(<#field_ty as #path::query::WorldQuery>::ReadOnly));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -155,46 +155,80 @@ pub fn derive_world_query_impl(ast: DeriveInput) -> TokenStream {
|
|||
// `#[derive()]` is valid syntax
|
||||
let derive_macro_call = quote! { #[derive(#derive_args)] };
|
||||
|
||||
let path = bevy_ecs_path();
|
||||
|
||||
let impl_fetch = |is_readonly: bool, fetch_struct_name: Ident, item_struct_name: Ident| {
|
||||
let fetch_type_alias = if is_readonly {
|
||||
&read_only_fetch_type_alias
|
||||
let impl_fetch = |is_readonly: bool| {
|
||||
let struct_name = if is_readonly {
|
||||
&read_only_struct_name
|
||||
} else {
|
||||
&fetch_type_alias
|
||||
&struct_name
|
||||
};
|
||||
let item_type_alias = if is_readonly {
|
||||
&read_only_item_type_alias
|
||||
let item_struct_name = if is_readonly {
|
||||
&read_only_item_struct_name
|
||||
} else {
|
||||
&item_type_alias
|
||||
&item_struct_name
|
||||
};
|
||||
let fetch_struct_name = if is_readonly {
|
||||
&read_only_fetch_struct_name
|
||||
} else {
|
||||
&fetch_struct_name
|
||||
};
|
||||
|
||||
let field_types = if is_readonly {
|
||||
&read_only_field_types
|
||||
} else {
|
||||
&field_types
|
||||
};
|
||||
|
||||
quote! {
|
||||
#derive_macro_call
|
||||
#[automatically_derived]
|
||||
#visibility struct #item_struct_name #user_impl_generics_with_world #user_where_clauses_with_world {
|
||||
#(#(#field_attrs)* #field_visibilities #field_idents: #path::query::#item_type_alias<'__w, #field_types>,)*
|
||||
#(#(#field_attrs)* #field_visibilities #field_idents: <#field_types as #path::query::WorldQueryGats<'__w>>::Item,)*
|
||||
#(#(#ignored_field_attrs)* #ignored_field_visibilities #ignored_field_idents: #ignored_field_types,)*
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[doc(hidden)]
|
||||
#visibility struct #fetch_struct_name #user_impl_generics_with_world #user_where_clauses_with_world {
|
||||
#(#field_idents: #path::query::#fetch_type_alias::<'__w, #field_types>,)*
|
||||
#(#field_idents: <#field_types as #path::query::WorldQueryGats<'__w>>::Fetch,)*
|
||||
#(#ignored_field_idents: #ignored_field_types,)*
|
||||
}
|
||||
|
||||
// SAFETY: `update_component_access` and `update_archetype_component_access` are called on every field
|
||||
unsafe impl #user_impl_generics_with_world #path::query::Fetch<'__w>
|
||||
for #fetch_struct_name #user_ty_generics_with_world #user_where_clauses_with_world {
|
||||
|
||||
type Item = #item_struct_name #user_ty_generics_with_world;
|
||||
impl #user_impl_generics_with_world #path::query::WorldQueryGats<'__w>
|
||||
for #struct_name #user_ty_generics #user_where_clauses {
|
||||
type Item = #item_struct_name #user_ty_generics_with_world;
|
||||
type Fetch = #fetch_struct_name #user_ty_generics_with_world;
|
||||
}
|
||||
|
||||
unsafe impl #user_impl_generics #path::query::WorldQuery
|
||||
for #struct_name #user_ty_generics #user_where_clauses {
|
||||
|
||||
type ReadOnly = #read_only_struct_name #user_ty_generics;
|
||||
type State = #state_struct_name #user_ty_generics;
|
||||
|
||||
unsafe fn init(_world: &'__w #path::world::World, state: &Self::State, _last_change_tick: u32, _change_tick: u32) -> Self {
|
||||
Self {
|
||||
fn shrink<'__wlong: '__wshort, '__wshort>(
|
||||
item: <#struct_name #user_ty_generics as #path::query::WorldQueryGats<'__wlong>>::Item
|
||||
) -> <#struct_name #user_ty_generics as #path::query::WorldQueryGats<'__wshort>>::Item {
|
||||
#item_struct_name {
|
||||
#(
|
||||
#field_idents: <#field_types>::shrink(item.#field_idents),
|
||||
)*
|
||||
#(
|
||||
#ignored_field_idents: item.#ignored_field_idents,
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn init_fetch<'__w>(
|
||||
_world: &'__w #path::world::World,
|
||||
state: &Self::State,
|
||||
_last_change_tick: u32,
|
||||
_change_tick: u32
|
||||
) -> <Self as #path::query::WorldQueryGats<'__w>>::Fetch {
|
||||
#fetch_struct_name {
|
||||
#(#field_idents:
|
||||
#path::query::#fetch_type_alias::<'__w, #field_types>::init(
|
||||
<#field_types>::init_fetch(
|
||||
_world,
|
||||
&state.#field_idents,
|
||||
_last_change_tick,
|
||||
|
@ -205,138 +239,106 @@ pub fn derive_world_query_impl(ast: DeriveInput) -> TokenStream {
|
|||
}
|
||||
}
|
||||
|
||||
const IS_DENSE: bool = true #(&& #path::query::#fetch_type_alias::<'__w, #field_types>::IS_DENSE)*;
|
||||
const IS_DENSE: bool = true #(&& <#field_types>::IS_DENSE)*;
|
||||
|
||||
const IS_ARCHETYPAL: bool = true #(&& #path::query::#fetch_type_alias::<'__w, #field_types>::IS_ARCHETYPAL)*;
|
||||
const IS_ARCHETYPAL: bool = true #(&& <#field_types>::IS_ARCHETYPAL)*;
|
||||
|
||||
/// SAFETY: we call `set_archetype` for each member that implements `Fetch`
|
||||
#[inline]
|
||||
unsafe fn set_archetype(
|
||||
&mut self,
|
||||
unsafe fn set_archetype<'__w>(
|
||||
_fetch: &mut <Self as #path::query::WorldQueryGats<'__w>>::Fetch,
|
||||
_state: &Self::State,
|
||||
_archetype: &'__w #path::archetype::Archetype,
|
||||
_tables: &'__w #path::storage::Tables
|
||||
) {
|
||||
#(self.#field_idents.set_archetype(&_state.#field_idents, _archetype, _tables);)*
|
||||
#(<#field_types>::set_archetype(&mut _fetch.#field_idents, &_state.#field_idents, _archetype, _tables);)*
|
||||
}
|
||||
|
||||
/// SAFETY: we call `set_table` for each member that implements `Fetch`
|
||||
#[inline]
|
||||
unsafe fn set_table(&mut self, _state: &Self::State, _table: &'__w #path::storage::Table) {
|
||||
#(self.#field_idents.set_table(&_state.#field_idents, _table);)*
|
||||
unsafe fn set_table<'__w>(
|
||||
_fetch: &mut <Self as #path::query::WorldQueryGats<'__w>>::Fetch,
|
||||
_state: &Self::State,
|
||||
_table: &'__w #path::storage::Table
|
||||
) {
|
||||
#(<#field_types>::set_table(&mut _fetch.#field_idents, &_state.#field_idents, _table);)*
|
||||
}
|
||||
|
||||
/// SAFETY: we call `table_fetch` for each member that implements `Fetch`.
|
||||
#[inline]
|
||||
unsafe fn table_fetch(&mut self, _table_row: usize) -> Self::Item {
|
||||
unsafe fn table_fetch<'__w>(
|
||||
_fetch: &mut <Self as #path::query::WorldQueryGats<'__w>>::Fetch,
|
||||
_table_row: usize
|
||||
) -> <Self as #path::query::WorldQueryGats<'__w>>::Item {
|
||||
Self::Item {
|
||||
#(#field_idents: self.#field_idents.table_fetch(_table_row),)*
|
||||
#(#field_idents: <#field_types>::table_fetch(&mut _fetch.#field_idents, _table_row),)*
|
||||
#(#ignored_field_idents: Default::default(),)*
|
||||
}
|
||||
}
|
||||
|
||||
/// SAFETY: we call `archetype_fetch` for each member that implements `Fetch`.
|
||||
#[inline]
|
||||
unsafe fn archetype_fetch(&mut self, _archetype_index: usize) -> Self::Item {
|
||||
unsafe fn archetype_fetch<'__w>(
|
||||
_fetch: &mut <Self as #path::query::WorldQueryGats<'__w>>::Fetch,
|
||||
_archetype_index: usize
|
||||
) -> <Self as #path::query::WorldQueryGats<'__w>>::Item {
|
||||
Self::Item {
|
||||
#(#field_idents: self.#field_idents.archetype_fetch(_archetype_index),)*
|
||||
#(#field_idents: <#field_types>::archetype_fetch(&mut _fetch.#field_idents, _archetype_index),)*
|
||||
#(#ignored_field_idents: Default::default(),)*
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
#[inline]
|
||||
unsafe fn table_filter_fetch(&mut self, _table_row: usize) -> bool {
|
||||
true #(&& self.#field_idents.table_filter_fetch(_table_row))*
|
||||
unsafe fn table_filter_fetch<'__w>(_fetch: &mut <Self as #path::query::WorldQueryGats<'__w>>::Fetch, _table_row: usize) -> bool {
|
||||
true #(&& <#field_types>::table_filter_fetch(&mut _fetch.#field_idents, _table_row))*
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
#[inline]
|
||||
unsafe fn archetype_filter_fetch(&mut self, _archetype_index: usize) -> bool {
|
||||
true #(&& self.#field_idents.archetype_filter_fetch(_archetype_index))*
|
||||
unsafe fn archetype_filter_fetch<'__w>(_fetch: &mut <Self as #path::query::WorldQueryGats<'__w>>::Fetch, _archetype_index: usize) -> bool {
|
||||
true #(&& <#field_types>::archetype_filter_fetch(&mut _fetch.#field_idents, _archetype_index))*
|
||||
}
|
||||
|
||||
fn update_component_access(state: &Self::State, _access: &mut #path::query::FilteredAccess<#path::component::ComponentId>) {
|
||||
#( #path::query::#fetch_type_alias::<'static, #field_types> :: update_component_access(&state.#field_idents, _access); )*
|
||||
#( <#field_types>::update_component_access(&state.#field_idents, _access); )*
|
||||
}
|
||||
|
||||
fn update_archetype_component_access(state: &Self::State, _archetype: &#path::archetype::Archetype, _access: &mut #path::query::Access<#path::archetype::ArchetypeComponentId>) {
|
||||
fn update_archetype_component_access(
|
||||
state: &Self::State,
|
||||
_archetype: &#path::archetype::Archetype,
|
||||
_access: &mut #path::query::Access<#path::archetype::ArchetypeComponentId>
|
||||
) {
|
||||
#(
|
||||
#path::query::#fetch_type_alias::<'static, #field_types>
|
||||
:: update_archetype_component_access(&state.#field_idents, _archetype, _access);
|
||||
<#field_types>::update_archetype_component_access(&state.#field_idents, _archetype, _access);
|
||||
)*
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let fetch_impl = impl_fetch(false, fetch_struct_name.clone(), item_struct_name.clone());
|
||||
fn init_state(world: &mut #path::world::World) -> #state_struct_name #user_ty_generics {
|
||||
#state_struct_name {
|
||||
#(#field_idents: <#field_types>::init_state(world),)*
|
||||
#(#ignored_field_idents: Default::default(),)*
|
||||
}
|
||||
}
|
||||
|
||||
let state_impl = quote! {
|
||||
#[doc(hidden)]
|
||||
#visibility struct #state_struct_name #user_impl_generics #user_where_clauses {
|
||||
|
||||
#(#field_idents: <#field_types as #path::query::WorldQuery>::State,)*
|
||||
#(#ignored_field_idents: #ignored_field_types,)*
|
||||
}
|
||||
|
||||
impl #user_impl_generics #path::query::FetchState for #state_struct_name #user_ty_generics #user_where_clauses {
|
||||
fn init(world: &mut #path::world::World) -> Self {
|
||||
#state_struct_name {
|
||||
#(#field_idents: <<#field_types as #path::query::WorldQuery>::State as #path::query::FetchState>::init(world),)*
|
||||
#(#ignored_field_idents: Default::default(),)*
|
||||
fn matches_component_set(state: &Self::State, _set_contains_id: &impl Fn(#path::component::ComponentId) -> bool) -> bool {
|
||||
true #(&& <#field_types>::matches_component_set(&state.#field_idents, _set_contains_id))*
|
||||
}
|
||||
}
|
||||
|
||||
fn matches_component_set(&self, _set_contains_id: &impl Fn(#path::component::ComponentId) -> bool) -> bool {
|
||||
true #(&& self.#field_idents.matches_component_set(_set_contains_id))*
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let read_only_fetch_impl = if fetch_struct_attributes.is_mutable {
|
||||
impl_fetch(
|
||||
true,
|
||||
read_only_fetch_struct_name.clone(),
|
||||
read_only_item_struct_name.clone(),
|
||||
)
|
||||
} else {
|
||||
quote! {}
|
||||
};
|
||||
|
||||
let read_only_world_query_impl = if fetch_struct_attributes.is_mutable {
|
||||
let mutable_impl = impl_fetch(false);
|
||||
let readonly_impl = if fetch_struct_attributes.is_mutable {
|
||||
let world_query_impl = impl_fetch(true);
|
||||
quote! {
|
||||
#[automatically_derived]
|
||||
#visibility struct #read_only_struct_name #user_impl_generics #user_where_clauses {
|
||||
#( #field_idents: < #field_types as #path::query::WorldQuery >::ReadOnly, )*
|
||||
#( #field_idents: #read_only_field_types, )*
|
||||
#(#(#ignored_field_attrs)* #ignored_field_visibilities #ignored_field_idents: #ignored_field_types,)*
|
||||
}
|
||||
|
||||
// SAFETY: `ROQueryFetch<Self>` is the same as `QueryFetch<Self>`
|
||||
unsafe impl #user_impl_generics #path::query::WorldQuery for #read_only_struct_name #user_ty_generics #user_where_clauses {
|
||||
type ReadOnly = Self;
|
||||
type State = #state_struct_name #user_ty_generics;
|
||||
|
||||
fn shrink<'__wlong: '__wshort, '__wshort>(item: #path::query::#item_type_alias<'__wlong, Self>)
|
||||
-> #path::query::#item_type_alias<'__wshort, Self> {
|
||||
#read_only_item_struct_name {
|
||||
#(
|
||||
#field_idents : <
|
||||
< #field_types as #path::query::WorldQuery >::ReadOnly as #path::query::WorldQuery
|
||||
> :: shrink( item.#field_idents ),
|
||||
)*
|
||||
#(
|
||||
#ignored_field_idents: item.#ignored_field_idents,
|
||||
)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl #user_impl_generics_with_world #path::query::WorldQueryGats<'__w> for #read_only_struct_name #user_ty_generics #user_where_clauses {
|
||||
type Fetch = #read_only_fetch_struct_name #user_ty_generics_with_world;
|
||||
type _State = #state_struct_name #user_ty_generics;
|
||||
}
|
||||
#world_query_impl
|
||||
}
|
||||
} else {
|
||||
quote! {}
|
||||
|
@ -347,7 +349,7 @@ pub fn derive_world_query_impl(ast: DeriveInput) -> TokenStream {
|
|||
// Double-check that the data fetched by `<_ as WorldQuery>::ReadOnly` is read-only.
|
||||
// This is technically unnecessary as `<_ as WorldQuery>::ReadOnly: ReadOnlyWorldQuery`
|
||||
// but to protect against future mistakes we assert the assoc type implements `ReadOnlyWorldQuery` anyway
|
||||
#( assert_readonly::< < #field_types as #path::query::WorldQuery > :: ReadOnly >(); )*
|
||||
#( assert_readonly::<#read_only_field_types>(); )*
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
|
@ -363,38 +365,17 @@ pub fn derive_world_query_impl(ast: DeriveInput) -> TokenStream {
|
|||
};
|
||||
|
||||
TokenStream::from(quote! {
|
||||
#fetch_impl
|
||||
#mutable_impl
|
||||
|
||||
#state_impl
|
||||
#readonly_impl
|
||||
|
||||
#read_only_fetch_impl
|
||||
|
||||
#read_only_world_query_impl
|
||||
|
||||
// SAFETY: if the worldquery is mutable this defers to soundness of the `#field_types: WorldQuery` impl, otherwise
|
||||
// if the world query is immutable then `#read_only_struct_name #user_ty_generics` is the same type as `#struct_name #user_ty_generics`
|
||||
unsafe impl #user_impl_generics #path::query::WorldQuery for #struct_name #user_ty_generics #user_where_clauses {
|
||||
type ReadOnly = #read_only_struct_name #user_ty_generics;
|
||||
type State = #state_struct_name #user_ty_generics;
|
||||
fn shrink<'__wlong: '__wshort, '__wshort>(item: #path::query::#item_type_alias<'__wlong, Self>)
|
||||
-> #path::query::#item_type_alias<'__wshort, Self> {
|
||||
#item_struct_name {
|
||||
#(
|
||||
#field_idents : < #field_types as #path::query::WorldQuery> :: shrink( item.#field_idents ),
|
||||
)*
|
||||
#(
|
||||
#ignored_field_idents: item.#ignored_field_idents,
|
||||
)*
|
||||
}
|
||||
}
|
||||
#[doc(hidden)]
|
||||
#visibility struct #state_struct_name #user_impl_generics #user_where_clauses {
|
||||
#(#field_idents: <#field_types as #path::query::WorldQuery>::State,)*
|
||||
#(#ignored_field_idents: #ignored_field_types,)*
|
||||
}
|
||||
|
||||
impl #user_impl_generics_with_world #path::query::WorldQueryGats<'__w> for #struct_name #user_ty_generics #user_where_clauses {
|
||||
type Fetch = #fetch_struct_name #user_ty_generics_with_world;
|
||||
type _State = #state_struct_name #user_ty_generics;
|
||||
}
|
||||
|
||||
/// SAFETY: each item in the struct is read only
|
||||
/// SAFETY: we assert fields are readonly below
|
||||
unsafe impl #user_impl_generics #path::query::ReadOnlyWorldQuery
|
||||
for #read_only_struct_name #user_ty_generics #user_where_clauses {}
|
||||
|
||||
|
@ -417,9 +398,15 @@ pub fn derive_world_query_impl(ast: DeriveInput) -> TokenStream {
|
|||
// workaround.
|
||||
#[allow(dead_code)]
|
||||
const _: () = {
|
||||
fn dead_code_workaround #user_impl_generics (q: #struct_name #user_ty_generics) #user_where_clauses {
|
||||
fn dead_code_workaround #user_impl_generics (
|
||||
q: #struct_name #user_ty_generics,
|
||||
q2: #read_only_struct_name #user_ty_generics
|
||||
) #user_where_clauses {
|
||||
#(q.#field_idents;)*
|
||||
#(q.#ignored_field_idents;)*
|
||||
#(q2.#field_idents;)*
|
||||
#(q2.#ignored_field_idents;)*
|
||||
|
||||
}
|
||||
};
|
||||
})
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -3,8 +3,7 @@ use crate::{
|
|||
component::{Component, ComponentId, ComponentStorage, ComponentTicks, StorageType},
|
||||
entity::Entity,
|
||||
query::{
|
||||
debug_checked_unreachable, Access, Fetch, FetchState, FilteredAccess, QueryFetch,
|
||||
WorldQuery, WorldQueryGats,
|
||||
debug_checked_unreachable, Access, FilteredAccess, QueryFetch, WorldQuery, WorldQueryGats,
|
||||
},
|
||||
storage::{ComponentSparseSet, Table, Tables},
|
||||
world::World,
|
||||
|
@ -44,65 +43,27 @@ use super::ReadOnlyWorldQuery;
|
|||
/// ```
|
||||
pub struct With<T>(PhantomData<T>);
|
||||
|
||||
impl<T: Component> WorldQueryGats<'_> for With<T> {
|
||||
type Fetch = ();
|
||||
type Item = ();
|
||||
}
|
||||
|
||||
// SAFETY: `ROQueryFetch<Self>` is the same as `QueryFetch<Self>`
|
||||
unsafe impl<T: Component> WorldQuery for With<T> {
|
||||
type ReadOnly = Self;
|
||||
type State = WithState<T>;
|
||||
type State = ComponentId;
|
||||
|
||||
#[allow(clippy::semicolon_if_nothing_returned)]
|
||||
fn shrink<'wlong: 'wshort, 'wshort>(
|
||||
item: super::QueryItem<'wlong, Self>,
|
||||
) -> super::QueryItem<'wshort, Self> {
|
||||
item
|
||||
}
|
||||
}
|
||||
|
||||
/// The [`Fetch`] of [`With`].
|
||||
#[doc(hidden)]
|
||||
pub struct WithFetch<T> {
|
||||
marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
/// The [`FetchState`] of [`With`].
|
||||
#[doc(hidden)]
|
||||
pub struct WithState<T> {
|
||||
component_id: ComponentId,
|
||||
marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: Component> FetchState for WithState<T> {
|
||||
fn init(world: &mut World) -> Self {
|
||||
let component_id = world.init_component::<T>();
|
||||
Self {
|
||||
component_id,
|
||||
marker: PhantomData,
|
||||
}
|
||||
_: <Self as WorldQueryGats<'wlong>>::Item,
|
||||
) -> <Self as WorldQueryGats<'wshort>>::Item {
|
||||
}
|
||||
|
||||
fn matches_component_set(&self, set_contains_id: &impl Fn(ComponentId) -> bool) -> bool {
|
||||
set_contains_id(self.component_id)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Component> WorldQueryGats<'_> for With<T> {
|
||||
type Fetch = WithFetch<T>;
|
||||
type _State = WithState<T>;
|
||||
}
|
||||
|
||||
// SAFETY: no component access or archetype component access
|
||||
unsafe impl<'w, T: Component> Fetch<'w> for WithFetch<T> {
|
||||
type Item = ();
|
||||
type State = WithState<T>;
|
||||
|
||||
unsafe fn init(
|
||||
unsafe fn init_fetch(
|
||||
_world: &World,
|
||||
_state: &WithState<T>,
|
||||
_state: &ComponentId,
|
||||
_last_change_tick: u32,
|
||||
_change_tick: u32,
|
||||
) -> Self {
|
||||
Self {
|
||||
marker: PhantomData,
|
||||
}
|
||||
) {
|
||||
}
|
||||
|
||||
const IS_DENSE: bool = {
|
||||
|
@ -115,50 +76,59 @@ unsafe impl<'w, T: Component> Fetch<'w> for WithFetch<T> {
|
|||
const IS_ARCHETYPAL: bool = true;
|
||||
|
||||
#[inline]
|
||||
unsafe fn set_table(&mut self, _state: &Self::State, _table: &Table) {}
|
||||
unsafe fn set_table(_fetch: &mut (), _state: &ComponentId, _table: &Table) {}
|
||||
|
||||
#[inline]
|
||||
unsafe fn set_archetype(
|
||||
&mut self,
|
||||
_state: &Self::State,
|
||||
_fetch: &mut (),
|
||||
_state: &ComponentId,
|
||||
_archetype: &Archetype,
|
||||
_tables: &Tables,
|
||||
) {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn archetype_fetch(&mut self, _archetype_index: usize) {}
|
||||
unsafe fn archetype_fetch<'w>(
|
||||
_fetch: &mut <Self as WorldQueryGats<'w>>::Fetch,
|
||||
_archetype_index: usize,
|
||||
) -> <Self as WorldQueryGats<'w>>::Item {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn table_fetch(&mut self, _table_row: usize) {}
|
||||
unsafe fn table_fetch<'w>(
|
||||
_fetch: &mut <Self as WorldQueryGats<'w>>::Fetch,
|
||||
_table_row: usize,
|
||||
) -> <Self as WorldQueryGats<'w>>::Item {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn update_component_access(state: &Self::State, access: &mut FilteredAccess<ComponentId>) {
|
||||
access.add_with(state.component_id);
|
||||
fn update_component_access(&id: &ComponentId, access: &mut FilteredAccess<ComponentId>) {
|
||||
access.add_with(id);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn update_archetype_component_access(
|
||||
_state: &Self::State,
|
||||
_state: &ComponentId,
|
||||
_archetype: &Archetype,
|
||||
_access: &mut Access<ArchetypeComponentId>,
|
||||
) {
|
||||
}
|
||||
|
||||
fn init_state(world: &mut World) -> ComponentId {
|
||||
world.init_component::<T>()
|
||||
}
|
||||
|
||||
fn matches_component_set(
|
||||
&id: &ComponentId,
|
||||
set_contains_id: &impl Fn(ComponentId) -> bool,
|
||||
) -> bool {
|
||||
set_contains_id(id)
|
||||
}
|
||||
}
|
||||
|
||||
// SAFETY: no component access or archetype component access
|
||||
unsafe impl<T: Component> ReadOnlyWorldQuery for With<T> {}
|
||||
|
||||
impl<T> Clone for WithFetch<T> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
marker: self.marker,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Copy for WithFetch<T> {}
|
||||
|
||||
/// Filter that selects entities without a component `T`.
|
||||
///
|
||||
/// This is the negation of [`With`].
|
||||
|
@ -188,62 +158,19 @@ pub struct Without<T>(PhantomData<T>);
|
|||
// SAFETY: `ROQueryFetch<Self>` is the same as `QueryFetch<Self>`
|
||||
unsafe impl<T: Component> WorldQuery for Without<T> {
|
||||
type ReadOnly = Self;
|
||||
type State = WithoutState<T>;
|
||||
type State = ComponentId;
|
||||
|
||||
#[allow(clippy::semicolon_if_nothing_returned)]
|
||||
fn shrink<'wlong: 'wshort, 'wshort>(
|
||||
item: super::QueryItem<'wlong, Self>,
|
||||
) -> super::QueryItem<'wshort, Self> {
|
||||
item
|
||||
}
|
||||
}
|
||||
|
||||
/// The [`Fetch`] of [`Without`].
|
||||
#[doc(hidden)]
|
||||
pub struct WithoutFetch<T> {
|
||||
marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
/// The [`FetchState`] of [`Without`].
|
||||
#[doc(hidden)]
|
||||
pub struct WithoutState<T> {
|
||||
component_id: ComponentId,
|
||||
marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: Component> FetchState for WithoutState<T> {
|
||||
fn init(world: &mut World) -> Self {
|
||||
let component_id = world.init_component::<T>();
|
||||
Self {
|
||||
component_id,
|
||||
marker: PhantomData,
|
||||
}
|
||||
_: <Self as WorldQueryGats<'wlong>>::Item,
|
||||
) -> <Self as WorldQueryGats<'wshort>>::Item {
|
||||
}
|
||||
|
||||
fn matches_component_set(&self, set_contains_id: &impl Fn(ComponentId) -> bool) -> bool {
|
||||
!set_contains_id(self.component_id)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Component> WorldQueryGats<'_> for Without<T> {
|
||||
type Fetch = WithoutFetch<T>;
|
||||
type _State = WithoutState<T>;
|
||||
}
|
||||
|
||||
// SAFETY: no component access or archetype component access
|
||||
unsafe impl<'w, T: Component> Fetch<'w> for WithoutFetch<T> {
|
||||
type Item = ();
|
||||
type State = WithoutState<T>;
|
||||
|
||||
unsafe fn init(
|
||||
unsafe fn init_fetch(
|
||||
_world: &World,
|
||||
_state: &WithoutState<T>,
|
||||
_state: &ComponentId,
|
||||
_last_change_tick: u32,
|
||||
_change_tick: u32,
|
||||
) -> Self {
|
||||
WithoutFetch {
|
||||
marker: PhantomData,
|
||||
}
|
||||
) {
|
||||
}
|
||||
|
||||
const IS_DENSE: bool = {
|
||||
|
@ -256,50 +183,64 @@ unsafe impl<'w, T: Component> Fetch<'w> for WithoutFetch<T> {
|
|||
const IS_ARCHETYPAL: bool = true;
|
||||
|
||||
#[inline]
|
||||
unsafe fn set_table(&mut self, _state: &Self::State, _table: &Table) {}
|
||||
unsafe fn set_table(_fetch: &mut (), _state: &Self::State, _table: &Table) {}
|
||||
|
||||
#[inline]
|
||||
unsafe fn set_archetype(
|
||||
&mut self,
|
||||
_state: &Self::State,
|
||||
_fetch: &mut (),
|
||||
_state: &ComponentId,
|
||||
_archetype: &Archetype,
|
||||
_tables: &Tables,
|
||||
) {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn archetype_fetch(&mut self, _archetype_index: usize) {}
|
||||
unsafe fn archetype_fetch<'w>(
|
||||
_fetch: &mut <Self as WorldQueryGats<'w>>::Fetch,
|
||||
_archetype_index: usize,
|
||||
) -> <Self as WorldQueryGats<'w>>::Item {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn table_fetch(&mut self, _table_row: usize) {}
|
||||
unsafe fn table_fetch<'w>(
|
||||
_fetch: &mut <Self as WorldQueryGats<'w>>::Fetch,
|
||||
_table_row: usize,
|
||||
) -> <Self as WorldQueryGats<'w>>::Item {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn update_component_access(state: &Self::State, access: &mut FilteredAccess<ComponentId>) {
|
||||
access.add_without(state.component_id);
|
||||
fn update_component_access(&id: &ComponentId, access: &mut FilteredAccess<ComponentId>) {
|
||||
access.add_without(id);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn update_archetype_component_access(
|
||||
_state: &Self::State,
|
||||
_state: &ComponentId,
|
||||
_archetype: &Archetype,
|
||||
_access: &mut Access<ArchetypeComponentId>,
|
||||
) {
|
||||
}
|
||||
|
||||
fn init_state(world: &mut World) -> ComponentId {
|
||||
world.init_component::<T>()
|
||||
}
|
||||
|
||||
fn matches_component_set(
|
||||
&id: &ComponentId,
|
||||
set_contains_id: &impl Fn(ComponentId) -> bool,
|
||||
) -> bool {
|
||||
!set_contains_id(id)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Component> WorldQueryGats<'_> for Without<T> {
|
||||
type Fetch = ();
|
||||
type Item = ();
|
||||
}
|
||||
|
||||
// SAFETY: no component access or archetype component access
|
||||
unsafe impl<T: Component> ReadOnlyWorldQuery for Without<T> {}
|
||||
|
||||
impl<T> Clone for WithoutFetch<T> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
marker: self.marker,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Copy for WithoutFetch<T> {}
|
||||
|
||||
/// A filter that tests if any of the given filters apply.
|
||||
///
|
||||
/// This is useful for example if a system with multiple components in a query only wants to run
|
||||
|
@ -333,104 +274,106 @@ impl<T> Copy for WithoutFetch<T> {}
|
|||
#[derive(Clone, Copy)]
|
||||
pub struct Or<T>(pub T);
|
||||
|
||||
/// The [`Fetch`] of [`Or`].
|
||||
#[derive(Clone, Copy)]
|
||||
#[doc(hidden)]
|
||||
pub struct OrFetch<'w, T: Fetch<'w>> {
|
||||
fetch: T,
|
||||
pub struct OrFetch<'w, T: WorldQuery> {
|
||||
fetch: QueryFetch<'w, T>,
|
||||
matches: bool,
|
||||
_marker: PhantomData<&'w ()>,
|
||||
}
|
||||
impl<'w, T: WorldQuery> Copy for OrFetch<'w, T> where QueryFetch<'w, T>: Copy {}
|
||||
impl<'w, T: WorldQuery> Clone for OrFetch<'w, T>
|
||||
where
|
||||
QueryFetch<'w, T>: Clone,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
fetch: self.fetch.clone(),
|
||||
matches: self.matches,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_query_filter_tuple {
|
||||
($(($filter: ident, $state: ident)),*) => {
|
||||
#[allow(unused_variables)]
|
||||
#[allow(non_snake_case)]
|
||||
impl<'w, $($filter: WorldQuery),*> WorldQueryGats<'w> for Or<($($filter,)*)> {
|
||||
type Fetch = ($(OrFetch<'w, $filter>,)*);
|
||||
type Item = bool;
|
||||
}
|
||||
|
||||
|
||||
#[allow(unused_variables)]
|
||||
#[allow(non_snake_case)]
|
||||
#[allow(clippy::unused_unit)]
|
||||
// SAFETY: defers to soundness of `$filter: WorldQuery` impl
|
||||
unsafe impl<$($filter: WorldQuery),*> WorldQuery for Or<($($filter,)*)> {
|
||||
type ReadOnly = Or<($($filter::ReadOnly,)*)>;
|
||||
type State = Or<($($filter::State,)*)>;
|
||||
type State = ($($filter::State,)*);
|
||||
|
||||
fn shrink<'wlong: 'wshort, 'wshort>(item: super::QueryItem<'wlong, Self>) -> super::QueryItem<'wshort, Self> {
|
||||
item
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
#[allow(non_snake_case)]
|
||||
impl<'w, $($filter: WorldQueryGats<'w>),*> WorldQueryGats<'w> for Or<($($filter,)*)> {
|
||||
type Fetch = Or<($(OrFetch<'w, QueryFetch<'w, $filter>>,)*)>;
|
||||
type _State = Or<($($filter::_State,)*)>;
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
#[allow(non_snake_case)]
|
||||
// SAFETY: update_component_access and update_archetype_component_access are called for each item in the tuple
|
||||
unsafe impl<'w, $($filter: Fetch<'w>),*> Fetch<'w> for Or<($(OrFetch<'w, $filter>,)*)> {
|
||||
type State = Or<($(<$filter as Fetch<'w>>::State,)*)>;
|
||||
type Item = bool;
|
||||
|
||||
const IS_DENSE: bool = true $(&& $filter::IS_DENSE)*;
|
||||
|
||||
const IS_ARCHETYPAL: bool = true $(&& $filter::IS_ARCHETYPAL)*;
|
||||
|
||||
unsafe fn init(world: &'w World, state: & Or<($(<$filter as Fetch<'w>>::State,)*)>, last_change_tick: u32, change_tick: u32) -> Self {
|
||||
let ($($filter,)*) = &state.0;
|
||||
Or(($(OrFetch {
|
||||
fetch: <$filter as Fetch<'w>>::init(world, $filter, last_change_tick, change_tick),
|
||||
unsafe fn init_fetch<'w>(world: &'w World, state: &Self::State, last_change_tick: u32, change_tick: u32) -> <Self as WorldQueryGats<'w>>::Fetch {
|
||||
let ($($filter,)*) = state;
|
||||
($(OrFetch {
|
||||
fetch: $filter::init_fetch(world, $filter, last_change_tick, change_tick),
|
||||
matches: false,
|
||||
_marker: PhantomData,
|
||||
},)*))
|
||||
},)*)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn set_table(&mut self, state: &Self::State, table: &'w Table) {
|
||||
let ($($filter,)*) = &mut self.0;
|
||||
let ($($state,)*) = &state.0;
|
||||
unsafe fn set_table<'w>(fetch: &mut <Self as WorldQueryGats<'w>>::Fetch, state: &Self::State, table: &'w Table) {
|
||||
let ($($filter,)*) = fetch;
|
||||
let ($($state,)*) = state;
|
||||
$(
|
||||
$filter.matches = $state.matches_component_set(&|id| table.has_column(id));
|
||||
$filter.matches = $filter::matches_component_set($state, &|id| table.has_column(id));
|
||||
if $filter.matches {
|
||||
$filter.fetch.set_table($state, table);
|
||||
$filter::set_table(&mut $filter.fetch, $state, table);
|
||||
}
|
||||
)*
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn set_archetype(&mut self, state: & Self::State, archetype: &'w Archetype, tables: &'w Tables) {
|
||||
let ($($filter,)*) = &mut self.0;
|
||||
let ($($state,)*) = &state.0;
|
||||
unsafe fn set_archetype<'w>(fetch: &mut <Self as WorldQueryGats<'w>>::Fetch, state: &Self::State, archetype: &'w Archetype, tables: &'w Tables) {
|
||||
let ($($filter,)*) = fetch;
|
||||
let ($($state,)*) = state;
|
||||
$(
|
||||
$filter.matches = $state.matches_component_set(&|id| archetype.contains(id));
|
||||
$filter.matches = $filter::matches_component_set($state, &|id| archetype.contains(id));
|
||||
if $filter.matches {
|
||||
$filter.fetch.set_archetype($state, archetype, tables);
|
||||
$filter::set_archetype(&mut $filter.fetch, $state, archetype, tables);
|
||||
}
|
||||
)*
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn table_fetch(&mut self, table_row: usize) -> bool {
|
||||
let ($($filter,)*) = &mut self.0;
|
||||
false $(|| ($filter.matches && $filter.fetch.table_filter_fetch(table_row)))*
|
||||
unsafe fn table_fetch<'w>(fetch: &mut <Self as WorldQueryGats<'w>>::Fetch, table_row: usize) -> <Self as WorldQueryGats<'w>>::Item {
|
||||
let ($($filter,)*) = fetch;
|
||||
false $(|| ($filter.matches && $filter::table_filter_fetch(&mut $filter.fetch, table_row)))*
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn archetype_fetch(&mut self, archetype_index: usize) -> bool {
|
||||
let ($($filter,)*) = &mut self.0;
|
||||
false $(|| ($filter.matches && $filter.fetch.archetype_filter_fetch(archetype_index)))*
|
||||
unsafe fn archetype_fetch<'w>(fetch: &mut <Self as WorldQueryGats<'w>>::Fetch, archetype_index: usize) -> <Self as WorldQueryGats<'w>>::Item {
|
||||
let ($($filter,)*) = fetch;
|
||||
false $(|| ($filter.matches && $filter::archetype_filter_fetch(&mut $filter.fetch, archetype_index)))*
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn table_filter_fetch(&mut self, table_row: usize) -> bool {
|
||||
self.table_fetch(table_row)
|
||||
unsafe fn table_filter_fetch(fetch: &mut QueryFetch<'_, Self>, table_row: usize) -> bool {
|
||||
Self::table_fetch(fetch, table_row)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn archetype_filter_fetch(&mut self, archetype_index: usize) -> bool {
|
||||
self.archetype_fetch(archetype_index)
|
||||
unsafe fn archetype_filter_fetch(fetch: &mut QueryFetch<'_, Self>, archetype_index: usize) -> bool {
|
||||
Self::archetype_fetch(fetch, archetype_index)
|
||||
}
|
||||
|
||||
fn update_component_access(state: &Self::State, access: &mut FilteredAccess<ComponentId>) {
|
||||
let ($($filter,)*) = &state.0;
|
||||
let ($($filter,)*) = state;
|
||||
|
||||
// We do not unconditionally add `$filter`'s `with`/`without` accesses to `access`
|
||||
// as this would be unsound. For example the following two queries should conflict:
|
||||
|
@ -462,21 +405,17 @@ macro_rules! impl_query_filter_tuple {
|
|||
}
|
||||
|
||||
fn update_archetype_component_access(state: &Self::State, archetype: &Archetype, access: &mut Access<ArchetypeComponentId>) {
|
||||
let ($($filter,)*) = &state.0;
|
||||
let ($($filter,)*) = state;
|
||||
$($filter::update_archetype_component_access($filter, archetype, access);)*
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
#[allow(non_snake_case)]
|
||||
impl<$($filter: FetchState),*> FetchState for Or<($($filter,)*)> {
|
||||
fn init(world: &mut World) -> Self {
|
||||
Or(($($filter::init(world),)*))
|
||||
fn init_state(world: &mut World) -> Self::State {
|
||||
($($filter::init_state(world),)*)
|
||||
}
|
||||
|
||||
fn matches_component_set(&self, _set_contains_id: &impl Fn(ComponentId) -> bool) -> bool {
|
||||
let ($($filter,)*) = &self.0;
|
||||
false $(|| $filter.matches_component_set(_set_contains_id))*
|
||||
fn matches_component_set(_state: &Self::State, _set_contains_id: &impl Fn(ComponentId) -> bool) -> bool {
|
||||
let ($($filter,)*) = _state;
|
||||
false $(|| $filter::matches_component_set($filter, _set_contains_id))*
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -491,8 +430,6 @@ macro_rules! impl_tick_filter {
|
|||
(
|
||||
$(#[$meta:meta])*
|
||||
$name: ident,
|
||||
$(#[$state_meta:meta])*
|
||||
$state_name: ident,
|
||||
$(#[$fetch_meta:meta])*
|
||||
$fetch_name: ident,
|
||||
$is_detected: expr
|
||||
|
@ -512,53 +449,22 @@ macro_rules! impl_tick_filter {
|
|||
change_tick: u32,
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
$(#[$state_meta])*
|
||||
pub struct $state_name<T> {
|
||||
component_id: ComponentId,
|
||||
marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
// SAFETY: `ROQueryFetch<Self>` is the same as `QueryFetch<Self>`
|
||||
unsafe impl<T: Component> WorldQuery for $name<T> {
|
||||
type ReadOnly = Self;
|
||||
type State = $state_name<T>;
|
||||
type State = ComponentId;
|
||||
|
||||
fn shrink<'wlong: 'wshort, 'wshort>(item: super::QueryItem<'wlong, Self>) -> super::QueryItem<'wshort, Self> {
|
||||
item
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Component> FetchState for $state_name<T> {
|
||||
fn init(world: &mut World) -> Self {
|
||||
Self {
|
||||
component_id: world.init_component::<T>(),
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
fn matches_component_set(&self, set_contains_id: &impl Fn(ComponentId) -> bool) -> bool {
|
||||
set_contains_id(self.component_id)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'w, T: Component> WorldQueryGats<'w> for $name<T> {
|
||||
type Fetch = $fetch_name<'w, T>;
|
||||
type _State = $state_name<T>;
|
||||
}
|
||||
|
||||
// SAFETY: this reads the T component. archetype component access and component access are updated to reflect that
|
||||
unsafe impl<'w, T: Component> Fetch<'w> for $fetch_name<'w, T> {
|
||||
type State = $state_name<T>;
|
||||
type Item = bool;
|
||||
|
||||
unsafe fn init(world: &'w World, state: & $state_name<T>, last_change_tick: u32, change_tick: u32) -> Self {
|
||||
Self {
|
||||
unsafe fn init_fetch<'w>(world: &'w World, &id: &ComponentId, last_change_tick: u32, change_tick: u32) -> <Self as WorldQueryGats<'w>>::Fetch {
|
||||
QueryFetch::<'w, Self> {
|
||||
table_ticks: None,
|
||||
entities: None,
|
||||
entity_table_rows: None,
|
||||
sparse_set: (T::Storage::STORAGE_TYPE == StorageType::SparseSet)
|
||||
.then(|| world.storages().sparse_sets.get(state.component_id).unwrap()),
|
||||
.then(|| world.storages().sparse_sets.get(id).unwrap()),
|
||||
marker: PhantomData,
|
||||
last_change_tick,
|
||||
change_tick,
|
||||
|
@ -574,74 +480,87 @@ macro_rules! impl_tick_filter {
|
|||
|
||||
const IS_ARCHETYPAL: bool = false;
|
||||
|
||||
unsafe fn set_table(&mut self, state: &Self::State, table: &'w Table) {
|
||||
self.table_ticks = Some(table.get_column(state.component_id).unwrap().get_ticks_slice().into());
|
||||
unsafe fn set_table<'w>(fetch: &mut <Self as WorldQueryGats<'w>>::Fetch, &id: &ComponentId, table: &'w Table) {
|
||||
fetch.table_ticks = Some(table.get_column(id).unwrap().get_ticks_slice().into());
|
||||
}
|
||||
|
||||
unsafe fn set_archetype(&mut self, state: &Self::State, archetype: &'w Archetype, tables: &'w Tables) {
|
||||
unsafe fn set_archetype<'w>(fetch: &mut <Self as WorldQueryGats<'w>>::Fetch, &id: &ComponentId, archetype: &'w Archetype, tables: &'w Tables) {
|
||||
match T::Storage::STORAGE_TYPE {
|
||||
StorageType::Table => {
|
||||
self.entity_table_rows = Some(archetype.entity_table_rows().into());
|
||||
fetch.entity_table_rows = Some(archetype.entity_table_rows().into());
|
||||
let table = &tables[archetype.table_id()];
|
||||
self.table_ticks = Some(table.get_column(state.component_id).unwrap().get_ticks_slice().into());
|
||||
fetch.table_ticks = Some(table.get_column(id).unwrap().get_ticks_slice().into());
|
||||
}
|
||||
StorageType::SparseSet => self.entities = Some(archetype.entities().into()),
|
||||
StorageType::SparseSet => fetch.entities = Some(archetype.entities().into()),
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn table_fetch(&mut self, table_row: usize) -> bool {
|
||||
$is_detected(&*(self.table_ticks.unwrap_or_else(|| debug_checked_unreachable()).get(table_row)).deref(), self.last_change_tick, self.change_tick)
|
||||
unsafe fn table_fetch<'w>(fetch: &mut <Self as WorldQueryGats<'w>>::Fetch, table_row: usize) -> <Self as WorldQueryGats<'w>>::Item {
|
||||
$is_detected(&*(fetch.table_ticks.unwrap_or_else(|| debug_checked_unreachable()).get(table_row)).deref(), fetch.last_change_tick, fetch.change_tick)
|
||||
}
|
||||
|
||||
unsafe fn archetype_fetch(&mut self, archetype_index: usize) -> bool {
|
||||
unsafe fn archetype_fetch<'w>(fetch: &mut <Self as WorldQueryGats<'w>>::Fetch, archetype_index: usize) -> <Self as WorldQueryGats<'w>>::Item {
|
||||
match T::Storage::STORAGE_TYPE {
|
||||
StorageType::Table => {
|
||||
let table_row = *self.entity_table_rows.unwrap_or_else(|| debug_checked_unreachable()).get(archetype_index);
|
||||
$is_detected(&*(self.table_ticks.unwrap_or_else(|| debug_checked_unreachable()).get(table_row)).deref(), self.last_change_tick, self.change_tick)
|
||||
let table_row = *fetch.entity_table_rows.unwrap_or_else(|| debug_checked_unreachable()).get(archetype_index);
|
||||
$is_detected(&*(fetch.table_ticks.unwrap_or_else(|| debug_checked_unreachable()).get(table_row)).deref(), fetch.last_change_tick, fetch.change_tick)
|
||||
}
|
||||
StorageType::SparseSet => {
|
||||
let entity = *self.entities.unwrap_or_else(|| debug_checked_unreachable()).get(archetype_index);
|
||||
let ticks = self
|
||||
let entity = *fetch.entities.unwrap_or_else(|| debug_checked_unreachable()).get(archetype_index);
|
||||
let ticks = fetch
|
||||
.sparse_set
|
||||
.unwrap_or_else(|| debug_checked_unreachable())
|
||||
.get_ticks(entity)
|
||||
.map(|ticks| &*ticks.get())
|
||||
.cloned()
|
||||
.unwrap();
|
||||
$is_detected(&ticks, self.last_change_tick, self.change_tick)
|
||||
$is_detected(&ticks, fetch.last_change_tick, fetch.change_tick)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn table_filter_fetch(&mut self, table_row: usize) -> bool {
|
||||
self.table_fetch(table_row)
|
||||
unsafe fn table_filter_fetch(fetch: &mut QueryFetch<'_, Self>, table_row: usize) -> bool {
|
||||
Self::table_fetch(fetch, table_row)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn archetype_filter_fetch(&mut self, archetype_index: usize) -> bool {
|
||||
self.archetype_fetch(archetype_index)
|
||||
unsafe fn archetype_filter_fetch(fetch: &mut QueryFetch<'_, Self>, archetype_index: usize) -> bool {
|
||||
Self::archetype_fetch(fetch, archetype_index)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn update_component_access(state: &Self::State, access: &mut FilteredAccess<ComponentId>) {
|
||||
if access.access().has_write(state.component_id) {
|
||||
fn update_component_access(&id: &ComponentId, access: &mut FilteredAccess<ComponentId>) {
|
||||
if access.access().has_write(id) {
|
||||
panic!("$state_name<{}> conflicts with a previous access in this query. Shared access cannot coincide with exclusive access.",
|
||||
std::any::type_name::<T>());
|
||||
}
|
||||
access.add_read(state.component_id);
|
||||
access.add_read(id);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn update_archetype_component_access(
|
||||
state: &Self::State,
|
||||
&id: &ComponentId,
|
||||
archetype: &Archetype,
|
||||
access: &mut Access<ArchetypeComponentId>,
|
||||
) {
|
||||
if let Some(archetype_component_id) = archetype.get_archetype_component_id(state.component_id) {
|
||||
if let Some(archetype_component_id) = archetype.get_archetype_component_id(id) {
|
||||
access.add_read(archetype_component_id);
|
||||
}
|
||||
}
|
||||
|
||||
fn init_state(world: &mut World) -> ComponentId {
|
||||
world.init_component::<T>()
|
||||
}
|
||||
|
||||
fn matches_component_set(&id: &ComponentId, set_contains_id: &impl Fn(ComponentId) -> bool) -> bool {
|
||||
set_contains_id(id)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'w, T: Component> WorldQueryGats<'w> for $name<T> {
|
||||
type Fetch = $fetch_name<'w, T>;
|
||||
type Item = bool;
|
||||
}
|
||||
|
||||
/// SAFETY: read-only access
|
||||
|
@ -693,9 +612,6 @@ impl_tick_filter!(
|
|||
/// # bevy_ecs::system::assert_is_system(print_add_name_component);
|
||||
/// ```
|
||||
Added,
|
||||
/// The [`FetchState`] of [`Added`].
|
||||
AddedState,
|
||||
/// The [`Fetch`] of [`Added`].
|
||||
AddedFetch,
|
||||
ComponentTicks::is_added
|
||||
);
|
||||
|
@ -733,9 +649,6 @@ impl_tick_filter!(
|
|||
/// # bevy_ecs::system::assert_is_system(print_moving_objects_system);
|
||||
/// ```
|
||||
Changed,
|
||||
/// The [`FetchState`] of [`Changed`].
|
||||
ChangedState,
|
||||
/// The [`Fetch`] of [`Changed`].
|
||||
ChangedFetch,
|
||||
ComponentTicks::is_changed
|
||||
);
|
||||
|
@ -745,7 +658,7 @@ impl_tick_filter!(
|
|||
/// This is needed to implement [`ExactSizeIterator`](std::iter::ExactSizeIterator) for
|
||||
/// [`QueryIter`](crate::query::QueryIter) that contains archetype-level filters.
|
||||
///
|
||||
/// The trait must only be implement for filters where its corresponding [`Fetch::IS_ARCHETYPAL`](crate::query::Fetch::IS_ARCHETYPAL)
|
||||
/// The trait must only be implement for filters where its corresponding [`WorldQuery::IS_ARCHETYPAL`](crate::query::WorldQuery::IS_ARCHETYPAL)
|
||||
/// is [`prim@true`]. As such, only the [`With`] and [`Without`] filters can implement the trait.
|
||||
/// [Tuples](prim@tuple) and [`Or`] filters are automatically implemented with the trait only if its containing types
|
||||
/// also implement the same trait.
|
||||
|
|
|
@ -2,7 +2,7 @@ use crate::{
|
|||
archetype::{ArchetypeId, Archetypes},
|
||||
entity::{Entities, Entity},
|
||||
prelude::World,
|
||||
query::{ArchetypeFilter, Fetch, QueryState, WorldQuery},
|
||||
query::{ArchetypeFilter, QueryState, WorldQuery},
|
||||
storage::{TableId, Tables},
|
||||
};
|
||||
use std::{borrow::Borrow, iter::FusedIterator, marker::PhantomData, mem::MaybeUninit};
|
||||
|
@ -63,7 +63,7 @@ impl<'w, 's, Q: WorldQuery, F: WorldQuery> Iterator for QueryIter<'w, 's, Q, F>
|
|||
.map(|id| self.archetypes[*id].len())
|
||||
.sum();
|
||||
|
||||
let archetype_query = Q::Fetch::IS_ARCHETYPAL && F::Fetch::IS_ARCHETYPAL;
|
||||
let archetype_query = Q::IS_ARCHETYPAL && F::IS_ARCHETYPAL;
|
||||
let min_size = if archetype_query { max_size } else { 0 };
|
||||
(min_size, Some(max_size))
|
||||
}
|
||||
|
@ -104,13 +104,13 @@ where
|
|||
last_change_tick: u32,
|
||||
change_tick: u32,
|
||||
) -> QueryManyIter<'w, 's, Q, F, I> {
|
||||
let fetch = Q::Fetch::init(
|
||||
let fetch = Q::init_fetch(
|
||||
world,
|
||||
&query_state.fetch_state,
|
||||
last_change_tick,
|
||||
change_tick,
|
||||
);
|
||||
let filter = F::Fetch::init(
|
||||
let filter = F::init_fetch(
|
||||
world,
|
||||
&query_state.filter_state,
|
||||
last_change_tick,
|
||||
|
@ -153,19 +153,25 @@ where
|
|||
|
||||
// SAFETY: `archetype` is from the world that `fetch/filter` were created for,
|
||||
// `fetch_state`/`filter_state` are the states that `fetch/filter` were initialized with
|
||||
self.fetch
|
||||
.set_archetype(&self.query_state.fetch_state, archetype, self.tables);
|
||||
|
||||
Q::set_archetype(
|
||||
&mut self.fetch,
|
||||
&self.query_state.fetch_state,
|
||||
archetype,
|
||||
self.tables,
|
||||
);
|
||||
// SAFETY: `table` is from the world that `fetch/filter` were created for,
|
||||
// `fetch_state`/`filter_state` are the states that `fetch/filter` were initialized with
|
||||
self.filter
|
||||
.set_archetype(&self.query_state.filter_state, archetype, self.tables);
|
||||
|
||||
F::set_archetype(
|
||||
&mut self.filter,
|
||||
&self.query_state.filter_state,
|
||||
archetype,
|
||||
self.tables,
|
||||
);
|
||||
// SAFETY: set_archetype was called prior.
|
||||
// `location.index` is an archetype index row in range of the current archetype, because if it was not, the match above would have `continue`d
|
||||
if self.filter.archetype_filter_fetch(location.index) {
|
||||
if F::archetype_filter_fetch(&mut self.filter, location.index) {
|
||||
// SAFETY: set_archetype was called prior, `location.index` is an archetype index in range of the current archetype
|
||||
return Some(self.fetch.archetype_fetch(location.index));
|
||||
return Some(Q::archetype_fetch(&mut self.fetch, location.index));
|
||||
}
|
||||
}
|
||||
None
|
||||
|
@ -370,7 +376,7 @@ where
|
|||
let smallest = K.min(max_size - K);
|
||||
let max_combinations = choose(max_size, smallest);
|
||||
|
||||
let archetype_query = F::Fetch::IS_ARCHETYPAL && Q::Fetch::IS_ARCHETYPAL;
|
||||
let archetype_query = F::IS_ARCHETYPAL && Q::IS_ARCHETYPAL;
|
||||
let known_max = max_combinations.unwrap_or(usize::MAX);
|
||||
let min_combinations = if archetype_query { known_max } else { 0 };
|
||||
(min_combinations, max_combinations)
|
||||
|
@ -445,7 +451,7 @@ where
|
|||
}
|
||||
|
||||
impl<'w, 's, Q: WorldQuery, F: WorldQuery> QueryIterationCursor<'w, 's, Q, F> {
|
||||
const IS_DENSE: bool = Q::Fetch::IS_DENSE && F::Fetch::IS_DENSE;
|
||||
const IS_DENSE: bool = Q::IS_DENSE && F::IS_DENSE;
|
||||
|
||||
unsafe fn init_empty(
|
||||
world: &'w World,
|
||||
|
@ -466,13 +472,13 @@ impl<'w, 's, Q: WorldQuery, F: WorldQuery> QueryIterationCursor<'w, 's, Q, F> {
|
|||
last_change_tick: u32,
|
||||
change_tick: u32,
|
||||
) -> Self {
|
||||
let fetch = Q::Fetch::init(
|
||||
let fetch = Q::init_fetch(
|
||||
world,
|
||||
&query_state.fetch_state,
|
||||
last_change_tick,
|
||||
change_tick,
|
||||
);
|
||||
let filter = F::Fetch::init(
|
||||
let filter = F::init_fetch(
|
||||
world,
|
||||
&query_state.filter_state,
|
||||
last_change_tick,
|
||||
|
@ -494,9 +500,9 @@ impl<'w, 's, Q: WorldQuery, F: WorldQuery> QueryIterationCursor<'w, 's, Q, F> {
|
|||
unsafe fn peek_last(&mut self) -> Option<QueryItem<'w, Q>> {
|
||||
if self.current_index > 0 {
|
||||
if Self::IS_DENSE {
|
||||
Some(self.fetch.table_fetch(self.current_index - 1))
|
||||
Some(Q::table_fetch(&mut self.fetch, self.current_index - 1))
|
||||
} else {
|
||||
Some(self.fetch.archetype_fetch(self.current_index - 1))
|
||||
Some(Q::archetype_fetch(&mut self.fetch, self.current_index - 1))
|
||||
}
|
||||
} else {
|
||||
None
|
||||
|
@ -524,8 +530,8 @@ impl<'w, 's, Q: WorldQuery, F: WorldQuery> QueryIterationCursor<'w, 's, Q, F> {
|
|||
let table = &tables[*table_id];
|
||||
// SAFETY: `table` is from the world that `fetch/filter` were created for,
|
||||
// `fetch_state`/`filter_state` are the states that `fetch/filter` were initialized with
|
||||
self.fetch.set_table(&query_state.fetch_state, table);
|
||||
self.filter.set_table(&query_state.filter_state, table);
|
||||
Q::set_table(&mut self.fetch, &query_state.fetch_state, table);
|
||||
F::set_table(&mut self.filter, &query_state.filter_state, table);
|
||||
self.current_len = table.len();
|
||||
self.current_index = 0;
|
||||
continue;
|
||||
|
@ -533,14 +539,14 @@ impl<'w, 's, Q: WorldQuery, F: WorldQuery> QueryIterationCursor<'w, 's, Q, F> {
|
|||
|
||||
// SAFETY: set_table was called prior.
|
||||
// `current_index` is a table row in range of the current table, because if it was not, then the if above would have been executed.
|
||||
if !self.filter.table_filter_fetch(self.current_index) {
|
||||
if !F::table_filter_fetch(&mut self.filter, self.current_index) {
|
||||
self.current_index += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
// SAFETY: set_table was called prior.
|
||||
// `current_index` is a table row in range of the current table, because if it was not, then the if above would have been executed.
|
||||
let item = self.fetch.table_fetch(self.current_index);
|
||||
let item = Q::table_fetch(&mut self.fetch, self.current_index);
|
||||
|
||||
self.current_index += 1;
|
||||
return Some(item);
|
||||
|
@ -552,10 +558,13 @@ impl<'w, 's, Q: WorldQuery, F: WorldQuery> QueryIterationCursor<'w, 's, Q, F> {
|
|||
let archetype = &archetypes[*archetype_id];
|
||||
// SAFETY: `archetype` and `tables` are from the world that `fetch/filter` were created for,
|
||||
// `fetch_state`/`filter_state` are the states that `fetch/filter` were initialized with
|
||||
self.fetch
|
||||
.set_archetype(&query_state.fetch_state, archetype, tables);
|
||||
self.filter
|
||||
.set_archetype(&query_state.filter_state, archetype, tables);
|
||||
Q::set_archetype(&mut self.fetch, &query_state.fetch_state, archetype, tables);
|
||||
F::set_archetype(
|
||||
&mut self.filter,
|
||||
&query_state.filter_state,
|
||||
archetype,
|
||||
tables,
|
||||
);
|
||||
self.current_len = archetype.len();
|
||||
self.current_index = 0;
|
||||
continue;
|
||||
|
@ -563,14 +572,14 @@ impl<'w, 's, Q: WorldQuery, F: WorldQuery> QueryIterationCursor<'w, 's, Q, F> {
|
|||
|
||||
// SAFETY: set_archetype was called prior.
|
||||
// `current_index` is an archetype index row in range of the current archetype, because if it was not, then the if above would have been executed.
|
||||
if !self.filter.archetype_filter_fetch(self.current_index) {
|
||||
if !F::archetype_filter_fetch(&mut self.filter, self.current_index) {
|
||||
self.current_index += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
// SAFETY: set_archetype was called prior, `current_index` is an archetype index in range of the current archetype
|
||||
// `current_index` is an archetype index row in range of the current archetype, because if it was not, then the if above would have been executed.
|
||||
let item = self.fetch.archetype_fetch(self.current_index);
|
||||
let item = Q::archetype_fetch(&mut self.fetch, self.current_index);
|
||||
self.current_index += 1;
|
||||
return Some(item);
|
||||
}
|
||||
|
|
|
@ -3,9 +3,7 @@ use crate::{
|
|||
component::ComponentId,
|
||||
entity::Entity,
|
||||
prelude::FromWorld,
|
||||
query::{
|
||||
Access, Fetch, FetchState, FilteredAccess, QueryCombinationIter, QueryIter, WorldQuery,
|
||||
},
|
||||
query::{Access, FilteredAccess, QueryCombinationIter, QueryIter, WorldQuery},
|
||||
storage::TableId,
|
||||
world::{World, WorldId},
|
||||
};
|
||||
|
@ -15,7 +13,7 @@ use bevy_utils::tracing::Instrument;
|
|||
use fixedbitset::FixedBitSet;
|
||||
use std::{borrow::Borrow, fmt};
|
||||
|
||||
use super::{NopWorldQuery, QueryFetch, QueryItem, QueryManyIter, ROQueryItem};
|
||||
use super::{NopWorldQuery, QueryItem, QueryManyIter, ROQueryItem};
|
||||
|
||||
/// Provides scoped access to a [`World`] state according to a given [`WorldQuery`] and query filter.
|
||||
#[repr(C)]
|
||||
|
@ -84,20 +82,17 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
|
|||
impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
|
||||
/// Creates a new [`QueryState`] from a given [`World`] and inherits the result of `world.id()`.
|
||||
pub fn new(world: &mut World) -> Self {
|
||||
let fetch_state = <Q::State as FetchState>::init(world);
|
||||
let filter_state = <F::State as FetchState>::init(world);
|
||||
let fetch_state = Q::init_state(world);
|
||||
let filter_state = F::init_state(world);
|
||||
|
||||
let mut component_access = FilteredAccess::default();
|
||||
QueryFetch::<'static, Q>::update_component_access(&fetch_state, &mut component_access);
|
||||
Q::update_component_access(&fetch_state, &mut component_access);
|
||||
|
||||
// Use a temporary empty FilteredAccess for filters. This prevents them from conflicting with the
|
||||
// main Query's `fetch_state` access. Filters are allowed to conflict with the main query fetch
|
||||
// because they are evaluated *before* a specific reference is constructed.
|
||||
let mut filter_component_access = FilteredAccess::default();
|
||||
QueryFetch::<'static, F>::update_component_access(
|
||||
&filter_state,
|
||||
&mut filter_component_access,
|
||||
);
|
||||
F::update_component_access(&filter_state, &mut filter_component_access);
|
||||
|
||||
// Merge the temporary filter access with the main access. This ensures that filter access is
|
||||
// properly considered in a global "cross-query" context (both within systems and across systems).
|
||||
|
@ -160,19 +155,15 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
|
|||
|
||||
/// Creates a new [`Archetype`].
|
||||
pub fn new_archetype(&mut self, archetype: &Archetype) {
|
||||
if self
|
||||
.fetch_state
|
||||
.matches_component_set(&|id| archetype.contains(id))
|
||||
&& self
|
||||
.filter_state
|
||||
.matches_component_set(&|id| archetype.contains(id))
|
||||
if Q::matches_component_set(&self.fetch_state, &|id| archetype.contains(id))
|
||||
&& F::matches_component_set(&self.filter_state, &|id| archetype.contains(id))
|
||||
{
|
||||
QueryFetch::<'static, Q>::update_archetype_component_access(
|
||||
Q::update_archetype_component_access(
|
||||
&self.fetch_state,
|
||||
archetype,
|
||||
&mut self.archetype_component_access,
|
||||
);
|
||||
QueryFetch::<'static, F>::update_archetype_component_access(
|
||||
F::update_archetype_component_access(
|
||||
&self.filter_state,
|
||||
archetype,
|
||||
&mut self.archetype_component_access,
|
||||
|
@ -408,19 +399,23 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
|
|||
return Err(QueryEntityError::QueryDoesNotMatch(entity));
|
||||
}
|
||||
let archetype = &world.archetypes[location.archetype_id];
|
||||
let mut fetch =
|
||||
<QueryFetch<Q> as Fetch>::init(world, &self.fetch_state, last_change_tick, change_tick);
|
||||
let mut filter = <QueryFetch<F> as Fetch>::init(
|
||||
world,
|
||||
&self.filter_state,
|
||||
last_change_tick,
|
||||
change_tick,
|
||||
);
|
||||
let mut fetch = Q::init_fetch(world, &self.fetch_state, last_change_tick, change_tick);
|
||||
let mut filter = F::init_fetch(world, &self.filter_state, last_change_tick, change_tick);
|
||||
|
||||
fetch.set_archetype(&self.fetch_state, archetype, &world.storages().tables);
|
||||
filter.set_archetype(&self.filter_state, archetype, &world.storages().tables);
|
||||
if filter.archetype_filter_fetch(location.index) {
|
||||
Ok(fetch.archetype_fetch(location.index))
|
||||
Q::set_archetype(
|
||||
&mut fetch,
|
||||
&self.fetch_state,
|
||||
archetype,
|
||||
&world.storages().tables,
|
||||
);
|
||||
F::set_archetype(
|
||||
&mut filter,
|
||||
&self.filter_state,
|
||||
archetype,
|
||||
&world.storages().tables,
|
||||
);
|
||||
if F::archetype_filter_fetch(&mut filter, location.index) {
|
||||
Ok(Q::archetype_fetch(&mut fetch, location.index))
|
||||
} else {
|
||||
Err(QueryEntityError::QueryDoesNotMatch(entity))
|
||||
}
|
||||
|
@ -909,27 +904,21 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
|
|||
) {
|
||||
// NOTE: If you are changing query iteration code, remember to update the following places, where relevant:
|
||||
// QueryIter, QueryIterationCursor, QueryManyIter, QueryCombinationIter, QueryState::for_each_unchecked_manual, QueryState::par_for_each_unchecked_manual
|
||||
let mut fetch =
|
||||
<QueryFetch<Q> as Fetch>::init(world, &self.fetch_state, last_change_tick, change_tick);
|
||||
let mut filter = <QueryFetch<F> as Fetch>::init(
|
||||
world,
|
||||
&self.filter_state,
|
||||
last_change_tick,
|
||||
change_tick,
|
||||
);
|
||||
let mut fetch = Q::init_fetch(world, &self.fetch_state, last_change_tick, change_tick);
|
||||
let mut filter = F::init_fetch(world, &self.filter_state, last_change_tick, change_tick);
|
||||
|
||||
if <QueryFetch<'static, Q>>::IS_DENSE && <QueryFetch<'static, F>>::IS_DENSE {
|
||||
if Q::IS_DENSE && F::IS_DENSE {
|
||||
let tables = &world.storages().tables;
|
||||
for table_id in &self.matched_table_ids {
|
||||
let table = &tables[*table_id];
|
||||
fetch.set_table(&self.fetch_state, table);
|
||||
filter.set_table(&self.filter_state, table);
|
||||
Q::set_table(&mut fetch, &self.fetch_state, table);
|
||||
F::set_table(&mut filter, &self.filter_state, table);
|
||||
|
||||
for table_index in 0..table.len() {
|
||||
if !filter.table_filter_fetch(table_index) {
|
||||
if !F::table_filter_fetch(&mut filter, table_index) {
|
||||
continue;
|
||||
}
|
||||
let item = fetch.table_fetch(table_index);
|
||||
let item = Q::table_fetch(&mut fetch, table_index);
|
||||
func(item);
|
||||
}
|
||||
}
|
||||
|
@ -938,14 +927,14 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
|
|||
let tables = &world.storages().tables;
|
||||
for archetype_id in &self.matched_archetype_ids {
|
||||
let archetype = &archetypes[*archetype_id];
|
||||
fetch.set_archetype(&self.fetch_state, archetype, tables);
|
||||
filter.set_archetype(&self.filter_state, archetype, tables);
|
||||
Q::set_archetype(&mut fetch, &self.fetch_state, archetype, tables);
|
||||
F::set_archetype(&mut filter, &self.filter_state, archetype, tables);
|
||||
|
||||
for archetype_index in 0..archetype.len() {
|
||||
if !filter.archetype_filter_fetch(archetype_index) {
|
||||
if !F::archetype_filter_fetch(&mut filter, archetype_index) {
|
||||
continue;
|
||||
}
|
||||
func(fetch.archetype_fetch(archetype_index));
|
||||
func(Q::archetype_fetch(&mut fetch, archetype_index));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -979,7 +968,7 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
|
|||
// NOTE: If you are changing query iteration code, remember to update the following places, where relevant:
|
||||
// QueryIter, QueryIterationCursor, QueryManyIter, QueryCombinationIter, QueryState::for_each_unchecked_manual, QueryState::par_for_each_unchecked_manual
|
||||
ComputeTaskPool::get().scope(|scope| {
|
||||
if <QueryFetch<'static, Q>>::IS_DENSE && <QueryFetch<'static, F>>::IS_DENSE {
|
||||
if Q::IS_DENSE && F::IS_DENSE {
|
||||
let tables = &world.storages().tables;
|
||||
for table_id in &self.matched_table_ids {
|
||||
let table = &tables[*table_id];
|
||||
|
@ -988,13 +977,13 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
|
|||
let func = func.clone();
|
||||
let len = batch_size.min(table.len() - offset);
|
||||
let task = async move {
|
||||
let mut fetch = <QueryFetch<Q> as Fetch>::init(
|
||||
let mut fetch = Q::init_fetch(
|
||||
world,
|
||||
&self.fetch_state,
|
||||
last_change_tick,
|
||||
change_tick,
|
||||
);
|
||||
let mut filter = <QueryFetch<F> as Fetch>::init(
|
||||
let mut filter = F::init_fetch(
|
||||
world,
|
||||
&self.filter_state,
|
||||
last_change_tick,
|
||||
|
@ -1002,13 +991,13 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
|
|||
);
|
||||
let tables = &world.storages().tables;
|
||||
let table = &tables[*table_id];
|
||||
fetch.set_table(&self.fetch_state, table);
|
||||
filter.set_table(&self.filter_state, table);
|
||||
Q::set_table(&mut fetch, &self.fetch_state, table);
|
||||
F::set_table(&mut filter, &self.filter_state, table);
|
||||
for table_index in offset..offset + len {
|
||||
if !filter.table_filter_fetch(table_index) {
|
||||
if !F::table_filter_fetch(&mut filter, table_index) {
|
||||
continue;
|
||||
}
|
||||
let item = fetch.table_fetch(table_index);
|
||||
let item = Q::table_fetch(&mut fetch, table_index);
|
||||
func(item);
|
||||
}
|
||||
};
|
||||
|
@ -1034,13 +1023,13 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
|
|||
let func = func.clone();
|
||||
let len = batch_size.min(archetype.len() - offset);
|
||||
let task = async move {
|
||||
let mut fetch = <QueryFetch<Q> as Fetch>::init(
|
||||
let mut fetch = Q::init_fetch(
|
||||
world,
|
||||
&self.fetch_state,
|
||||
last_change_tick,
|
||||
change_tick,
|
||||
);
|
||||
let mut filter = <QueryFetch<F> as Fetch>::init(
|
||||
let mut filter = F::init_fetch(
|
||||
world,
|
||||
&self.filter_state,
|
||||
last_change_tick,
|
||||
|
@ -1048,14 +1037,14 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
|
|||
);
|
||||
let tables = &world.storages().tables;
|
||||
let archetype = &world.archetypes[*archetype_id];
|
||||
fetch.set_archetype(&self.fetch_state, archetype, tables);
|
||||
filter.set_archetype(&self.filter_state, archetype, tables);
|
||||
Q::set_archetype(&mut fetch, &self.fetch_state, archetype, tables);
|
||||
F::set_archetype(&mut filter, &self.filter_state, archetype, tables);
|
||||
|
||||
for archetype_index in offset..offset + len {
|
||||
if !filter.archetype_filter_fetch(archetype_index) {
|
||||
if !F::archetype_filter_fetch(&mut filter, archetype_index) {
|
||||
continue;
|
||||
}
|
||||
func(fetch.archetype_fetch(archetype_index));
|
||||
func(Q::archetype_fetch(&mut fetch, archetype_index));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ error[E0277]: the trait bound `&'static mut Foo: ReadOnlyWorldQuery` is not sati
|
|||
= note: `ReadOnlyWorldQuery` is implemented for `&'static Foo`, but not for `&'static mut Foo`
|
||||
= note: required because of the requirements on the impl of `ReadOnlySystemParamFetch` for `QueryState<&'static mut Foo>`
|
||||
= note: 2 redundant requirements hidden
|
||||
= note: required because of the requirements on the impl of `ReadOnlySystemParamFetch` for `_::FetchState<(QueryState<&'static mut Foo>,)>`
|
||||
= note: required because of the requirements on the impl of `ReadOnlySystemParamFetch` for `FetchState<(QueryState<&'static mut Foo>,)>`
|
||||
note: required by a bound in `assert_readonly`
|
||||
--> tests/ui/system_param_derive_readonly.rs:23:32
|
||||
|
|
||||
|
|
Loading…
Reference in a new issue