mirror of
https://github.com/bevyengine/bevy
synced 2024-11-23 05:03:47 +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));
|
.unwrap_or_else(|_| panic!("Invalid `{}` attribute format", WORLD_QUERY_ATTRIBUTE_NAME));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let path = bevy_ecs_path();
|
||||||
|
|
||||||
let user_generics = ast.generics.clone();
|
let user_generics = ast.generics.clone();
|
||||||
let (user_impl_generics, user_ty_generics, user_where_clauses) = user_generics.split_for_impl();
|
let (user_impl_generics, user_ty_generics, user_where_clauses) = user_generics.split_for_impl();
|
||||||
let user_generics_with_world = {
|
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 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 {
|
let fields = match &ast.data {
|
||||||
Data::Struct(DataStruct {
|
Data::Struct(DataStruct {
|
||||||
fields: Fields::Named(fields),
|
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_visibilities = Vec::new();
|
||||||
let mut field_idents = Vec::new();
|
let mut field_idents = Vec::new();
|
||||||
let mut field_types = Vec::new();
|
let mut field_types = Vec::new();
|
||||||
|
let mut read_only_field_types = Vec::new();
|
||||||
|
|
||||||
for field in fields {
|
for field in fields {
|
||||||
let WorldQueryFieldInfo { is_ignored, attrs } = read_world_query_field_info(field);
|
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_attrs.push(attrs);
|
||||||
field_visibilities.push(field.vis.clone());
|
field_visibilities.push(field.vis.clone());
|
||||||
field_idents.push(field_ident.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
|
// `#[derive()]` is valid syntax
|
||||||
let derive_macro_call = quote! { #[derive(#derive_args)] };
|
let derive_macro_call = quote! { #[derive(#derive_args)] };
|
||||||
|
|
||||||
let path = bevy_ecs_path();
|
let impl_fetch = |is_readonly: bool| {
|
||||||
|
let struct_name = if is_readonly {
|
||||||
let impl_fetch = |is_readonly: bool, fetch_struct_name: Ident, item_struct_name: Ident| {
|
&read_only_struct_name
|
||||||
let fetch_type_alias = if is_readonly {
|
|
||||||
&read_only_fetch_type_alias
|
|
||||||
} else {
|
} else {
|
||||||
&fetch_type_alias
|
&struct_name
|
||||||
};
|
};
|
||||||
let item_type_alias = if is_readonly {
|
let item_struct_name = if is_readonly {
|
||||||
&read_only_item_type_alias
|
&read_only_item_struct_name
|
||||||
} else {
|
} 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! {
|
quote! {
|
||||||
#derive_macro_call
|
#derive_macro_call
|
||||||
#[automatically_derived]
|
#[automatically_derived]
|
||||||
#visibility struct #item_struct_name #user_impl_generics_with_world #user_where_clauses_with_world {
|
#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,)*
|
#(#(#ignored_field_attrs)* #ignored_field_visibilities #ignored_field_idents: #ignored_field_types,)*
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#visibility struct #fetch_struct_name #user_impl_generics_with_world #user_where_clauses_with_world {
|
#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,)*
|
#(#ignored_field_idents: #ignored_field_types,)*
|
||||||
}
|
}
|
||||||
|
|
||||||
// SAFETY: `update_component_access` and `update_archetype_component_access` are called on every field
|
// 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 {
|
|
||||||
|
|
||||||
|
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 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;
|
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 {
|
fn shrink<'__wlong: '__wshort, '__wshort>(
|
||||||
Self {
|
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:
|
#(#field_idents:
|
||||||
#path::query::#fetch_type_alias::<'__w, #field_types>::init(
|
<#field_types>::init_fetch(
|
||||||
_world,
|
_world,
|
||||||
&state.#field_idents,
|
&state.#field_idents,
|
||||||
_last_change_tick,
|
_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`
|
/// SAFETY: we call `set_archetype` for each member that implements `Fetch`
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn set_archetype(
|
unsafe fn set_archetype<'__w>(
|
||||||
&mut self,
|
_fetch: &mut <Self as #path::query::WorldQueryGats<'__w>>::Fetch,
|
||||||
_state: &Self::State,
|
_state: &Self::State,
|
||||||
_archetype: &'__w #path::archetype::Archetype,
|
_archetype: &'__w #path::archetype::Archetype,
|
||||||
_tables: &'__w #path::storage::Tables
|
_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`
|
/// SAFETY: we call `set_table` for each member that implements `Fetch`
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn set_table(&mut self, _state: &Self::State, _table: &'__w #path::storage::Table) {
|
unsafe fn set_table<'__w>(
|
||||||
#(self.#field_idents.set_table(&_state.#field_idents, _table);)*
|
_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`.
|
/// SAFETY: we call `table_fetch` for each member that implements `Fetch`.
|
||||||
#[inline]
|
#[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 {
|
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(),)*
|
#(#ignored_field_idents: Default::default(),)*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// SAFETY: we call `archetype_fetch` for each member that implements `Fetch`.
|
/// SAFETY: we call `archetype_fetch` for each member that implements `Fetch`.
|
||||||
#[inline]
|
#[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 {
|
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(),)*
|
#(#ignored_field_idents: Default::default(),)*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn table_filter_fetch(&mut self, _table_row: usize) -> bool {
|
unsafe fn table_filter_fetch<'__w>(_fetch: &mut <Self as #path::query::WorldQueryGats<'__w>>::Fetch, _table_row: usize) -> bool {
|
||||||
true #(&& self.#field_idents.table_filter_fetch(_table_row))*
|
true #(&& <#field_types>::table_filter_fetch(&mut _fetch.#field_idents, _table_row))*
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn archetype_filter_fetch(&mut self, _archetype_index: usize) -> bool {
|
unsafe fn archetype_filter_fetch<'__w>(_fetch: &mut <Self as #path::query::WorldQueryGats<'__w>>::Fetch, _archetype_index: usize) -> bool {
|
||||||
true #(&& self.#field_idents.archetype_filter_fetch(_archetype_index))*
|
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>) {
|
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>
|
<#field_types>::update_archetype_component_access(&state.#field_idents, _archetype, _access);
|
||||||
:: 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 {
|
||||||
|
|
||||||
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 {
|
#state_struct_name {
|
||||||
#(#field_idents: <<#field_types as #path::query::WorldQuery>::State as #path::query::FetchState>::init(world),)*
|
#(#field_idents: <#field_types>::init_state(world),)*
|
||||||
#(#ignored_field_idents: Default::default(),)*
|
#(#ignored_field_idents: Default::default(),)*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn matches_component_set(&self, _set_contains_id: &impl Fn(#path::component::ComponentId) -> bool) -> bool {
|
fn matches_component_set(state: &Self::State, _set_contains_id: &impl Fn(#path::component::ComponentId) -> bool) -> bool {
|
||||||
true #(&& self.#field_idents.matches_component_set(_set_contains_id))*
|
true #(&& <#field_types>::matches_component_set(&state.#field_idents, _set_contains_id))*
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let read_only_fetch_impl = if fetch_struct_attributes.is_mutable {
|
let mutable_impl = impl_fetch(false);
|
||||||
impl_fetch(
|
let readonly_impl = if fetch_struct_attributes.is_mutable {
|
||||||
true,
|
let world_query_impl = 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 {
|
|
||||||
quote! {
|
quote! {
|
||||||
#[automatically_derived]
|
#[automatically_derived]
|
||||||
#visibility struct #read_only_struct_name #user_impl_generics #user_where_clauses {
|
#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,)*
|
#(#(#ignored_field_attrs)* #ignored_field_visibilities #ignored_field_idents: #ignored_field_types,)*
|
||||||
}
|
}
|
||||||
|
|
||||||
// SAFETY: `ROQueryFetch<Self>` is the same as `QueryFetch<Self>`
|
#world_query_impl
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
quote! {}
|
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.
|
// Double-check that the data fetched by `<_ as WorldQuery>::ReadOnly` is read-only.
|
||||||
// This is technically unnecessary as `<_ as WorldQuery>::ReadOnly: ReadOnlyWorldQuery`
|
// This is technically unnecessary as `<_ as WorldQuery>::ReadOnly: ReadOnlyWorldQuery`
|
||||||
// but to protect against future mistakes we assert the assoc type implements `ReadOnlyWorldQuery` anyway
|
// 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 {
|
} else {
|
||||||
quote! {
|
quote! {
|
||||||
|
@ -363,38 +365,17 @@ pub fn derive_world_query_impl(ast: DeriveInput) -> TokenStream {
|
||||||
};
|
};
|
||||||
|
|
||||||
TokenStream::from(quote! {
|
TokenStream::from(quote! {
|
||||||
#fetch_impl
|
#mutable_impl
|
||||||
|
|
||||||
#state_impl
|
#readonly_impl
|
||||||
|
|
||||||
#read_only_fetch_impl
|
#[doc(hidden)]
|
||||||
|
#visibility struct #state_struct_name #user_impl_generics #user_where_clauses {
|
||||||
#read_only_world_query_impl
|
#(#field_idents: <#field_types as #path::query::WorldQuery>::State,)*
|
||||||
|
#(#ignored_field_idents: #ignored_field_types,)*
|
||||||
// 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,
|
|
||||||
)*
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl #user_impl_generics_with_world #path::query::WorldQueryGats<'__w> for #struct_name #user_ty_generics #user_where_clauses {
|
/// SAFETY: we assert fields are readonly below
|
||||||
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
|
|
||||||
unsafe impl #user_impl_generics #path::query::ReadOnlyWorldQuery
|
unsafe impl #user_impl_generics #path::query::ReadOnlyWorldQuery
|
||||||
for #read_only_struct_name #user_ty_generics #user_where_clauses {}
|
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.
|
// workaround.
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
const _: () = {
|
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.#field_idents;)*
|
||||||
#(q.#ignored_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},
|
component::{Component, ComponentId, ComponentStorage, ComponentTicks, StorageType},
|
||||||
entity::Entity,
|
entity::Entity,
|
||||||
query::{
|
query::{
|
||||||
debug_checked_unreachable, Access, Fetch, FetchState, FilteredAccess, QueryFetch,
|
debug_checked_unreachable, Access, FilteredAccess, QueryFetch, WorldQuery, WorldQueryGats,
|
||||||
WorldQuery, WorldQueryGats,
|
|
||||||
},
|
},
|
||||||
storage::{ComponentSparseSet, Table, Tables},
|
storage::{ComponentSparseSet, Table, Tables},
|
||||||
world::World,
|
world::World,
|
||||||
|
@ -44,65 +43,27 @@ use super::ReadOnlyWorldQuery;
|
||||||
/// ```
|
/// ```
|
||||||
pub struct With<T>(PhantomData<T>);
|
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>`
|
// SAFETY: `ROQueryFetch<Self>` is the same as `QueryFetch<Self>`
|
||||||
unsafe impl<T: Component> WorldQuery for With<T> {
|
unsafe impl<T: Component> WorldQuery for With<T> {
|
||||||
type ReadOnly = Self;
|
type ReadOnly = Self;
|
||||||
type State = WithState<T>;
|
type State = ComponentId;
|
||||||
|
|
||||||
#[allow(clippy::semicolon_if_nothing_returned)]
|
|
||||||
fn shrink<'wlong: 'wshort, 'wshort>(
|
fn shrink<'wlong: 'wshort, 'wshort>(
|
||||||
item: super::QueryItem<'wlong, Self>,
|
_: <Self as WorldQueryGats<'wlong>>::Item,
|
||||||
) -> super::QueryItem<'wshort, Self> {
|
) -> <Self as WorldQueryGats<'wshort>>::Item {
|
||||||
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,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn matches_component_set(&self, set_contains_id: &impl Fn(ComponentId) -> bool) -> bool {
|
unsafe fn init_fetch(
|
||||||
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(
|
|
||||||
_world: &World,
|
_world: &World,
|
||||||
_state: &WithState<T>,
|
_state: &ComponentId,
|
||||||
_last_change_tick: u32,
|
_last_change_tick: u32,
|
||||||
_change_tick: u32,
|
_change_tick: u32,
|
||||||
) -> Self {
|
) {
|
||||||
Self {
|
|
||||||
marker: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const IS_DENSE: bool = {
|
const IS_DENSE: bool = {
|
||||||
|
@ -115,50 +76,59 @@ unsafe impl<'w, T: Component> Fetch<'w> for WithFetch<T> {
|
||||||
const IS_ARCHETYPAL: bool = true;
|
const IS_ARCHETYPAL: bool = true;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn set_table(&mut self, _state: &Self::State, _table: &Table) {}
|
unsafe fn set_table(_fetch: &mut (), _state: &ComponentId, _table: &Table) {}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn set_archetype(
|
unsafe fn set_archetype(
|
||||||
&mut self,
|
_fetch: &mut (),
|
||||||
_state: &Self::State,
|
_state: &ComponentId,
|
||||||
_archetype: &Archetype,
|
_archetype: &Archetype,
|
||||||
_tables: &Tables,
|
_tables: &Tables,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[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]
|
#[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]
|
#[inline]
|
||||||
fn update_component_access(state: &Self::State, access: &mut FilteredAccess<ComponentId>) {
|
fn update_component_access(&id: &ComponentId, access: &mut FilteredAccess<ComponentId>) {
|
||||||
access.add_with(state.component_id);
|
access.add_with(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn update_archetype_component_access(
|
fn update_archetype_component_access(
|
||||||
_state: &Self::State,
|
_state: &ComponentId,
|
||||||
_archetype: &Archetype,
|
_archetype: &Archetype,
|
||||||
_access: &mut Access<ArchetypeComponentId>,
|
_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
|
// SAFETY: no component access or archetype component access
|
||||||
unsafe impl<T: Component> ReadOnlyWorldQuery for With<T> {}
|
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`.
|
/// Filter that selects entities without a component `T`.
|
||||||
///
|
///
|
||||||
/// This is the negation of [`With`].
|
/// 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>`
|
// SAFETY: `ROQueryFetch<Self>` is the same as `QueryFetch<Self>`
|
||||||
unsafe impl<T: Component> WorldQuery for Without<T> {
|
unsafe impl<T: Component> WorldQuery for Without<T> {
|
||||||
type ReadOnly = Self;
|
type ReadOnly = Self;
|
||||||
type State = WithoutState<T>;
|
type State = ComponentId;
|
||||||
|
|
||||||
#[allow(clippy::semicolon_if_nothing_returned)]
|
|
||||||
fn shrink<'wlong: 'wshort, 'wshort>(
|
fn shrink<'wlong: 'wshort, 'wshort>(
|
||||||
item: super::QueryItem<'wlong, Self>,
|
_: <Self as WorldQueryGats<'wlong>>::Item,
|
||||||
) -> super::QueryItem<'wshort, Self> {
|
) -> <Self as WorldQueryGats<'wshort>>::Item {
|
||||||
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,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn matches_component_set(&self, set_contains_id: &impl Fn(ComponentId) -> bool) -> bool {
|
unsafe fn init_fetch(
|
||||||
!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(
|
|
||||||
_world: &World,
|
_world: &World,
|
||||||
_state: &WithoutState<T>,
|
_state: &ComponentId,
|
||||||
_last_change_tick: u32,
|
_last_change_tick: u32,
|
||||||
_change_tick: u32,
|
_change_tick: u32,
|
||||||
) -> Self {
|
) {
|
||||||
WithoutFetch {
|
|
||||||
marker: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const IS_DENSE: bool = {
|
const IS_DENSE: bool = {
|
||||||
|
@ -256,50 +183,64 @@ unsafe impl<'w, T: Component> Fetch<'w> for WithoutFetch<T> {
|
||||||
const IS_ARCHETYPAL: bool = true;
|
const IS_ARCHETYPAL: bool = true;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn set_table(&mut self, _state: &Self::State, _table: &Table) {}
|
unsafe fn set_table(_fetch: &mut (), _state: &Self::State, _table: &Table) {}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn set_archetype(
|
unsafe fn set_archetype(
|
||||||
&mut self,
|
_fetch: &mut (),
|
||||||
_state: &Self::State,
|
_state: &ComponentId,
|
||||||
_archetype: &Archetype,
|
_archetype: &Archetype,
|
||||||
_tables: &Tables,
|
_tables: &Tables,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[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]
|
#[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]
|
#[inline]
|
||||||
fn update_component_access(state: &Self::State, access: &mut FilteredAccess<ComponentId>) {
|
fn update_component_access(&id: &ComponentId, access: &mut FilteredAccess<ComponentId>) {
|
||||||
access.add_without(state.component_id);
|
access.add_without(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn update_archetype_component_access(
|
fn update_archetype_component_access(
|
||||||
_state: &Self::State,
|
_state: &ComponentId,
|
||||||
_archetype: &Archetype,
|
_archetype: &Archetype,
|
||||||
_access: &mut Access<ArchetypeComponentId>,
|
_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
|
// SAFETY: no component access or archetype component access
|
||||||
unsafe impl<T: Component> ReadOnlyWorldQuery for Without<T> {}
|
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.
|
/// 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
|
/// 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)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct Or<T>(pub T);
|
pub struct Or<T>(pub T);
|
||||||
|
|
||||||
/// The [`Fetch`] of [`Or`].
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub struct OrFetch<'w, T: Fetch<'w>> {
|
pub struct OrFetch<'w, T: WorldQuery> {
|
||||||
fetch: T,
|
fetch: QueryFetch<'w, T>,
|
||||||
matches: bool,
|
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 {
|
macro_rules! impl_query_filter_tuple {
|
||||||
($(($filter: ident, $state: ident)),*) => {
|
($(($filter: ident, $state: ident)),*) => {
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
#[allow(non_snake_case)]
|
#[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
|
// SAFETY: defers to soundness of `$filter: WorldQuery` impl
|
||||||
unsafe impl<$($filter: WorldQuery),*> WorldQuery for Or<($($filter,)*)> {
|
unsafe impl<$($filter: WorldQuery),*> WorldQuery for Or<($($filter,)*)> {
|
||||||
type ReadOnly = Or<($($filter::ReadOnly,)*)>;
|
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> {
|
fn shrink<'wlong: 'wshort, 'wshort>(item: super::QueryItem<'wlong, Self>) -> super::QueryItem<'wshort, Self> {
|
||||||
item
|
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_DENSE: bool = true $(&& $filter::IS_DENSE)*;
|
||||||
|
|
||||||
const IS_ARCHETYPAL: bool = true $(&& $filter::IS_ARCHETYPAL)*;
|
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 {
|
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.0;
|
let ($($filter,)*) = state;
|
||||||
Or(($(OrFetch {
|
($(OrFetch {
|
||||||
fetch: <$filter as Fetch<'w>>::init(world, $filter, last_change_tick, change_tick),
|
fetch: $filter::init_fetch(world, $filter, last_change_tick, change_tick),
|
||||||
matches: false,
|
matches: false,
|
||||||
_marker: PhantomData,
|
},)*)
|
||||||
},)*))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn set_table(&mut self, state: &Self::State, table: &'w Table) {
|
unsafe fn set_table<'w>(fetch: &mut <Self as WorldQueryGats<'w>>::Fetch, state: &Self::State, table: &'w Table) {
|
||||||
let ($($filter,)*) = &mut self.0;
|
let ($($filter,)*) = fetch;
|
||||||
let ($($state,)*) = &state.0;
|
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 {
|
if $filter.matches {
|
||||||
$filter.fetch.set_table($state, table);
|
$filter::set_table(&mut $filter.fetch, $state, table);
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
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, state: &Self::State, archetype: &'w Archetype, tables: &'w Tables) {
|
||||||
let ($($filter,)*) = &mut self.0;
|
let ($($filter,)*) = fetch;
|
||||||
let ($($state,)*) = &state.0;
|
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 {
|
if $filter.matches {
|
||||||
$filter.fetch.set_archetype($state, archetype, tables);
|
$filter::set_archetype(&mut $filter.fetch, $state, archetype, tables);
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn table_fetch(&mut self, table_row: usize) -> bool {
|
unsafe fn table_fetch<'w>(fetch: &mut <Self as WorldQueryGats<'w>>::Fetch, table_row: usize) -> <Self as WorldQueryGats<'w>>::Item {
|
||||||
let ($($filter,)*) = &mut self.0;
|
let ($($filter,)*) = fetch;
|
||||||
false $(|| ($filter.matches && $filter.fetch.table_filter_fetch(table_row)))*
|
false $(|| ($filter.matches && $filter::table_filter_fetch(&mut $filter.fetch, table_row)))*
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
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 {
|
||||||
let ($($filter,)*) = &mut self.0;
|
let ($($filter,)*) = fetch;
|
||||||
false $(|| ($filter.matches && $filter.fetch.archetype_filter_fetch(archetype_index)))*
|
false $(|| ($filter.matches && $filter::archetype_filter_fetch(&mut $filter.fetch, archetype_index)))*
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn table_filter_fetch(&mut self, table_row: usize) -> bool {
|
unsafe fn table_filter_fetch(fetch: &mut QueryFetch<'_, Self>, table_row: usize) -> bool {
|
||||||
self.table_fetch(table_row)
|
Self::table_fetch(fetch, table_row)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn archetype_filter_fetch(&mut self, archetype_index: usize) -> bool {
|
unsafe fn archetype_filter_fetch(fetch: &mut QueryFetch<'_, Self>, archetype_index: usize) -> bool {
|
||||||
self.archetype_fetch(archetype_index)
|
Self::archetype_fetch(fetch, archetype_index)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_component_access(state: &Self::State, access: &mut FilteredAccess<ComponentId>) {
|
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`
|
// 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:
|
// 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>) {
|
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);)*
|
$($filter::update_archetype_component_access($filter, archetype, access);)*
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn init_state(world: &mut World) -> Self::State {
|
||||||
|
($($filter::init_state(world),)*)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
fn matches_component_set(_state: &Self::State, _set_contains_id: &impl Fn(ComponentId) -> bool) -> bool {
|
||||||
#[allow(non_snake_case)]
|
let ($($filter,)*) = _state;
|
||||||
impl<$($filter: FetchState),*> FetchState for Or<($($filter,)*)> {
|
false $(|| $filter::matches_component_set($filter, _set_contains_id))*
|
||||||
fn init(world: &mut World) -> Self {
|
|
||||||
Or(($($filter::init(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))*
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -491,8 +430,6 @@ macro_rules! impl_tick_filter {
|
||||||
(
|
(
|
||||||
$(#[$meta:meta])*
|
$(#[$meta:meta])*
|
||||||
$name: ident,
|
$name: ident,
|
||||||
$(#[$state_meta:meta])*
|
|
||||||
$state_name: ident,
|
|
||||||
$(#[$fetch_meta:meta])*
|
$(#[$fetch_meta:meta])*
|
||||||
$fetch_name: ident,
|
$fetch_name: ident,
|
||||||
$is_detected: expr
|
$is_detected: expr
|
||||||
|
@ -512,53 +449,22 @@ macro_rules! impl_tick_filter {
|
||||||
change_tick: u32,
|
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>`
|
// SAFETY: `ROQueryFetch<Self>` is the same as `QueryFetch<Self>`
|
||||||
unsafe impl<T: Component> WorldQuery for $name<T> {
|
unsafe impl<T: Component> WorldQuery for $name<T> {
|
||||||
type ReadOnly = Self;
|
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> {
|
fn shrink<'wlong: 'wshort, 'wshort>(item: super::QueryItem<'wlong, Self>) -> super::QueryItem<'wshort, Self> {
|
||||||
item
|
item
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Component> FetchState for $state_name<T> {
|
unsafe fn init_fetch<'w>(world: &'w World, &id: &ComponentId, last_change_tick: u32, change_tick: u32) -> <Self as WorldQueryGats<'w>>::Fetch {
|
||||||
fn init(world: &mut World) -> Self {
|
QueryFetch::<'w, 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 {
|
|
||||||
table_ticks: None,
|
table_ticks: None,
|
||||||
entities: None,
|
entities: None,
|
||||||
entity_table_rows: None,
|
entity_table_rows: None,
|
||||||
sparse_set: (T::Storage::STORAGE_TYPE == StorageType::SparseSet)
|
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,
|
marker: PhantomData,
|
||||||
last_change_tick,
|
last_change_tick,
|
||||||
change_tick,
|
change_tick,
|
||||||
|
@ -574,74 +480,87 @@ macro_rules! impl_tick_filter {
|
||||||
|
|
||||||
const IS_ARCHETYPAL: bool = false;
|
const IS_ARCHETYPAL: bool = false;
|
||||||
|
|
||||||
unsafe fn set_table(&mut self, state: &Self::State, table: &'w Table) {
|
unsafe fn set_table<'w>(fetch: &mut <Self as WorldQueryGats<'w>>::Fetch, &id: &ComponentId, table: &'w Table) {
|
||||||
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());
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
match T::Storage::STORAGE_TYPE {
|
||||||
StorageType::Table => {
|
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()];
|
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 {
|
unsafe fn table_fetch<'w>(fetch: &mut <Self as WorldQueryGats<'w>>::Fetch, table_row: usize) -> <Self as WorldQueryGats<'w>>::Item {
|
||||||
$is_detected(&*(self.table_ticks.unwrap_or_else(|| debug_checked_unreachable()).get(table_row)).deref(), self.last_change_tick, self.change_tick)
|
$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 {
|
match T::Storage::STORAGE_TYPE {
|
||||||
StorageType::Table => {
|
StorageType::Table => {
|
||||||
let table_row = *self.entity_table_rows.unwrap_or_else(|| debug_checked_unreachable()).get(archetype_index);
|
let table_row = *fetch.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)
|
$is_detected(&*(fetch.table_ticks.unwrap_or_else(|| debug_checked_unreachable()).get(table_row)).deref(), fetch.last_change_tick, fetch.change_tick)
|
||||||
}
|
}
|
||||||
StorageType::SparseSet => {
|
StorageType::SparseSet => {
|
||||||
let entity = *self.entities.unwrap_or_else(|| debug_checked_unreachable()).get(archetype_index);
|
let entity = *fetch.entities.unwrap_or_else(|| debug_checked_unreachable()).get(archetype_index);
|
||||||
let ticks = self
|
let ticks = fetch
|
||||||
.sparse_set
|
.sparse_set
|
||||||
.unwrap_or_else(|| debug_checked_unreachable())
|
.unwrap_or_else(|| debug_checked_unreachable())
|
||||||
.get_ticks(entity)
|
.get_ticks(entity)
|
||||||
.map(|ticks| &*ticks.get())
|
.map(|ticks| &*ticks.get())
|
||||||
.cloned()
|
.cloned()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
$is_detected(&ticks, self.last_change_tick, self.change_tick)
|
$is_detected(&ticks, fetch.last_change_tick, fetch.change_tick)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn table_filter_fetch(&mut self, table_row: usize) -> bool {
|
unsafe fn table_filter_fetch(fetch: &mut QueryFetch<'_, Self>, table_row: usize) -> bool {
|
||||||
self.table_fetch(table_row)
|
Self::table_fetch(fetch, table_row)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn archetype_filter_fetch(&mut self, archetype_index: usize) -> bool {
|
unsafe fn archetype_filter_fetch(fetch: &mut QueryFetch<'_, Self>, archetype_index: usize) -> bool {
|
||||||
self.archetype_fetch(archetype_index)
|
Self::archetype_fetch(fetch, archetype_index)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn update_component_access(state: &Self::State, access: &mut FilteredAccess<ComponentId>) {
|
fn update_component_access(&id: &ComponentId, access: &mut FilteredAccess<ComponentId>) {
|
||||||
if access.access().has_write(state.component_id) {
|
if access.access().has_write(id) {
|
||||||
panic!("$state_name<{}> conflicts with a previous access in this query. Shared access cannot coincide with exclusive access.",
|
panic!("$state_name<{}> conflicts with a previous access in this query. Shared access cannot coincide with exclusive access.",
|
||||||
std::any::type_name::<T>());
|
std::any::type_name::<T>());
|
||||||
}
|
}
|
||||||
access.add_read(state.component_id);
|
access.add_read(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn update_archetype_component_access(
|
fn update_archetype_component_access(
|
||||||
state: &Self::State,
|
&id: &ComponentId,
|
||||||
archetype: &Archetype,
|
archetype: &Archetype,
|
||||||
access: &mut Access<ArchetypeComponentId>,
|
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);
|
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
|
/// SAFETY: read-only access
|
||||||
|
@ -693,9 +612,6 @@ impl_tick_filter!(
|
||||||
/// # bevy_ecs::system::assert_is_system(print_add_name_component);
|
/// # bevy_ecs::system::assert_is_system(print_add_name_component);
|
||||||
/// ```
|
/// ```
|
||||||
Added,
|
Added,
|
||||||
/// The [`FetchState`] of [`Added`].
|
|
||||||
AddedState,
|
|
||||||
/// The [`Fetch`] of [`Added`].
|
|
||||||
AddedFetch,
|
AddedFetch,
|
||||||
ComponentTicks::is_added
|
ComponentTicks::is_added
|
||||||
);
|
);
|
||||||
|
@ -733,9 +649,6 @@ impl_tick_filter!(
|
||||||
/// # bevy_ecs::system::assert_is_system(print_moving_objects_system);
|
/// # bevy_ecs::system::assert_is_system(print_moving_objects_system);
|
||||||
/// ```
|
/// ```
|
||||||
Changed,
|
Changed,
|
||||||
/// The [`FetchState`] of [`Changed`].
|
|
||||||
ChangedState,
|
|
||||||
/// The [`Fetch`] of [`Changed`].
|
|
||||||
ChangedFetch,
|
ChangedFetch,
|
||||||
ComponentTicks::is_changed
|
ComponentTicks::is_changed
|
||||||
);
|
);
|
||||||
|
@ -745,7 +658,7 @@ impl_tick_filter!(
|
||||||
/// This is needed to implement [`ExactSizeIterator`](std::iter::ExactSizeIterator) for
|
/// This is needed to implement [`ExactSizeIterator`](std::iter::ExactSizeIterator) for
|
||||||
/// [`QueryIter`](crate::query::QueryIter) that contains archetype-level filters.
|
/// [`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.
|
/// 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
|
/// [Tuples](prim@tuple) and [`Or`] filters are automatically implemented with the trait only if its containing types
|
||||||
/// also implement the same trait.
|
/// also implement the same trait.
|
||||||
|
|
|
@ -2,7 +2,7 @@ use crate::{
|
||||||
archetype::{ArchetypeId, Archetypes},
|
archetype::{ArchetypeId, Archetypes},
|
||||||
entity::{Entities, Entity},
|
entity::{Entities, Entity},
|
||||||
prelude::World,
|
prelude::World,
|
||||||
query::{ArchetypeFilter, Fetch, QueryState, WorldQuery},
|
query::{ArchetypeFilter, QueryState, WorldQuery},
|
||||||
storage::{TableId, Tables},
|
storage::{TableId, Tables},
|
||||||
};
|
};
|
||||||
use std::{borrow::Borrow, iter::FusedIterator, marker::PhantomData, mem::MaybeUninit};
|
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())
|
.map(|id| self.archetypes[*id].len())
|
||||||
.sum();
|
.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 };
|
let min_size = if archetype_query { max_size } else { 0 };
|
||||||
(min_size, Some(max_size))
|
(min_size, Some(max_size))
|
||||||
}
|
}
|
||||||
|
@ -104,13 +104,13 @@ where
|
||||||
last_change_tick: u32,
|
last_change_tick: u32,
|
||||||
change_tick: u32,
|
change_tick: u32,
|
||||||
) -> QueryManyIter<'w, 's, Q, F, I> {
|
) -> QueryManyIter<'w, 's, Q, F, I> {
|
||||||
let fetch = Q::Fetch::init(
|
let fetch = Q::init_fetch(
|
||||||
world,
|
world,
|
||||||
&query_state.fetch_state,
|
&query_state.fetch_state,
|
||||||
last_change_tick,
|
last_change_tick,
|
||||||
change_tick,
|
change_tick,
|
||||||
);
|
);
|
||||||
let filter = F::Fetch::init(
|
let filter = F::init_fetch(
|
||||||
world,
|
world,
|
||||||
&query_state.filter_state,
|
&query_state.filter_state,
|
||||||
last_change_tick,
|
last_change_tick,
|
||||||
|
@ -153,19 +153,25 @@ where
|
||||||
|
|
||||||
// SAFETY: `archetype` is from the world that `fetch/filter` were created for,
|
// 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
|
// `fetch_state`/`filter_state` are the states that `fetch/filter` were initialized with
|
||||||
self.fetch
|
Q::set_archetype(
|
||||||
.set_archetype(&self.query_state.fetch_state, archetype, self.tables);
|
&mut self.fetch,
|
||||||
|
&self.query_state.fetch_state,
|
||||||
|
archetype,
|
||||||
|
self.tables,
|
||||||
|
);
|
||||||
// SAFETY: `table` is from the world that `fetch/filter` were created for,
|
// 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
|
// `fetch_state`/`filter_state` are the states that `fetch/filter` were initialized with
|
||||||
self.filter
|
F::set_archetype(
|
||||||
.set_archetype(&self.query_state.filter_state, archetype, self.tables);
|
&mut self.filter,
|
||||||
|
&self.query_state.filter_state,
|
||||||
|
archetype,
|
||||||
|
self.tables,
|
||||||
|
);
|
||||||
// SAFETY: set_archetype was called prior.
|
// 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
|
// `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
|
// 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
|
None
|
||||||
|
@ -370,7 +376,7 @@ where
|
||||||
let smallest = K.min(max_size - K);
|
let smallest = K.min(max_size - K);
|
||||||
let max_combinations = choose(max_size, smallest);
|
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 known_max = max_combinations.unwrap_or(usize::MAX);
|
||||||
let min_combinations = if archetype_query { known_max } else { 0 };
|
let min_combinations = if archetype_query { known_max } else { 0 };
|
||||||
(min_combinations, max_combinations)
|
(min_combinations, max_combinations)
|
||||||
|
@ -445,7 +451,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'w, 's, Q: WorldQuery, F: WorldQuery> QueryIterationCursor<'w, 's, Q, F> {
|
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(
|
unsafe fn init_empty(
|
||||||
world: &'w World,
|
world: &'w World,
|
||||||
|
@ -466,13 +472,13 @@ impl<'w, 's, Q: WorldQuery, F: WorldQuery> QueryIterationCursor<'w, 's, Q, F> {
|
||||||
last_change_tick: u32,
|
last_change_tick: u32,
|
||||||
change_tick: u32,
|
change_tick: u32,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let fetch = Q::Fetch::init(
|
let fetch = Q::init_fetch(
|
||||||
world,
|
world,
|
||||||
&query_state.fetch_state,
|
&query_state.fetch_state,
|
||||||
last_change_tick,
|
last_change_tick,
|
||||||
change_tick,
|
change_tick,
|
||||||
);
|
);
|
||||||
let filter = F::Fetch::init(
|
let filter = F::init_fetch(
|
||||||
world,
|
world,
|
||||||
&query_state.filter_state,
|
&query_state.filter_state,
|
||||||
last_change_tick,
|
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>> {
|
unsafe fn peek_last(&mut self) -> Option<QueryItem<'w, Q>> {
|
||||||
if self.current_index > 0 {
|
if self.current_index > 0 {
|
||||||
if Self::IS_DENSE {
|
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 {
|
} else {
|
||||||
Some(self.fetch.archetype_fetch(self.current_index - 1))
|
Some(Q::archetype_fetch(&mut self.fetch, self.current_index - 1))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -524,8 +530,8 @@ impl<'w, 's, Q: WorldQuery, F: WorldQuery> QueryIterationCursor<'w, 's, Q, F> {
|
||||||
let table = &tables[*table_id];
|
let table = &tables[*table_id];
|
||||||
// SAFETY: `table` is from the world that `fetch/filter` were created for,
|
// 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
|
// `fetch_state`/`filter_state` are the states that `fetch/filter` were initialized with
|
||||||
self.fetch.set_table(&query_state.fetch_state, table);
|
Q::set_table(&mut self.fetch, &query_state.fetch_state, table);
|
||||||
self.filter.set_table(&query_state.filter_state, table);
|
F::set_table(&mut self.filter, &query_state.filter_state, table);
|
||||||
self.current_len = table.len();
|
self.current_len = table.len();
|
||||||
self.current_index = 0;
|
self.current_index = 0;
|
||||||
continue;
|
continue;
|
||||||
|
@ -533,14 +539,14 @@ impl<'w, 's, Q: WorldQuery, F: WorldQuery> QueryIterationCursor<'w, 's, Q, F> {
|
||||||
|
|
||||||
// SAFETY: set_table was called prior.
|
// 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.
|
// `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;
|
self.current_index += 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// SAFETY: set_table was called prior.
|
// 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.
|
// `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;
|
self.current_index += 1;
|
||||||
return Some(item);
|
return Some(item);
|
||||||
|
@ -552,10 +558,13 @@ impl<'w, 's, Q: WorldQuery, F: WorldQuery> QueryIterationCursor<'w, 's, Q, F> {
|
||||||
let archetype = &archetypes[*archetype_id];
|
let archetype = &archetypes[*archetype_id];
|
||||||
// SAFETY: `archetype` and `tables` are from the world that `fetch/filter` were created for,
|
// 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
|
// `fetch_state`/`filter_state` are the states that `fetch/filter` were initialized with
|
||||||
self.fetch
|
Q::set_archetype(&mut self.fetch, &query_state.fetch_state, archetype, tables);
|
||||||
.set_archetype(&query_state.fetch_state, archetype, tables);
|
F::set_archetype(
|
||||||
self.filter
|
&mut self.filter,
|
||||||
.set_archetype(&query_state.filter_state, archetype, tables);
|
&query_state.filter_state,
|
||||||
|
archetype,
|
||||||
|
tables,
|
||||||
|
);
|
||||||
self.current_len = archetype.len();
|
self.current_len = archetype.len();
|
||||||
self.current_index = 0;
|
self.current_index = 0;
|
||||||
continue;
|
continue;
|
||||||
|
@ -563,14 +572,14 @@ impl<'w, 's, Q: WorldQuery, F: WorldQuery> QueryIterationCursor<'w, 's, Q, F> {
|
||||||
|
|
||||||
// SAFETY: set_archetype was called prior.
|
// 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.
|
// `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;
|
self.current_index += 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// SAFETY: set_archetype was called prior, `current_index` is an archetype index in range of the current archetype
|
// 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.
|
// `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;
|
self.current_index += 1;
|
||||||
return Some(item);
|
return Some(item);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,9 +3,7 @@ use crate::{
|
||||||
component::ComponentId,
|
component::ComponentId,
|
||||||
entity::Entity,
|
entity::Entity,
|
||||||
prelude::FromWorld,
|
prelude::FromWorld,
|
||||||
query::{
|
query::{Access, FilteredAccess, QueryCombinationIter, QueryIter, WorldQuery},
|
||||||
Access, Fetch, FetchState, FilteredAccess, QueryCombinationIter, QueryIter, WorldQuery,
|
|
||||||
},
|
|
||||||
storage::TableId,
|
storage::TableId,
|
||||||
world::{World, WorldId},
|
world::{World, WorldId},
|
||||||
};
|
};
|
||||||
|
@ -15,7 +13,7 @@ use bevy_utils::tracing::Instrument;
|
||||||
use fixedbitset::FixedBitSet;
|
use fixedbitset::FixedBitSet;
|
||||||
use std::{borrow::Borrow, fmt};
|
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.
|
/// Provides scoped access to a [`World`] state according to a given [`WorldQuery`] and query filter.
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
|
@ -84,20 +82,17 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
|
||||||
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()`.
|
/// Creates a new [`QueryState`] from a given [`World`] and inherits the result of `world.id()`.
|
||||||
pub fn new(world: &mut World) -> Self {
|
pub fn new(world: &mut World) -> Self {
|
||||||
let fetch_state = <Q::State as FetchState>::init(world);
|
let fetch_state = Q::init_state(world);
|
||||||
let filter_state = <F::State as FetchState>::init(world);
|
let filter_state = F::init_state(world);
|
||||||
|
|
||||||
let mut component_access = FilteredAccess::default();
|
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
|
// 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
|
// 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.
|
// because they are evaluated *before* a specific reference is constructed.
|
||||||
let mut filter_component_access = FilteredAccess::default();
|
let mut filter_component_access = FilteredAccess::default();
|
||||||
QueryFetch::<'static, F>::update_component_access(
|
F::update_component_access(&filter_state, &mut filter_component_access);
|
||||||
&filter_state,
|
|
||||||
&mut filter_component_access,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Merge the temporary filter access with the main access. This ensures that filter access is
|
// 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).
|
// 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`].
|
/// Creates a new [`Archetype`].
|
||||||
pub fn new_archetype(&mut self, archetype: &Archetype) {
|
pub fn new_archetype(&mut self, archetype: &Archetype) {
|
||||||
if self
|
if Q::matches_component_set(&self.fetch_state, &|id| archetype.contains(id))
|
||||||
.fetch_state
|
&& F::matches_component_set(&self.filter_state, &|id| archetype.contains(id))
|
||||||
.matches_component_set(&|id| archetype.contains(id))
|
|
||||||
&& self
|
|
||||||
.filter_state
|
|
||||||
.matches_component_set(&|id| archetype.contains(id))
|
|
||||||
{
|
{
|
||||||
QueryFetch::<'static, Q>::update_archetype_component_access(
|
Q::update_archetype_component_access(
|
||||||
&self.fetch_state,
|
&self.fetch_state,
|
||||||
archetype,
|
archetype,
|
||||||
&mut self.archetype_component_access,
|
&mut self.archetype_component_access,
|
||||||
);
|
);
|
||||||
QueryFetch::<'static, F>::update_archetype_component_access(
|
F::update_archetype_component_access(
|
||||||
&self.filter_state,
|
&self.filter_state,
|
||||||
archetype,
|
archetype,
|
||||||
&mut self.archetype_component_access,
|
&mut self.archetype_component_access,
|
||||||
|
@ -408,19 +399,23 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
|
||||||
return Err(QueryEntityError::QueryDoesNotMatch(entity));
|
return Err(QueryEntityError::QueryDoesNotMatch(entity));
|
||||||
}
|
}
|
||||||
let archetype = &world.archetypes[location.archetype_id];
|
let archetype = &world.archetypes[location.archetype_id];
|
||||||
let mut fetch =
|
let mut fetch = Q::init_fetch(world, &self.fetch_state, last_change_tick, change_tick);
|
||||||
<QueryFetch<Q> as Fetch>::init(world, &self.fetch_state, last_change_tick, change_tick);
|
let mut filter = F::init_fetch(world, &self.filter_state, last_change_tick, change_tick);
|
||||||
let mut filter = <QueryFetch<F> as Fetch>::init(
|
|
||||||
world,
|
|
||||||
&self.filter_state,
|
|
||||||
last_change_tick,
|
|
||||||
change_tick,
|
|
||||||
);
|
|
||||||
|
|
||||||
fetch.set_archetype(&self.fetch_state, archetype, &world.storages().tables);
|
Q::set_archetype(
|
||||||
filter.set_archetype(&self.filter_state, archetype, &world.storages().tables);
|
&mut fetch,
|
||||||
if filter.archetype_filter_fetch(location.index) {
|
&self.fetch_state,
|
||||||
Ok(fetch.archetype_fetch(location.index))
|
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 {
|
} else {
|
||||||
Err(QueryEntityError::QueryDoesNotMatch(entity))
|
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:
|
// 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
|
// QueryIter, QueryIterationCursor, QueryManyIter, QueryCombinationIter, QueryState::for_each_unchecked_manual, QueryState::par_for_each_unchecked_manual
|
||||||
let mut fetch =
|
let mut fetch = Q::init_fetch(world, &self.fetch_state, last_change_tick, change_tick);
|
||||||
<QueryFetch<Q> as Fetch>::init(world, &self.fetch_state, last_change_tick, change_tick);
|
let mut filter = F::init_fetch(world, &self.filter_state, last_change_tick, change_tick);
|
||||||
let mut filter = <QueryFetch<F> as Fetch>::init(
|
|
||||||
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;
|
let tables = &world.storages().tables;
|
||||||
for table_id in &self.matched_table_ids {
|
for table_id in &self.matched_table_ids {
|
||||||
let table = &tables[*table_id];
|
let table = &tables[*table_id];
|
||||||
fetch.set_table(&self.fetch_state, table);
|
Q::set_table(&mut fetch, &self.fetch_state, table);
|
||||||
filter.set_table(&self.filter_state, table);
|
F::set_table(&mut filter, &self.filter_state, table);
|
||||||
|
|
||||||
for table_index in 0..table.len() {
|
for table_index in 0..table.len() {
|
||||||
if !filter.table_filter_fetch(table_index) {
|
if !F::table_filter_fetch(&mut filter, table_index) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let item = fetch.table_fetch(table_index);
|
let item = Q::table_fetch(&mut fetch, table_index);
|
||||||
func(item);
|
func(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -938,14 +927,14 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
|
||||||
let tables = &world.storages().tables;
|
let tables = &world.storages().tables;
|
||||||
for archetype_id in &self.matched_archetype_ids {
|
for archetype_id in &self.matched_archetype_ids {
|
||||||
let archetype = &archetypes[*archetype_id];
|
let archetype = &archetypes[*archetype_id];
|
||||||
fetch.set_archetype(&self.fetch_state, archetype, tables);
|
Q::set_archetype(&mut fetch, &self.fetch_state, archetype, tables);
|
||||||
filter.set_archetype(&self.filter_state, archetype, tables);
|
F::set_archetype(&mut filter, &self.filter_state, archetype, tables);
|
||||||
|
|
||||||
for archetype_index in 0..archetype.len() {
|
for archetype_index in 0..archetype.len() {
|
||||||
if !filter.archetype_filter_fetch(archetype_index) {
|
if !F::archetype_filter_fetch(&mut filter, archetype_index) {
|
||||||
continue;
|
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:
|
// 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
|
// QueryIter, QueryIterationCursor, QueryManyIter, QueryCombinationIter, QueryState::for_each_unchecked_manual, QueryState::par_for_each_unchecked_manual
|
||||||
ComputeTaskPool::get().scope(|scope| {
|
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;
|
let tables = &world.storages().tables;
|
||||||
for table_id in &self.matched_table_ids {
|
for table_id in &self.matched_table_ids {
|
||||||
let table = &tables[*table_id];
|
let table = &tables[*table_id];
|
||||||
|
@ -988,13 +977,13 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
|
||||||
let func = func.clone();
|
let func = func.clone();
|
||||||
let len = batch_size.min(table.len() - offset);
|
let len = batch_size.min(table.len() - offset);
|
||||||
let task = async move {
|
let task = async move {
|
||||||
let mut fetch = <QueryFetch<Q> as Fetch>::init(
|
let mut fetch = Q::init_fetch(
|
||||||
world,
|
world,
|
||||||
&self.fetch_state,
|
&self.fetch_state,
|
||||||
last_change_tick,
|
last_change_tick,
|
||||||
change_tick,
|
change_tick,
|
||||||
);
|
);
|
||||||
let mut filter = <QueryFetch<F> as Fetch>::init(
|
let mut filter = F::init_fetch(
|
||||||
world,
|
world,
|
||||||
&self.filter_state,
|
&self.filter_state,
|
||||||
last_change_tick,
|
last_change_tick,
|
||||||
|
@ -1002,13 +991,13 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
|
||||||
);
|
);
|
||||||
let tables = &world.storages().tables;
|
let tables = &world.storages().tables;
|
||||||
let table = &tables[*table_id];
|
let table = &tables[*table_id];
|
||||||
fetch.set_table(&self.fetch_state, table);
|
Q::set_table(&mut fetch, &self.fetch_state, table);
|
||||||
filter.set_table(&self.filter_state, table);
|
F::set_table(&mut filter, &self.filter_state, table);
|
||||||
for table_index in offset..offset + len {
|
for table_index in offset..offset + len {
|
||||||
if !filter.table_filter_fetch(table_index) {
|
if !F::table_filter_fetch(&mut filter, table_index) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let item = fetch.table_fetch(table_index);
|
let item = Q::table_fetch(&mut fetch, table_index);
|
||||||
func(item);
|
func(item);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1034,13 +1023,13 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
|
||||||
let func = func.clone();
|
let func = func.clone();
|
||||||
let len = batch_size.min(archetype.len() - offset);
|
let len = batch_size.min(archetype.len() - offset);
|
||||||
let task = async move {
|
let task = async move {
|
||||||
let mut fetch = <QueryFetch<Q> as Fetch>::init(
|
let mut fetch = Q::init_fetch(
|
||||||
world,
|
world,
|
||||||
&self.fetch_state,
|
&self.fetch_state,
|
||||||
last_change_tick,
|
last_change_tick,
|
||||||
change_tick,
|
change_tick,
|
||||||
);
|
);
|
||||||
let mut filter = <QueryFetch<F> as Fetch>::init(
|
let mut filter = F::init_fetch(
|
||||||
world,
|
world,
|
||||||
&self.filter_state,
|
&self.filter_state,
|
||||||
last_change_tick,
|
last_change_tick,
|
||||||
|
@ -1048,14 +1037,14 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
|
||||||
);
|
);
|
||||||
let tables = &world.storages().tables;
|
let tables = &world.storages().tables;
|
||||||
let archetype = &world.archetypes[*archetype_id];
|
let archetype = &world.archetypes[*archetype_id];
|
||||||
fetch.set_archetype(&self.fetch_state, archetype, tables);
|
Q::set_archetype(&mut fetch, &self.fetch_state, archetype, tables);
|
||||||
filter.set_archetype(&self.filter_state, archetype, tables);
|
F::set_archetype(&mut filter, &self.filter_state, archetype, tables);
|
||||||
|
|
||||||
for archetype_index in offset..offset + len {
|
for archetype_index in offset..offset + len {
|
||||||
if !filter.archetype_filter_fetch(archetype_index) {
|
if !F::archetype_filter_fetch(&mut filter, archetype_index) {
|
||||||
continue;
|
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: `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: required because of the requirements on the impl of `ReadOnlySystemParamFetch` for `QueryState<&'static mut Foo>`
|
||||||
= note: 2 redundant requirements hidden
|
= 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`
|
note: required by a bound in `assert_readonly`
|
||||||
--> tests/ui/system_param_derive_readonly.rs:23:32
|
--> tests/ui/system_param_derive_readonly.rs:23:32
|
||||||
|
|
|
|
||||||
|
|
Loading…
Reference in a new issue