mirror of
https://github.com/bevyengine/bevy
synced 2024-11-25 14:10:19 +00:00
Split WorldQuery into WorldQueryData and WorldQueryFilter (#9918)
# Objective - Fixes #7680 - This is an updated for https://github.com/bevyengine/bevy/pull/8899 which had the same objective but fell a long way behind the latest changes ## Solution The traits `WorldQueryData : WorldQuery` and `WorldQueryFilter : WorldQuery` have been added and some of the types and functions from `WorldQuery` has been moved into them. `ReadOnlyWorldQuery` has been replaced with `ReadOnlyWorldQueryData`. `WorldQueryFilter` is safe (as long as `WorldQuery` is implemented safely). `WorldQueryData` is unsafe - safely implementing it requires that `Self::ReadOnly` is a readonly version of `Self` (this used to be a safety requirement of `WorldQuery`) The type parameters `Q` and `F` of `Query` must now implement `WorldQueryData` and `WorldQueryFilter` respectively. This makes it impossible to accidentally use a filter in the data position or vice versa which was something that could lead to bugs. ~~Compile failure tests have been added to check this.~~ It was previously sometimes useful to use `Option<With<T>>` in the data position. Use `Has<T>` instead in these cases. The `WorldQuery` derive macro has been split into separate derive macros for `WorldQueryData` and `WorldQueryFilter`. Previously it was possible to derive both `WorldQuery` for a struct that had a mixture of data and filter items. This would not work correctly in some cases but could be a useful pattern in others. *This is no longer possible.* --- ## Notes - The changes outside of `bevy_ecs` are all changing type parameters to the new types, updating the macro use, or replacing `Option<With<T>>` with `Has<T>`. - All `WorldQueryData` types always returned `true` for `IS_ARCHETYPAL` so I moved it to `WorldQueryFilter` and replaced all calls to it with `true`. That should be the only logic change outside of the macro generation code. - `Changed<T>` and `Added<T>` were being generated by a macro that I have expanded. Happy to revert that if desired. - The two derive macros share some functions for implementing `WorldQuery` but the tidiest way I could find to implement them was to give them a ton of arguments and ask clippy to ignore that. ## Changelog ### Changed - Split `WorldQuery` into `WorldQueryData` and `WorldQueryFilter` which now have separate derive macros. It is not possible to derive both for the same type. - `Query` now requires that the first type argument implements `WorldQueryData` and the second implements `WorldQueryFilter` ## Migration Guide - Update derives ```rust // old #[derive(WorldQuery)] #[world_query(mutable, derive(Debug))] struct CustomQuery { entity: Entity, a: &'static mut ComponentA } #[derive(WorldQuery)] struct QueryFilter { _c: With<ComponentC> } // new #[derive(WorldQueryData)] #[world_query_data(mutable, derive(Debug))] struct CustomQuery { entity: Entity, a: &'static mut ComponentA, } #[derive(WorldQueryFilter)] struct QueryFilter { _c: With<ComponentC> } ``` - Replace `Option<With<T>>` with `Has<T>` ```rust /// old fn my_system(query: Query<(Entity, Option<With<ComponentA>>)>) { for (entity, has_a_option) in query.iter(){ let has_a:bool = has_a_option.is_some(); //todo!() } } /// new fn my_system(query: Query<(Entity, Has<ComponentA>)>) { for (entity, has_a) in query.iter(){ //todo!() } } ``` - Fix queries which had filters in the data position or vice versa. ```rust // old fn my_system(query: Query<(Entity, With<ComponentA>)>) { for (entity, _) in query.iter(){ //todo!() } } // new fn my_system(query: Query<Entity, With<ComponentA>>) { for entity in query.iter(){ //todo!() } } // old fn my_system(query: Query<AnyOf<(&ComponentA, With<ComponentB>)>>) { for (entity, _) in query.iter(){ //todo!() } } // new fn my_system(query: Query<Option<&ComponentA>, Or<(With<ComponentA>, With<ComponentB>)>>) { for entity in query.iter(){ //todo!() } } ``` --------- Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
This commit is contained in:
parent
90958104cb
commit
f0a8994f55
31 changed files with 1898 additions and 1321 deletions
|
@ -1,6 +1,6 @@
|
||||||
use bevy_ecs::{
|
use bevy_ecs::query::WorldQueryData;
|
||||||
component::Component, entity::Entity, query::WorldQuery, reflect::ReflectComponent,
|
use bevy_ecs::{component::Component, entity::Entity, reflect::ReflectComponent};
|
||||||
};
|
|
||||||
use bevy_reflect::std_traits::ReflectDefault;
|
use bevy_reflect::std_traits::ReflectDefault;
|
||||||
use bevy_reflect::Reflect;
|
use bevy_reflect::Reflect;
|
||||||
use bevy_utils::AHasher;
|
use bevy_utils::AHasher;
|
||||||
|
@ -102,7 +102,7 @@ impl std::fmt::Debug for Name {
|
||||||
/// }
|
/// }
|
||||||
/// # bevy_ecs::system::assert_is_system(increment_score);
|
/// # bevy_ecs::system::assert_is_system(increment_score);
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(WorldQuery)]
|
#[derive(WorldQueryData)]
|
||||||
pub struct DebugName {
|
pub struct DebugName {
|
||||||
/// A [`Name`] that the entity might have that is displayed if available.
|
/// A [`Name`] that the entity might have that is displayed if available.
|
||||||
pub name: Option<&'static Name>,
|
pub name: Option<&'static Name>,
|
||||||
|
|
|
@ -1,483 +0,0 @@
|
||||||
use bevy_macro_utils::ensure_no_collision;
|
|
||||||
use proc_macro::TokenStream;
|
|
||||||
use proc_macro2::{Ident, Span};
|
|
||||||
use quote::{format_ident, quote, ToTokens};
|
|
||||||
use syn::{
|
|
||||||
parse::{Parse, ParseStream},
|
|
||||||
parse_macro_input, parse_quote,
|
|
||||||
punctuated::Punctuated,
|
|
||||||
token::Comma,
|
|
||||||
Attribute, Data, DataStruct, DeriveInput, Field, Index, Meta,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::bevy_ecs_path;
|
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
struct FetchStructAttributes {
|
|
||||||
pub is_mutable: bool,
|
|
||||||
pub derive_args: Punctuated<syn::Meta, syn::token::Comma>,
|
|
||||||
}
|
|
||||||
|
|
||||||
static MUTABLE_ATTRIBUTE_NAME: &str = "mutable";
|
|
||||||
static DERIVE_ATTRIBUTE_NAME: &str = "derive";
|
|
||||||
|
|
||||||
mod field_attr_keywords {
|
|
||||||
syn::custom_keyword!(ignore);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub static WORLD_QUERY_ATTRIBUTE_NAME: &str = "world_query";
|
|
||||||
|
|
||||||
pub fn derive_world_query_impl(input: TokenStream) -> TokenStream {
|
|
||||||
let tokens = input.clone();
|
|
||||||
|
|
||||||
let ast = parse_macro_input!(input as DeriveInput);
|
|
||||||
let visibility = ast.vis;
|
|
||||||
|
|
||||||
let mut fetch_struct_attributes = FetchStructAttributes::default();
|
|
||||||
for attr in &ast.attrs {
|
|
||||||
if !attr
|
|
||||||
.path()
|
|
||||||
.get_ident()
|
|
||||||
.map_or(false, |ident| ident == WORLD_QUERY_ATTRIBUTE_NAME)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
attr.parse_args_with(|input: ParseStream| {
|
|
||||||
let meta = input.parse_terminated(syn::Meta::parse, Comma)?;
|
|
||||||
for meta in meta {
|
|
||||||
let ident = meta.path().get_ident().unwrap_or_else(|| {
|
|
||||||
panic!(
|
|
||||||
"Unrecognized attribute: `{}`",
|
|
||||||
meta.path().to_token_stream()
|
|
||||||
)
|
|
||||||
});
|
|
||||||
if ident == MUTABLE_ATTRIBUTE_NAME {
|
|
||||||
if let syn::Meta::Path(_) = meta {
|
|
||||||
fetch_struct_attributes.is_mutable = true;
|
|
||||||
} else {
|
|
||||||
panic!(
|
|
||||||
"The `{MUTABLE_ATTRIBUTE_NAME}` attribute is expected to have no value or arguments",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else if ident == DERIVE_ATTRIBUTE_NAME {
|
|
||||||
if let syn::Meta::List(meta_list) = meta {
|
|
||||||
meta_list.parse_nested_meta(|meta| {
|
|
||||||
fetch_struct_attributes.derive_args.push(Meta::Path(meta.path));
|
|
||||||
Ok(())
|
|
||||||
})?;
|
|
||||||
} else {
|
|
||||||
panic!(
|
|
||||||
"Expected a structured list within the `{DERIVE_ATTRIBUTE_NAME}` attribute",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
panic!(
|
|
||||||
"Unrecognized attribute: `{}`",
|
|
||||||
meta.path().to_token_stream()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
})
|
|
||||||
.unwrap_or_else(|_| panic!("Invalid `{WORLD_QUERY_ATTRIBUTE_NAME}` attribute format"));
|
|
||||||
}
|
|
||||||
|
|
||||||
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 = {
|
|
||||||
let mut generics = ast.generics;
|
|
||||||
generics.params.insert(0, parse_quote!('__w));
|
|
||||||
generics
|
|
||||||
};
|
|
||||||
let (user_impl_generics_with_world, user_ty_generics_with_world, user_where_clauses_with_world) =
|
|
||||||
user_generics_with_world.split_for_impl();
|
|
||||||
|
|
||||||
let struct_name = ast.ident;
|
|
||||||
let read_only_struct_name = if fetch_struct_attributes.is_mutable {
|
|
||||||
Ident::new(&format!("{struct_name}ReadOnly"), Span::call_site())
|
|
||||||
} else {
|
|
||||||
#[allow(clippy::redundant_clone)]
|
|
||||||
struct_name.clone()
|
|
||||||
};
|
|
||||||
|
|
||||||
let item_struct_name = Ident::new(&format!("{struct_name}Item"), Span::call_site());
|
|
||||||
let read_only_item_struct_name = if fetch_struct_attributes.is_mutable {
|
|
||||||
Ident::new(&format!("{struct_name}ReadOnlyItem"), Span::call_site())
|
|
||||||
} else {
|
|
||||||
#[allow(clippy::redundant_clone)]
|
|
||||||
item_struct_name.clone()
|
|
||||||
};
|
|
||||||
|
|
||||||
let fetch_struct_name = Ident::new(&format!("{struct_name}Fetch"), Span::call_site());
|
|
||||||
let fetch_struct_name = ensure_no_collision(fetch_struct_name, tokens.clone());
|
|
||||||
let read_only_fetch_struct_name = if fetch_struct_attributes.is_mutable {
|
|
||||||
let new_ident = Ident::new(&format!("{struct_name}ReadOnlyFetch"), Span::call_site());
|
|
||||||
ensure_no_collision(new_ident, tokens.clone())
|
|
||||||
} else {
|
|
||||||
#[allow(clippy::redundant_clone)]
|
|
||||||
fetch_struct_name.clone()
|
|
||||||
};
|
|
||||||
|
|
||||||
let marker_name =
|
|
||||||
ensure_no_collision(format_ident!("_world_query_derive_marker"), tokens.clone());
|
|
||||||
|
|
||||||
// Generate a name for the state struct that doesn't conflict
|
|
||||||
// with the struct definition.
|
|
||||||
let state_struct_name = Ident::new(&format!("{struct_name}State"), Span::call_site());
|
|
||||||
let state_struct_name = ensure_no_collision(state_struct_name, tokens);
|
|
||||||
|
|
||||||
let Data::Struct(DataStruct { fields, .. }) = &ast.data else {
|
|
||||||
return syn::Error::new(
|
|
||||||
Span::call_site(),
|
|
||||||
"#[derive(WorldQuery)]` only supports structs",
|
|
||||||
)
|
|
||||||
.into_compile_error()
|
|
||||||
.into();
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut field_attrs = Vec::new();
|
|
||||||
let mut field_visibilities = Vec::new();
|
|
||||||
let mut field_idents = Vec::new();
|
|
||||||
let mut named_field_idents = Vec::new();
|
|
||||||
let mut field_types = Vec::new();
|
|
||||||
let mut read_only_field_types = Vec::new();
|
|
||||||
for (i, field) in fields.iter().enumerate() {
|
|
||||||
let attrs = match read_world_query_field_info(field) {
|
|
||||||
Ok(WorldQueryFieldInfo { attrs }) => attrs,
|
|
||||||
Err(e) => return e.into_compile_error().into(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let named_field_ident = field
|
|
||||||
.ident
|
|
||||||
.as_ref()
|
|
||||||
.cloned()
|
|
||||||
.unwrap_or_else(|| format_ident!("f{i}"));
|
|
||||||
let i = Index::from(i);
|
|
||||||
let field_ident = field
|
|
||||||
.ident
|
|
||||||
.as_ref()
|
|
||||||
.map_or(quote! { #i }, |i| quote! { #i });
|
|
||||||
field_idents.push(field_ident);
|
|
||||||
named_field_idents.push(named_field_ident);
|
|
||||||
field_attrs.push(attrs);
|
|
||||||
field_visibilities.push(field.vis.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));
|
|
||||||
}
|
|
||||||
|
|
||||||
let derive_args = &fetch_struct_attributes.derive_args;
|
|
||||||
// `#[derive()]` is valid syntax
|
|
||||||
let derive_macro_call = quote! { #[derive(#derive_args)] };
|
|
||||||
|
|
||||||
let impl_fetch = |is_readonly: bool| {
|
|
||||||
let struct_name = if is_readonly {
|
|
||||||
&read_only_struct_name
|
|
||||||
} else {
|
|
||||||
&struct_name
|
|
||||||
};
|
|
||||||
let item_struct_name = if is_readonly {
|
|
||||||
&read_only_item_struct_name
|
|
||||||
} else {
|
|
||||||
&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
|
|
||||||
};
|
|
||||||
|
|
||||||
let item_struct = match fields {
|
|
||||||
syn::Fields::Named(_) => quote! {
|
|
||||||
#derive_macro_call
|
|
||||||
#[doc = "Automatically generated [`WorldQuery`] item type for [`"]
|
|
||||||
#[doc = stringify!(#struct_name)]
|
|
||||||
#[doc = "`], returned when iterating over query results."]
|
|
||||||
#[automatically_derived]
|
|
||||||
#visibility struct #item_struct_name #user_impl_generics_with_world #user_where_clauses_with_world {
|
|
||||||
#(#(#field_attrs)* #field_visibilities #field_idents: <#field_types as #path::query::WorldQuery>::Item<'__w>,)*
|
|
||||||
}
|
|
||||||
},
|
|
||||||
syn::Fields::Unnamed(_) => quote! {
|
|
||||||
#derive_macro_call
|
|
||||||
#[doc = "Automatically generated [`WorldQuery`] item type for [`"]
|
|
||||||
#[doc = stringify!(#struct_name)]
|
|
||||||
#[doc = "`], returned when iterating over query results."]
|
|
||||||
#[automatically_derived]
|
|
||||||
#visibility struct #item_struct_name #user_impl_generics_with_world #user_where_clauses_with_world(
|
|
||||||
#( #field_visibilities <#field_types as #path::query::WorldQuery>::Item<'__w>, )*
|
|
||||||
);
|
|
||||||
},
|
|
||||||
syn::Fields::Unit => quote! {
|
|
||||||
#[doc = "Automatically generated [`WorldQuery`] item type for [`"]
|
|
||||||
#[doc = stringify!(#struct_name)]
|
|
||||||
#[doc = "`], returned when iterating over query results."]
|
|
||||||
#[automatically_derived]
|
|
||||||
#visibility type #item_struct_name #user_ty_generics_with_world = #struct_name #user_ty_generics;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let query_impl = quote! {
|
|
||||||
#[doc(hidden)]
|
|
||||||
#[doc = "Automatically generated internal [`WorldQuery`] fetch type for [`"]
|
|
||||||
#[doc = stringify!(#struct_name)]
|
|
||||||
#[doc = "`], used to define the world data accessed by this query."]
|
|
||||||
#[automatically_derived]
|
|
||||||
#visibility struct #fetch_struct_name #user_impl_generics_with_world #user_where_clauses_with_world {
|
|
||||||
#(#named_field_idents: <#field_types as #path::query::WorldQuery>::Fetch<'__w>,)*
|
|
||||||
#marker_name: &'__w (),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl #user_impl_generics_with_world Clone for #fetch_struct_name #user_ty_generics_with_world
|
|
||||||
#user_where_clauses_with_world {
|
|
||||||
fn clone(&self) -> Self {
|
|
||||||
Self {
|
|
||||||
#(#named_field_idents: self.#named_field_idents.clone(),)*
|
|
||||||
#marker_name: &(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// SAFETY: `update_component_access` and `update_archetype_component_access` are called on every field
|
|
||||||
unsafe impl #user_impl_generics #path::query::WorldQuery
|
|
||||||
for #struct_name #user_ty_generics #user_where_clauses {
|
|
||||||
|
|
||||||
type Item<'__w> = #item_struct_name #user_ty_generics_with_world;
|
|
||||||
type Fetch<'__w> = #fetch_struct_name #user_ty_generics_with_world;
|
|
||||||
type ReadOnly = #read_only_struct_name #user_ty_generics;
|
|
||||||
type State = #state_struct_name #user_ty_generics;
|
|
||||||
|
|
||||||
fn shrink<'__wlong: '__wshort, '__wshort>(
|
|
||||||
item: <#struct_name #user_ty_generics as #path::query::WorldQuery>::Item<'__wlong>
|
|
||||||
) -> <#struct_name #user_ty_generics as #path::query::WorldQuery>::Item<'__wshort> {
|
|
||||||
#item_struct_name {
|
|
||||||
#(
|
|
||||||
#field_idents: <#field_types>::shrink(item.#field_idents),
|
|
||||||
)*
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn init_fetch<'__w>(
|
|
||||||
_world: #path::world::unsafe_world_cell::UnsafeWorldCell<'__w>,
|
|
||||||
state: &Self::State,
|
|
||||||
_last_run: #path::component::Tick,
|
|
||||||
_this_run: #path::component::Tick,
|
|
||||||
) -> <Self as #path::query::WorldQuery>::Fetch<'__w> {
|
|
||||||
#fetch_struct_name {
|
|
||||||
#(#named_field_idents:
|
|
||||||
<#field_types>::init_fetch(
|
|
||||||
_world,
|
|
||||||
&state.#named_field_idents,
|
|
||||||
_last_run,
|
|
||||||
_this_run,
|
|
||||||
),
|
|
||||||
)*
|
|
||||||
#marker_name: &(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const IS_DENSE: bool = true #(&& <#field_types>::IS_DENSE)*;
|
|
||||||
|
|
||||||
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<'__w>(
|
|
||||||
_fetch: &mut <Self as #path::query::WorldQuery>::Fetch<'__w>,
|
|
||||||
_state: &Self::State,
|
|
||||||
_archetype: &'__w #path::archetype::Archetype,
|
|
||||||
_table: &'__w #path::storage::Table
|
|
||||||
) {
|
|
||||||
#(<#field_types>::set_archetype(&mut _fetch.#named_field_idents, &_state.#named_field_idents, _archetype, _table);)*
|
|
||||||
}
|
|
||||||
|
|
||||||
/// SAFETY: we call `set_table` for each member that implements `Fetch`
|
|
||||||
#[inline]
|
|
||||||
unsafe fn set_table<'__w>(
|
|
||||||
_fetch: &mut <Self as #path::query::WorldQuery>::Fetch<'__w>,
|
|
||||||
_state: &Self::State,
|
|
||||||
_table: &'__w #path::storage::Table
|
|
||||||
) {
|
|
||||||
#(<#field_types>::set_table(&mut _fetch.#named_field_idents, &_state.#named_field_idents, _table);)*
|
|
||||||
}
|
|
||||||
|
|
||||||
/// SAFETY: we call `fetch` for each member that implements `Fetch`.
|
|
||||||
#[inline(always)]
|
|
||||||
unsafe fn fetch<'__w>(
|
|
||||||
_fetch: &mut <Self as #path::query::WorldQuery>::Fetch<'__w>,
|
|
||||||
_entity: #path::entity::Entity,
|
|
||||||
_table_row: #path::storage::TableRow,
|
|
||||||
) -> <Self as #path::query::WorldQuery>::Item<'__w> {
|
|
||||||
Self::Item {
|
|
||||||
#(#field_idents: <#field_types>::fetch(&mut _fetch.#named_field_idents, _entity, _table_row),)*
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
|
||||||
#[inline(always)]
|
|
||||||
unsafe fn filter_fetch<'__w>(
|
|
||||||
_fetch: &mut <Self as #path::query::WorldQuery>::Fetch<'__w>,
|
|
||||||
_entity: #path::entity::Entity,
|
|
||||||
_table_row: #path::storage::TableRow,
|
|
||||||
) -> bool {
|
|
||||||
true #(&& <#field_types>::filter_fetch(&mut _fetch.#named_field_idents, _entity, _table_row))*
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update_component_access(state: &Self::State, _access: &mut #path::query::FilteredAccess<#path::component::ComponentId>) {
|
|
||||||
#( <#field_types>::update_component_access(&state.#named_field_idents, _access); )*
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update_archetype_component_access(
|
|
||||||
state: &Self::State,
|
|
||||||
_archetype: &#path::archetype::Archetype,
|
|
||||||
_access: &mut #path::query::Access<#path::archetype::ArchetypeComponentId>
|
|
||||||
) {
|
|
||||||
#(
|
|
||||||
<#field_types>::update_archetype_component_access(&state.#named_field_idents, _archetype, _access);
|
|
||||||
)*
|
|
||||||
}
|
|
||||||
|
|
||||||
fn init_state(world: &mut #path::world::World) -> #state_struct_name #user_ty_generics {
|
|
||||||
#state_struct_name {
|
|
||||||
#(#named_field_idents: <#field_types>::init_state(world),)*
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn matches_component_set(state: &Self::State, _set_contains_id: &impl Fn(#path::component::ComponentId) -> bool) -> bool {
|
|
||||||
true #(&& <#field_types>::matches_component_set(&state.#named_field_idents, _set_contains_id))*
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
(item_struct, query_impl)
|
|
||||||
};
|
|
||||||
|
|
||||||
let (mutable_struct, mutable_impl) = impl_fetch(false);
|
|
||||||
let (read_only_struct, read_only_impl) = if fetch_struct_attributes.is_mutable {
|
|
||||||
let (readonly_state, read_only_impl) = impl_fetch(true);
|
|
||||||
let read_only_structs = quote! {
|
|
||||||
#[doc = "Automatically generated [`WorldQuery`] type for a read-only variant of [`"]
|
|
||||||
#[doc = stringify!(#struct_name)]
|
|
||||||
#[doc = "`]."]
|
|
||||||
#[automatically_derived]
|
|
||||||
#visibility struct #read_only_struct_name #user_impl_generics #user_where_clauses {
|
|
||||||
#(
|
|
||||||
#[doc = "Automatically generated read-only field for accessing `"]
|
|
||||||
#[doc = stringify!(#field_types)]
|
|
||||||
#[doc = "`."]
|
|
||||||
#field_visibilities #named_field_idents: #read_only_field_types,
|
|
||||||
)*
|
|
||||||
}
|
|
||||||
|
|
||||||
#readonly_state
|
|
||||||
};
|
|
||||||
(read_only_structs, read_only_impl)
|
|
||||||
} else {
|
|
||||||
(quote! {}, quote! {})
|
|
||||||
};
|
|
||||||
|
|
||||||
let read_only_asserts = if fetch_struct_attributes.is_mutable {
|
|
||||||
quote! {
|
|
||||||
// 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::<#read_only_field_types>(); )*
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
quote! {
|
|
||||||
// Statically checks that the safety guarantee of `ReadOnlyWorldQuery` for `$fetch_struct_name` actually holds true.
|
|
||||||
// We need this to make sure that we don't compile `ReadOnlyWorldQuery` if our struct contains nested `WorldQuery`
|
|
||||||
// members that don't implement it. I.e.:
|
|
||||||
// ```
|
|
||||||
// #[derive(WorldQuery)]
|
|
||||||
// pub struct Foo { a: &'static mut MyComponent }
|
|
||||||
// ```
|
|
||||||
#( assert_readonly::<#field_types>(); )*
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
TokenStream::from(quote! {
|
|
||||||
#mutable_struct
|
|
||||||
|
|
||||||
#read_only_struct
|
|
||||||
|
|
||||||
/// 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 {}
|
|
||||||
|
|
||||||
const _: () = {
|
|
||||||
#[doc(hidden)]
|
|
||||||
#[doc = "Automatically generated internal [`WorldQuery`] state type for [`"]
|
|
||||||
#[doc = stringify!(#struct_name)]
|
|
||||||
#[doc = "`], used for caching."]
|
|
||||||
#[automatically_derived]
|
|
||||||
#visibility struct #state_struct_name #user_impl_generics #user_where_clauses {
|
|
||||||
#(#named_field_idents: <#field_types as #path::query::WorldQuery>::State,)*
|
|
||||||
}
|
|
||||||
|
|
||||||
#mutable_impl
|
|
||||||
|
|
||||||
#read_only_impl
|
|
||||||
};
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
const _: () = {
|
|
||||||
fn assert_readonly<T>()
|
|
||||||
where
|
|
||||||
T: #path::query::ReadOnlyWorldQuery,
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// We generate a readonly assertion for every struct member.
|
|
||||||
fn assert_all #user_impl_generics_with_world () #user_where_clauses_with_world {
|
|
||||||
#read_only_asserts
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// The original struct will most likely be left unused. As we don't want our users having
|
|
||||||
// to specify `#[allow(dead_code)]` for their custom queries, we are using this cursed
|
|
||||||
// workaround.
|
|
||||||
#[allow(dead_code)]
|
|
||||||
const _: () = {
|
|
||||||
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;)*
|
|
||||||
#(q2.#field_idents;)*
|
|
||||||
}
|
|
||||||
};
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
struct WorldQueryFieldInfo {
|
|
||||||
/// All field attributes except for `world_query` ones.
|
|
||||||
attrs: Vec<Attribute>,
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_world_query_field_info(field: &Field) -> syn::Result<WorldQueryFieldInfo> {
|
|
||||||
let mut attrs = Vec::new();
|
|
||||||
for attr in &field.attrs {
|
|
||||||
if attr
|
|
||||||
.path()
|
|
||||||
.get_ident()
|
|
||||||
.map_or(false, |ident| ident == WORLD_QUERY_ATTRIBUTE_NAME)
|
|
||||||
{
|
|
||||||
return Err(syn::Error::new_spanned(
|
|
||||||
attr,
|
|
||||||
"#[derive(WorldQuery)] does not support field attributes.",
|
|
||||||
));
|
|
||||||
}
|
|
||||||
attrs.push(attr.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(WorldQueryFieldInfo { attrs })
|
|
||||||
}
|
|
|
@ -1,10 +1,15 @@
|
||||||
extern crate proc_macro;
|
extern crate proc_macro;
|
||||||
|
|
||||||
mod component;
|
mod component;
|
||||||
mod fetch;
|
|
||||||
mod states;
|
mod states;
|
||||||
|
mod world_query;
|
||||||
|
mod world_query_data;
|
||||||
|
mod world_query_filter;
|
||||||
|
|
||||||
use crate::fetch::derive_world_query_impl;
|
use crate::{
|
||||||
|
world_query_data::derive_world_query_data_impl,
|
||||||
|
world_query_filter::derive_world_query_filter_impl,
|
||||||
|
};
|
||||||
use bevy_macro_utils::{derive_label, ensure_no_collision, get_struct_fields, BevyManifest};
|
use bevy_macro_utils::{derive_label, ensure_no_collision, get_struct_fields, BevyManifest};
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use proc_macro2::Span;
|
use proc_macro2::Span;
|
||||||
|
@ -445,10 +450,16 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implement `WorldQuery` to use a struct as a parameter in a query
|
/// Implement `WorldQueryData` to use a struct as a data parameter in a query
|
||||||
#[proc_macro_derive(WorldQuery, attributes(world_query))]
|
#[proc_macro_derive(WorldQueryData, attributes(world_query_data))]
|
||||||
pub fn derive_world_query(input: TokenStream) -> TokenStream {
|
pub fn derive_world_query_data(input: TokenStream) -> TokenStream {
|
||||||
derive_world_query_impl(input)
|
derive_world_query_data_impl(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Implement `WorldQueryFilter` to use a struct as a filter parameter in a query
|
||||||
|
#[proc_macro_derive(WorldQueryFilter, attributes(world_query_filter))]
|
||||||
|
pub fn derive_world_query_filter(input: TokenStream) -> TokenStream {
|
||||||
|
derive_world_query_filter_impl(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Derive macro generating an impl of the trait `ScheduleLabel`.
|
/// Derive macro generating an impl of the trait `ScheduleLabel`.
|
||||||
|
|
189
crates/bevy_ecs/macros/src/world_query.rs
Normal file
189
crates/bevy_ecs/macros/src/world_query.rs
Normal file
|
@ -0,0 +1,189 @@
|
||||||
|
use proc_macro2::Ident;
|
||||||
|
use quote::quote;
|
||||||
|
use syn::{Attribute, Fields, ImplGenerics, TypeGenerics, Visibility, WhereClause};
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
pub(crate) fn item_struct(
|
||||||
|
path: &syn::Path,
|
||||||
|
fields: &Fields,
|
||||||
|
derive_macro_call: &proc_macro2::TokenStream,
|
||||||
|
struct_name: &Ident,
|
||||||
|
visibility: &Visibility,
|
||||||
|
item_struct_name: &Ident,
|
||||||
|
field_types: &Vec<proc_macro2::TokenStream>,
|
||||||
|
user_impl_generics_with_world: &ImplGenerics,
|
||||||
|
field_attrs: &Vec<Vec<Attribute>>,
|
||||||
|
field_visibilities: &Vec<Visibility>,
|
||||||
|
field_idents: &Vec<proc_macro2::TokenStream>,
|
||||||
|
user_ty_generics: &TypeGenerics,
|
||||||
|
user_ty_generics_with_world: &TypeGenerics,
|
||||||
|
user_where_clauses_with_world: Option<&WhereClause>,
|
||||||
|
) -> proc_macro2::TokenStream {
|
||||||
|
let item_attrs = quote!(
|
||||||
|
#[doc = "Automatically generated [`WorldQuery`] item type for [`"]
|
||||||
|
#[doc = stringify!(#struct_name)]
|
||||||
|
#[doc = "`], returned when iterating over query results."]
|
||||||
|
#[automatically_derived]
|
||||||
|
);
|
||||||
|
|
||||||
|
match fields {
|
||||||
|
syn::Fields::Named(_) => quote! {
|
||||||
|
#derive_macro_call
|
||||||
|
#item_attrs
|
||||||
|
#visibility struct #item_struct_name #user_impl_generics_with_world #user_where_clauses_with_world {
|
||||||
|
#(#(#field_attrs)* #field_visibilities #field_idents: <#field_types as #path::query::WorldQuery>::Item<'__w>,)*
|
||||||
|
}
|
||||||
|
},
|
||||||
|
syn::Fields::Unnamed(_) => quote! {
|
||||||
|
#derive_macro_call
|
||||||
|
#item_attrs
|
||||||
|
#[automatically_derived]
|
||||||
|
#visibility struct #item_struct_name #user_impl_generics_with_world #user_where_clauses_with_world(
|
||||||
|
#( #field_visibilities <#field_types as #path::query::WorldQuery>::Item<'__w>, )*
|
||||||
|
);
|
||||||
|
},
|
||||||
|
syn::Fields::Unit => quote! {
|
||||||
|
#item_attrs
|
||||||
|
#visibility type #item_struct_name #user_ty_generics_with_world = #struct_name #user_ty_generics;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
pub(crate) fn world_query_impl(
|
||||||
|
path: &syn::Path,
|
||||||
|
struct_name: &Ident,
|
||||||
|
visibility: &Visibility,
|
||||||
|
item_struct_name: &Ident,
|
||||||
|
fetch_struct_name: &Ident,
|
||||||
|
field_types: &Vec<proc_macro2::TokenStream>,
|
||||||
|
user_impl_generics: &ImplGenerics,
|
||||||
|
user_impl_generics_with_world: &ImplGenerics,
|
||||||
|
field_idents: &Vec<proc_macro2::TokenStream>,
|
||||||
|
user_ty_generics: &TypeGenerics,
|
||||||
|
user_ty_generics_with_world: &TypeGenerics,
|
||||||
|
named_field_idents: &Vec<Ident>,
|
||||||
|
marker_name: &Ident,
|
||||||
|
state_struct_name: &Ident,
|
||||||
|
user_where_clauses: Option<&WhereClause>,
|
||||||
|
user_where_clauses_with_world: Option<&WhereClause>,
|
||||||
|
) -> proc_macro2::TokenStream {
|
||||||
|
quote! {
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[doc = "Automatically generated internal [`WorldQuery`] fetch type for [`"]
|
||||||
|
#[doc = stringify!(#struct_name)]
|
||||||
|
#[doc = "`], used to define the world data accessed by this query."]
|
||||||
|
#[automatically_derived]
|
||||||
|
#visibility struct #fetch_struct_name #user_impl_generics_with_world #user_where_clauses_with_world {
|
||||||
|
#(#named_field_idents: <#field_types as #path::query::WorldQuery>::Fetch<'__w>,)*
|
||||||
|
#marker_name: &'__w (),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl #user_impl_generics_with_world Clone for #fetch_struct_name #user_ty_generics_with_world
|
||||||
|
#user_where_clauses_with_world {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self {
|
||||||
|
#(#named_field_idents: self.#named_field_idents.clone(),)*
|
||||||
|
#marker_name: &(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SAFETY: `update_component_access` and `update_archetype_component_access` are called on every field
|
||||||
|
unsafe impl #user_impl_generics #path::query::WorldQuery
|
||||||
|
for #struct_name #user_ty_generics #user_where_clauses {
|
||||||
|
|
||||||
|
type Item<'__w> = #item_struct_name #user_ty_generics_with_world;
|
||||||
|
type Fetch<'__w> = #fetch_struct_name #user_ty_generics_with_world;
|
||||||
|
type State = #state_struct_name #user_ty_generics;
|
||||||
|
|
||||||
|
fn shrink<'__wlong: '__wshort, '__wshort>(
|
||||||
|
item: <#struct_name #user_ty_generics as #path::query::WorldQuery>::Item<'__wlong>
|
||||||
|
) -> <#struct_name #user_ty_generics as #path::query::WorldQuery>::Item<'__wshort> {
|
||||||
|
#item_struct_name {
|
||||||
|
#(
|
||||||
|
#field_idents: <#field_types>::shrink(item.#field_idents),
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn init_fetch<'__w>(
|
||||||
|
_world: #path::world::unsafe_world_cell::UnsafeWorldCell<'__w>,
|
||||||
|
state: &Self::State,
|
||||||
|
_last_run: #path::component::Tick,
|
||||||
|
_this_run: #path::component::Tick,
|
||||||
|
) -> <Self as #path::query::WorldQuery>::Fetch<'__w> {
|
||||||
|
#fetch_struct_name {
|
||||||
|
#(#named_field_idents:
|
||||||
|
<#field_types>::init_fetch(
|
||||||
|
_world,
|
||||||
|
&state.#named_field_idents,
|
||||||
|
_last_run,
|
||||||
|
_this_run,
|
||||||
|
),
|
||||||
|
)*
|
||||||
|
#marker_name: &(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const IS_DENSE: bool = true #(&& <#field_types>::IS_DENSE)*;
|
||||||
|
|
||||||
|
/// SAFETY: we call `set_archetype` for each member that implements `Fetch`
|
||||||
|
#[inline]
|
||||||
|
unsafe fn set_archetype<'__w>(
|
||||||
|
_fetch: &mut <Self as #path::query::WorldQuery>::Fetch<'__w>,
|
||||||
|
_state: &Self::State,
|
||||||
|
_archetype: &'__w #path::archetype::Archetype,
|
||||||
|
_table: &'__w #path::storage::Table
|
||||||
|
) {
|
||||||
|
#(<#field_types>::set_archetype(&mut _fetch.#named_field_idents, &_state.#named_field_idents, _archetype, _table);)*
|
||||||
|
}
|
||||||
|
|
||||||
|
/// SAFETY: we call `set_table` for each member that implements `Fetch`
|
||||||
|
#[inline]
|
||||||
|
unsafe fn set_table<'__w>(
|
||||||
|
_fetch: &mut <Self as #path::query::WorldQuery>::Fetch<'__w>,
|
||||||
|
_state: &Self::State,
|
||||||
|
_table: &'__w #path::storage::Table
|
||||||
|
) {
|
||||||
|
#(<#field_types>::set_table(&mut _fetch.#named_field_idents, &_state.#named_field_idents, _table);)*
|
||||||
|
}
|
||||||
|
|
||||||
|
/// SAFETY: we call `fetch` for each member that implements `Fetch`.
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn fetch<'__w>(
|
||||||
|
_fetch: &mut <Self as #path::query::WorldQuery>::Fetch<'__w>,
|
||||||
|
_entity: #path::entity::Entity,
|
||||||
|
_table_row: #path::storage::TableRow,
|
||||||
|
) -> <Self as #path::query::WorldQuery>::Item<'__w> {
|
||||||
|
Self::Item {
|
||||||
|
#(#field_idents: <#field_types>::fetch(&mut _fetch.#named_field_idents, _entity, _table_row),)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_component_access(state: &Self::State, _access: &mut #path::query::FilteredAccess<#path::component::ComponentId>) {
|
||||||
|
#( <#field_types>::update_component_access(&state.#named_field_idents, _access); )*
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_archetype_component_access(
|
||||||
|
state: &Self::State,
|
||||||
|
_archetype: &#path::archetype::Archetype,
|
||||||
|
_access: &mut #path::query::Access<#path::archetype::ArchetypeComponentId>
|
||||||
|
) {
|
||||||
|
#(
|
||||||
|
<#field_types>::update_archetype_component_access(&state.#named_field_idents, _archetype, _access);
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init_state(world: &mut #path::world::World) -> #state_struct_name #user_ty_generics {
|
||||||
|
#state_struct_name {
|
||||||
|
#(#named_field_idents: <#field_types>::init_state(world),)*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn matches_component_set(state: &Self::State, _set_contains_id: &impl Fn(#path::component::ComponentId) -> bool) -> bool {
|
||||||
|
true #(&& <#field_types>::matches_component_set(&state.#named_field_idents, _set_contains_id))*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
410
crates/bevy_ecs/macros/src/world_query_data.rs
Normal file
410
crates/bevy_ecs/macros/src/world_query_data.rs
Normal file
|
@ -0,0 +1,410 @@
|
||||||
|
use bevy_macro_utils::ensure_no_collision;
|
||||||
|
use proc_macro::TokenStream;
|
||||||
|
use proc_macro2::{Ident, Span};
|
||||||
|
use quote::{format_ident, quote, ToTokens};
|
||||||
|
use syn::{
|
||||||
|
parse::{Parse, ParseStream},
|
||||||
|
parse_macro_input, parse_quote,
|
||||||
|
punctuated::Punctuated,
|
||||||
|
token::Comma,
|
||||||
|
Attribute, Data, DataStruct, DeriveInput, Field, Index, Meta,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
bevy_ecs_path,
|
||||||
|
world_query::{item_struct, world_query_impl},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct WorldQueryDataAttributes {
|
||||||
|
pub is_mutable: bool,
|
||||||
|
|
||||||
|
pub derive_args: Punctuated<syn::Meta, syn::token::Comma>,
|
||||||
|
}
|
||||||
|
|
||||||
|
static MUTABLE_ATTRIBUTE_NAME: &str = "mutable";
|
||||||
|
static DERIVE_ATTRIBUTE_NAME: &str = "derive";
|
||||||
|
|
||||||
|
mod field_attr_keywords {
|
||||||
|
syn::custom_keyword!(ignore);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub static WORLD_QUERY_DATA_ATTRIBUTE_NAME: &str = "world_query_data";
|
||||||
|
|
||||||
|
pub fn derive_world_query_data_impl(input: TokenStream) -> TokenStream {
|
||||||
|
let tokens = input.clone();
|
||||||
|
|
||||||
|
let ast = parse_macro_input!(input as DeriveInput);
|
||||||
|
let visibility = ast.vis;
|
||||||
|
|
||||||
|
let mut attributes = WorldQueryDataAttributes::default();
|
||||||
|
for attr in &ast.attrs {
|
||||||
|
if !attr
|
||||||
|
.path()
|
||||||
|
.get_ident()
|
||||||
|
.map_or(false, |ident| ident == WORLD_QUERY_DATA_ATTRIBUTE_NAME)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
attr.parse_args_with(|input: ParseStream| {
|
||||||
|
let meta = input.parse_terminated(syn::Meta::parse, Comma)?;
|
||||||
|
for meta in meta {
|
||||||
|
let ident = meta.path().get_ident().unwrap_or_else(|| {
|
||||||
|
panic!(
|
||||||
|
"Unrecognized attribute: `{}`",
|
||||||
|
meta.path().to_token_stream()
|
||||||
|
)
|
||||||
|
});
|
||||||
|
if ident == MUTABLE_ATTRIBUTE_NAME {
|
||||||
|
if let syn::Meta::Path(_) = meta {
|
||||||
|
attributes.is_mutable = true;
|
||||||
|
} else {
|
||||||
|
panic!(
|
||||||
|
"The `{MUTABLE_ATTRIBUTE_NAME}` attribute is expected to have no value or arguments",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ident == DERIVE_ATTRIBUTE_NAME {
|
||||||
|
if let syn::Meta::List(meta_list) = meta {
|
||||||
|
meta_list.parse_nested_meta(|meta| {
|
||||||
|
attributes.derive_args.push(Meta::Path(meta.path));
|
||||||
|
Ok(())
|
||||||
|
})?;
|
||||||
|
} else {
|
||||||
|
panic!(
|
||||||
|
"Expected a structured list within the `{DERIVE_ATTRIBUTE_NAME}` attribute",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panic!(
|
||||||
|
"Unrecognized attribute: `{}`",
|
||||||
|
meta.path().to_token_stream()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
.unwrap_or_else(|_| panic!("Invalid `{WORLD_QUERY_DATA_ATTRIBUTE_NAME}` attribute format"));
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = {
|
||||||
|
let mut generics = ast.generics;
|
||||||
|
generics.params.insert(0, parse_quote!('__w));
|
||||||
|
generics
|
||||||
|
};
|
||||||
|
let (user_impl_generics_with_world, user_ty_generics_with_world, user_where_clauses_with_world) =
|
||||||
|
user_generics_with_world.split_for_impl();
|
||||||
|
|
||||||
|
let struct_name = ast.ident;
|
||||||
|
let read_only_struct_name = if attributes.is_mutable {
|
||||||
|
Ident::new(&format!("{struct_name}ReadOnly"), Span::call_site())
|
||||||
|
} else {
|
||||||
|
#[allow(clippy::redundant_clone)]
|
||||||
|
struct_name.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
let item_struct_name = Ident::new(&format!("{struct_name}Item"), Span::call_site());
|
||||||
|
let read_only_item_struct_name = if attributes.is_mutable {
|
||||||
|
Ident::new(&format!("{struct_name}ReadOnlyItem"), Span::call_site())
|
||||||
|
} else {
|
||||||
|
#[allow(clippy::redundant_clone)]
|
||||||
|
item_struct_name.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
let fetch_struct_name = Ident::new(&format!("{struct_name}Fetch"), Span::call_site());
|
||||||
|
let fetch_struct_name = ensure_no_collision(fetch_struct_name, tokens.clone());
|
||||||
|
let read_only_fetch_struct_name = if attributes.is_mutable {
|
||||||
|
let new_ident = Ident::new(&format!("{struct_name}ReadOnlyFetch"), Span::call_site());
|
||||||
|
ensure_no_collision(new_ident, tokens.clone())
|
||||||
|
} else {
|
||||||
|
#[allow(clippy::redundant_clone)]
|
||||||
|
fetch_struct_name.clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
let marker_name =
|
||||||
|
ensure_no_collision(format_ident!("_world_query_derive_marker"), tokens.clone());
|
||||||
|
|
||||||
|
// Generate a name for the state struct that doesn't conflict
|
||||||
|
// with the struct definition.
|
||||||
|
let state_struct_name = Ident::new(&format!("{struct_name}State"), Span::call_site());
|
||||||
|
let state_struct_name = ensure_no_collision(state_struct_name, tokens);
|
||||||
|
|
||||||
|
let Data::Struct(DataStruct { fields, .. }) = &ast.data else {
|
||||||
|
return syn::Error::new(
|
||||||
|
Span::call_site(),
|
||||||
|
"#[derive(WorldQueryData)]` only supports structs",
|
||||||
|
)
|
||||||
|
.into_compile_error()
|
||||||
|
.into();
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut field_attrs = Vec::new();
|
||||||
|
let mut field_visibilities = Vec::new();
|
||||||
|
let mut field_idents = Vec::new();
|
||||||
|
let mut named_field_idents = Vec::new();
|
||||||
|
let mut field_types = Vec::new();
|
||||||
|
let mut read_only_field_types = Vec::new();
|
||||||
|
for (i, field) in fields.iter().enumerate() {
|
||||||
|
let attrs = match read_world_query_field_info(field) {
|
||||||
|
Ok(WorldQueryDataFieldInfo { attrs }) => attrs,
|
||||||
|
Err(e) => return e.into_compile_error().into(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let named_field_ident = field
|
||||||
|
.ident
|
||||||
|
.as_ref()
|
||||||
|
.cloned()
|
||||||
|
.unwrap_or_else(|| format_ident!("f{i}"));
|
||||||
|
let i = Index::from(i);
|
||||||
|
let field_ident = field
|
||||||
|
.ident
|
||||||
|
.as_ref()
|
||||||
|
.map_or(quote! { #i }, |i| quote! { #i });
|
||||||
|
field_idents.push(field_ident);
|
||||||
|
named_field_idents.push(named_field_ident);
|
||||||
|
field_attrs.push(attrs);
|
||||||
|
field_visibilities.push(field.vis.clone());
|
||||||
|
let field_ty = field.ty.clone();
|
||||||
|
field_types.push(quote!(#field_ty));
|
||||||
|
read_only_field_types.push(quote!(<#field_ty as #path::query::WorldQueryData>::ReadOnly));
|
||||||
|
}
|
||||||
|
|
||||||
|
let derive_args = &attributes.derive_args;
|
||||||
|
// `#[derive()]` is valid syntax
|
||||||
|
let derive_macro_call = quote! { #[derive(#derive_args)] };
|
||||||
|
|
||||||
|
let mutable_item_struct = item_struct(
|
||||||
|
&path,
|
||||||
|
fields,
|
||||||
|
&derive_macro_call,
|
||||||
|
&struct_name,
|
||||||
|
&visibility,
|
||||||
|
&item_struct_name,
|
||||||
|
&field_types,
|
||||||
|
&user_impl_generics_with_world,
|
||||||
|
&field_attrs,
|
||||||
|
&field_visibilities,
|
||||||
|
&field_idents,
|
||||||
|
&user_ty_generics,
|
||||||
|
&user_ty_generics_with_world,
|
||||||
|
user_where_clauses_with_world,
|
||||||
|
);
|
||||||
|
let mutable_world_query_impl = world_query_impl(
|
||||||
|
&path,
|
||||||
|
&struct_name,
|
||||||
|
&visibility,
|
||||||
|
&item_struct_name,
|
||||||
|
&fetch_struct_name,
|
||||||
|
&field_types,
|
||||||
|
&user_impl_generics,
|
||||||
|
&user_impl_generics_with_world,
|
||||||
|
&field_idents,
|
||||||
|
&user_ty_generics,
|
||||||
|
&user_ty_generics_with_world,
|
||||||
|
&named_field_idents,
|
||||||
|
&marker_name,
|
||||||
|
&state_struct_name,
|
||||||
|
user_where_clauses,
|
||||||
|
user_where_clauses_with_world,
|
||||||
|
);
|
||||||
|
|
||||||
|
let (read_only_struct, read_only_impl) = if attributes.is_mutable {
|
||||||
|
// If the query is mutable, we need to generate a separate readonly version of some things
|
||||||
|
let readonly_item_struct = item_struct(
|
||||||
|
&path,
|
||||||
|
fields,
|
||||||
|
&derive_macro_call,
|
||||||
|
&read_only_struct_name,
|
||||||
|
&visibility,
|
||||||
|
&read_only_item_struct_name,
|
||||||
|
&read_only_field_types,
|
||||||
|
&user_impl_generics_with_world,
|
||||||
|
&field_attrs,
|
||||||
|
&field_visibilities,
|
||||||
|
&field_idents,
|
||||||
|
&user_ty_generics,
|
||||||
|
&user_ty_generics_with_world,
|
||||||
|
user_where_clauses_with_world,
|
||||||
|
);
|
||||||
|
let readonly_world_query_impl = world_query_impl(
|
||||||
|
&path,
|
||||||
|
&read_only_struct_name,
|
||||||
|
&visibility,
|
||||||
|
&read_only_item_struct_name,
|
||||||
|
&read_only_fetch_struct_name,
|
||||||
|
&read_only_field_types,
|
||||||
|
&user_impl_generics,
|
||||||
|
&user_impl_generics_with_world,
|
||||||
|
&field_idents,
|
||||||
|
&user_ty_generics,
|
||||||
|
&user_ty_generics_with_world,
|
||||||
|
&named_field_idents,
|
||||||
|
&marker_name,
|
||||||
|
&state_struct_name,
|
||||||
|
user_where_clauses,
|
||||||
|
user_where_clauses_with_world,
|
||||||
|
);
|
||||||
|
let read_only_structs = quote! {
|
||||||
|
#[doc = "Automatically generated [`WorldQuery`] type for a read-only variant of [`"]
|
||||||
|
#[doc = stringify!(#struct_name)]
|
||||||
|
#[doc = "`]."]
|
||||||
|
#[automatically_derived]
|
||||||
|
#visibility struct #read_only_struct_name #user_impl_generics #user_where_clauses {
|
||||||
|
#(
|
||||||
|
#[doc = "Automatically generated read-only field for accessing `"]
|
||||||
|
#[doc = stringify!(#field_types)]
|
||||||
|
#[doc = "`."]
|
||||||
|
#field_visibilities #named_field_idents: #read_only_field_types,
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
|
||||||
|
#readonly_item_struct
|
||||||
|
};
|
||||||
|
(read_only_structs, readonly_world_query_impl)
|
||||||
|
} else {
|
||||||
|
(quote! {}, quote! {})
|
||||||
|
};
|
||||||
|
|
||||||
|
let data_impl = {
|
||||||
|
let read_only_data_impl = if attributes.is_mutable {
|
||||||
|
quote! {
|
||||||
|
/// SAFETY: we assert fields are readonly below
|
||||||
|
unsafe impl #user_impl_generics #path::query::WorldQueryData
|
||||||
|
for #read_only_struct_name #user_ty_generics #user_where_clauses {
|
||||||
|
type ReadOnly = #read_only_struct_name #user_ty_generics;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
quote! {}
|
||||||
|
};
|
||||||
|
|
||||||
|
quote! {
|
||||||
|
/// SAFETY: we assert fields are readonly below
|
||||||
|
unsafe impl #user_impl_generics #path::query::WorldQueryData
|
||||||
|
for #struct_name #user_ty_generics #user_where_clauses {
|
||||||
|
type ReadOnly = #read_only_struct_name #user_ty_generics;
|
||||||
|
}
|
||||||
|
|
||||||
|
#read_only_data_impl
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let read_only_data_impl = quote! {
|
||||||
|
/// SAFETY: we assert fields are readonly below
|
||||||
|
unsafe impl #user_impl_generics #path::query::ReadOnlyWorldQueryData
|
||||||
|
for #read_only_struct_name #user_ty_generics #user_where_clauses {}
|
||||||
|
};
|
||||||
|
|
||||||
|
let read_only_asserts = if attributes.is_mutable {
|
||||||
|
quote! {
|
||||||
|
// Double-check that the data fetched by `<_ as WorldQuery>::ReadOnly` is read-only.
|
||||||
|
// This is technically unnecessary as `<_ as WorldQuery>::ReadOnly: ReadOnlyWorldQueryData`
|
||||||
|
// but to protect against future mistakes we assert the assoc type implements `ReadOnlyWorldQueryData` anyway
|
||||||
|
#( assert_readonly::<#read_only_field_types>(); )*
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
quote! {
|
||||||
|
// Statically checks that the safety guarantee of `ReadOnlyWorldQueryData` for `$fetch_struct_name` actually holds true.
|
||||||
|
// We need this to make sure that we don't compile `ReadOnlyWorldQueryData` if our struct contains nested `WorldQueryData`
|
||||||
|
// members that don't implement it. I.e.:
|
||||||
|
// ```
|
||||||
|
// #[derive(WorldQueryData)]
|
||||||
|
// pub struct Foo { a: &'static mut MyComponent }
|
||||||
|
// ```
|
||||||
|
#( assert_readonly::<#field_types>(); )*
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let data_asserts = quote! {
|
||||||
|
#( assert_data::<#field_types>(); )*
|
||||||
|
};
|
||||||
|
|
||||||
|
TokenStream::from(quote! {
|
||||||
|
#mutable_item_struct
|
||||||
|
|
||||||
|
#read_only_struct
|
||||||
|
|
||||||
|
const _: () = {
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[doc = "Automatically generated internal [`WorldQuery`] state type for [`"]
|
||||||
|
#[doc = stringify!(#struct_name)]
|
||||||
|
#[doc = "`], used for caching."]
|
||||||
|
#[automatically_derived]
|
||||||
|
#visibility struct #state_struct_name #user_impl_generics #user_where_clauses {
|
||||||
|
#(#named_field_idents: <#field_types as #path::query::WorldQuery>::State,)*
|
||||||
|
}
|
||||||
|
|
||||||
|
#mutable_world_query_impl
|
||||||
|
|
||||||
|
#read_only_impl
|
||||||
|
|
||||||
|
#data_impl
|
||||||
|
|
||||||
|
#read_only_data_impl
|
||||||
|
};
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
const _: () = {
|
||||||
|
fn assert_readonly<T>()
|
||||||
|
where
|
||||||
|
T: #path::query::ReadOnlyWorldQueryData,
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
fn assert_data<T>()
|
||||||
|
where
|
||||||
|
T: #path::query::WorldQueryData,
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// We generate a readonly assertion for every struct member.
|
||||||
|
fn assert_all #user_impl_generics_with_world () #user_where_clauses_with_world {
|
||||||
|
#read_only_asserts
|
||||||
|
#data_asserts
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// The original struct will most likely be left unused. As we don't want our users having
|
||||||
|
// to specify `#[allow(dead_code)]` for their custom queries, we are using this cursed
|
||||||
|
// workaround.
|
||||||
|
#[allow(dead_code)]
|
||||||
|
const _: () = {
|
||||||
|
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;)*
|
||||||
|
#(q2.#field_idents;)*
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
struct WorldQueryDataFieldInfo {
|
||||||
|
/// All field attributes except for `world_query_data` ones.
|
||||||
|
attrs: Vec<Attribute>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_world_query_field_info(field: &Field) -> syn::Result<WorldQueryDataFieldInfo> {
|
||||||
|
let mut attrs = Vec::new();
|
||||||
|
for attr in &field.attrs {
|
||||||
|
if attr
|
||||||
|
.path()
|
||||||
|
.get_ident()
|
||||||
|
.map_or(false, |ident| ident == WORLD_QUERY_DATA_ATTRIBUTE_NAME)
|
||||||
|
{
|
||||||
|
return Err(syn::Error::new_spanned(
|
||||||
|
attr,
|
||||||
|
"#[derive(WorldQueryData)] does not support field attributes.",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
attrs.push(attr.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(WorldQueryDataFieldInfo { attrs })
|
||||||
|
}
|
190
crates/bevy_ecs/macros/src/world_query_filter.rs
Normal file
190
crates/bevy_ecs/macros/src/world_query_filter.rs
Normal file
|
@ -0,0 +1,190 @@
|
||||||
|
use bevy_macro_utils::ensure_no_collision;
|
||||||
|
use proc_macro::TokenStream;
|
||||||
|
use proc_macro2::{Ident, Span};
|
||||||
|
use quote::{format_ident, quote};
|
||||||
|
use syn::{parse_macro_input, parse_quote, Data, DataStruct, DeriveInput, Index};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
bevy_ecs_path,
|
||||||
|
world_query::{item_struct, world_query_impl},
|
||||||
|
};
|
||||||
|
|
||||||
|
mod field_attr_keywords {
|
||||||
|
syn::custom_keyword!(ignore);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn derive_world_query_filter_impl(input: TokenStream) -> TokenStream {
|
||||||
|
let tokens = input.clone();
|
||||||
|
|
||||||
|
let ast = parse_macro_input!(input as DeriveInput);
|
||||||
|
let visibility = ast.vis;
|
||||||
|
|
||||||
|
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 = {
|
||||||
|
let mut generics = ast.generics;
|
||||||
|
generics.params.insert(0, parse_quote!('__w));
|
||||||
|
generics
|
||||||
|
};
|
||||||
|
let (user_impl_generics_with_world, user_ty_generics_with_world, user_where_clauses_with_world) =
|
||||||
|
user_generics_with_world.split_for_impl();
|
||||||
|
|
||||||
|
let struct_name = ast.ident;
|
||||||
|
|
||||||
|
let item_struct_name = Ident::new(&format!("{struct_name}Item"), Span::call_site());
|
||||||
|
|
||||||
|
let fetch_struct_name = Ident::new(&format!("{struct_name}Fetch"), Span::call_site());
|
||||||
|
let fetch_struct_name = ensure_no_collision(fetch_struct_name, tokens.clone());
|
||||||
|
|
||||||
|
let marker_name =
|
||||||
|
ensure_no_collision(format_ident!("_world_query_derive_marker"), tokens.clone());
|
||||||
|
|
||||||
|
// Generate a name for the state struct that doesn't conflict
|
||||||
|
// with the struct definition.
|
||||||
|
let state_struct_name = Ident::new(&format!("{struct_name}State"), Span::call_site());
|
||||||
|
let state_struct_name = ensure_no_collision(state_struct_name, tokens);
|
||||||
|
|
||||||
|
let Data::Struct(DataStruct { fields, .. }) = &ast.data else {
|
||||||
|
return syn::Error::new(
|
||||||
|
Span::call_site(),
|
||||||
|
"#[derive(WorldQuery)]` only supports structs",
|
||||||
|
)
|
||||||
|
.into_compile_error()
|
||||||
|
.into();
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut field_attrs = Vec::new();
|
||||||
|
let mut field_visibilities = Vec::new();
|
||||||
|
let mut field_idents = Vec::new();
|
||||||
|
let mut named_field_idents = Vec::new();
|
||||||
|
let mut field_types = Vec::new();
|
||||||
|
for (i, field) in fields.iter().enumerate() {
|
||||||
|
let attrs = field.attrs.clone();
|
||||||
|
|
||||||
|
let named_field_ident = field
|
||||||
|
.ident
|
||||||
|
.as_ref()
|
||||||
|
.cloned()
|
||||||
|
.unwrap_or_else(|| format_ident!("f{i}"));
|
||||||
|
let i = Index::from(i);
|
||||||
|
let field_ident = field
|
||||||
|
.ident
|
||||||
|
.as_ref()
|
||||||
|
.map_or(quote! { #i }, |i| quote! { #i });
|
||||||
|
field_idents.push(field_ident);
|
||||||
|
named_field_idents.push(named_field_ident);
|
||||||
|
field_attrs.push(attrs);
|
||||||
|
field_visibilities.push(field.vis.clone());
|
||||||
|
let field_ty = field.ty.clone();
|
||||||
|
field_types.push(quote!(#field_ty));
|
||||||
|
}
|
||||||
|
|
||||||
|
let derive_macro_call = quote!();
|
||||||
|
|
||||||
|
let item_struct = item_struct(
|
||||||
|
&path,
|
||||||
|
fields,
|
||||||
|
&derive_macro_call,
|
||||||
|
&struct_name,
|
||||||
|
&visibility,
|
||||||
|
&item_struct_name,
|
||||||
|
&field_types,
|
||||||
|
&user_impl_generics_with_world,
|
||||||
|
&field_attrs,
|
||||||
|
&field_visibilities,
|
||||||
|
&field_idents,
|
||||||
|
&user_ty_generics,
|
||||||
|
&user_ty_generics_with_world,
|
||||||
|
user_where_clauses_with_world,
|
||||||
|
);
|
||||||
|
|
||||||
|
let world_query_impl = world_query_impl(
|
||||||
|
&path,
|
||||||
|
&struct_name,
|
||||||
|
&visibility,
|
||||||
|
&item_struct_name,
|
||||||
|
&fetch_struct_name,
|
||||||
|
&field_types,
|
||||||
|
&user_impl_generics,
|
||||||
|
&user_impl_generics_with_world,
|
||||||
|
&field_idents,
|
||||||
|
&user_ty_generics,
|
||||||
|
&user_ty_generics_with_world,
|
||||||
|
&named_field_idents,
|
||||||
|
&marker_name,
|
||||||
|
&state_struct_name,
|
||||||
|
user_where_clauses,
|
||||||
|
user_where_clauses_with_world,
|
||||||
|
);
|
||||||
|
|
||||||
|
let filter_impl = quote! {
|
||||||
|
impl #user_impl_generics #path::query::WorldQueryFilter
|
||||||
|
for #struct_name #user_ty_generics #user_where_clauses {
|
||||||
|
const IS_ARCHETYPAL: bool = true #(&& <#field_types>::IS_ARCHETYPAL)*;
|
||||||
|
|
||||||
|
#[allow(unused_variables)]
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn filter_fetch<'__w>(
|
||||||
|
_fetch: &mut <Self as #path::query::WorldQuery>::Fetch<'__w>,
|
||||||
|
_entity: #path::entity::Entity,
|
||||||
|
_table_row: #path::storage::TableRow,
|
||||||
|
) -> bool {
|
||||||
|
true #(&& <#field_types>::filter_fetch(&mut _fetch.#named_field_idents, _entity, _table_row))*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let filter_asserts = quote! {
|
||||||
|
#( assert_filter::<#field_types>(); )*
|
||||||
|
};
|
||||||
|
|
||||||
|
TokenStream::from(quote! {
|
||||||
|
#item_struct
|
||||||
|
|
||||||
|
const _: () = {
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[doc = "Automatically generated internal [`WorldQuery`] state type for [`"]
|
||||||
|
#[doc = stringify!(#struct_name)]
|
||||||
|
#[doc = "`], used for caching."]
|
||||||
|
#[automatically_derived]
|
||||||
|
#visibility struct #state_struct_name #user_impl_generics #user_where_clauses {
|
||||||
|
#(#named_field_idents: <#field_types as #path::query::WorldQuery>::State,)*
|
||||||
|
}
|
||||||
|
|
||||||
|
#world_query_impl
|
||||||
|
|
||||||
|
#filter_impl
|
||||||
|
};
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
const _: () = {
|
||||||
|
|
||||||
|
fn assert_filter<T>()
|
||||||
|
where
|
||||||
|
T: #path::query::WorldQueryFilter,
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// We generate a filter assertion for every struct member.
|
||||||
|
fn assert_all #user_impl_generics_with_world () #user_where_clauses_with_world {
|
||||||
|
#filter_asserts
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// The original struct will most likely be left unused. As we don't want our users having
|
||||||
|
// to specify `#[allow(dead_code)]` for their custom queries, we are using this cursed
|
||||||
|
// workaround.
|
||||||
|
#[allow(dead_code)]
|
||||||
|
const _: () = {
|
||||||
|
fn dead_code_workaround #user_impl_generics (
|
||||||
|
q: #struct_name #user_ty_generics,
|
||||||
|
q2: #struct_name #user_ty_generics
|
||||||
|
) #user_where_clauses {
|
||||||
|
#(q.#field_idents;)*
|
||||||
|
#(q2.#field_idents;)*
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})
|
||||||
|
}
|
|
@ -64,7 +64,7 @@ mod tests {
|
||||||
change_detection::Ref,
|
change_detection::Ref,
|
||||||
component::{Component, ComponentId},
|
component::{Component, ComponentId},
|
||||||
entity::Entity,
|
entity::Entity,
|
||||||
query::{Added, Changed, FilteredAccess, ReadOnlyWorldQuery, With, Without},
|
query::{Added, Changed, FilteredAccess, With, Without, WorldQueryFilter},
|
||||||
system::Resource,
|
system::Resource,
|
||||||
world::{EntityRef, Mut, World},
|
world::{EntityRef, Mut, World},
|
||||||
};
|
};
|
||||||
|
@ -903,7 +903,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_filtered<F: ReadOnlyWorldQuery>(world: &mut World) -> Vec<Entity> {
|
fn get_filtered<F: WorldQueryFilter>(world: &mut World) -> Vec<Entity> {
|
||||||
world
|
world
|
||||||
.query_filtered::<Entity, F>()
|
.query_filtered::<Entity, F>()
|
||||||
.iter(world)
|
.iter(world)
|
||||||
|
@ -986,7 +986,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_filtered<F: ReadOnlyWorldQuery>(world: &mut World) -> Vec<Entity> {
|
fn get_filtered<F: WorldQueryFilter>(world: &mut World) -> Vec<Entity> {
|
||||||
world
|
world
|
||||||
.query_filtered::<Entity, F>()
|
.query_filtered::<Entity, F>()
|
||||||
.iter(world)
|
.iter(world)
|
||||||
|
|
|
@ -3,11 +3,10 @@ use crate::{
|
||||||
change_detection::{Ticks, TicksMut},
|
change_detection::{Ticks, TicksMut},
|
||||||
component::{Component, ComponentId, ComponentStorage, StorageType, Tick},
|
component::{Component, ComponentId, ComponentStorage, StorageType, Tick},
|
||||||
entity::Entity,
|
entity::Entity,
|
||||||
query::{Access, DebugCheckedUnwrap, FilteredAccess},
|
query::{Access, DebugCheckedUnwrap, FilteredAccess, WorldQuery},
|
||||||
storage::{ComponentSparseSet, Table, TableRow},
|
storage::{ComponentSparseSet, Table, TableRow},
|
||||||
world::{unsafe_world_cell::UnsafeWorldCell, EntityMut, EntityRef, Mut, Ref, World},
|
world::{unsafe_world_cell::UnsafeWorldCell, EntityMut, EntityRef, Mut, Ref, World},
|
||||||
};
|
};
|
||||||
pub use bevy_ecs_macros::WorldQuery;
|
|
||||||
use bevy_ptr::{ThinSlicePtr, UnsafeCellDeref};
|
use bevy_ptr::{ThinSlicePtr, UnsafeCellDeref};
|
||||||
use bevy_utils::all_tuples;
|
use bevy_utils::all_tuples;
|
||||||
use std::{cell::UnsafeCell, marker::PhantomData};
|
use std::{cell::UnsafeCell, marker::PhantomData};
|
||||||
|
@ -18,18 +17,11 @@ use std::{cell::UnsafeCell, marker::PhantomData};
|
||||||
///
|
///
|
||||||
/// - **Component references.**
|
/// - **Component references.**
|
||||||
/// Fetches a component by reference (immutably or mutably).
|
/// Fetches a component by reference (immutably or mutably).
|
||||||
/// - **`WorldQuery` tuples.**
|
/// - **`WorldQueryData` tuples.**
|
||||||
/// If every element of a tuple implements `WorldQuery`, then the tuple itself also implements the same trait.
|
/// If every element of a tuple implements `WorldQueryData`, then the tuple itself also implements the same trait.
|
||||||
/// This enables a single `Query` to access multiple components and filter over multiple conditions.
|
/// This enables a single `Query` to access multiple components.
|
||||||
/// Due to the current lack of variadic generics in Rust, the trait has been implemented for tuples from 0 to 15 elements,
|
/// Due to the current lack of variadic generics in Rust, the trait has been implemented for tuples from 0 to 15 elements,
|
||||||
/// but nesting of tuples allows infinite `WorldQuery`s.
|
/// but nesting of tuples allows infinite `WorldQuery`s.
|
||||||
/// - **Component filters.**
|
|
||||||
/// [`With`] and [`Without`] filters can be applied to check if the queried entity contains or not a particular component.
|
|
||||||
/// - **Change detection filters.**
|
|
||||||
/// [`Added`] and [`Changed`] filters can be applied to detect component changes to an entity.
|
|
||||||
/// - **Filter disjunction operator.**
|
|
||||||
/// By default, tuples compose query filters in such a way that all conditions must be satisfied to generate a query item for a given entity.
|
|
||||||
/// Wrapping a tuple inside an [`Or`] operator will relax the requirement to just one condition.
|
|
||||||
/// - **[`Entity`].**
|
/// - **[`Entity`].**
|
||||||
/// Gets the identifier of the queried entity.
|
/// Gets the identifier of the queried entity.
|
||||||
/// - **[`Option`].**
|
/// - **[`Option`].**
|
||||||
|
@ -40,13 +32,15 @@ use std::{cell::UnsafeCell, marker::PhantomData};
|
||||||
/// - **[`Ref`].**
|
/// - **[`Ref`].**
|
||||||
/// Similar to change detection filters but it is used as a query fetch parameter.
|
/// Similar to change detection filters but it is used as a query fetch parameter.
|
||||||
/// It exposes methods to check for changes to the wrapped component.
|
/// It exposes methods to check for changes to the wrapped component.
|
||||||
|
/// - **[`Has`].**
|
||||||
|
/// Returns a bool indicating whether the entity has the specified component.
|
||||||
///
|
///
|
||||||
/// Implementing the trait manually can allow for a fundamentally new type of behavior.
|
/// Implementing the trait manually can allow for a fundamentally new type of behavior.
|
||||||
///
|
///
|
||||||
/// # Trait derivation
|
/// # Trait derivation
|
||||||
///
|
///
|
||||||
/// Query design can be easily structured by deriving `WorldQuery` for custom types.
|
/// Query design can be easily structured by deriving `WorldQueryData` for custom types.
|
||||||
/// Despite the added complexity, this approach has several advantages over using `WorldQuery` tuples.
|
/// Despite the added complexity, this approach has several advantages over using `WorldQueryData` tuples.
|
||||||
/// The most relevant improvements are:
|
/// The most relevant improvements are:
|
||||||
///
|
///
|
||||||
/// - Reusability across multiple systems.
|
/// - Reusability across multiple systems.
|
||||||
|
@ -55,18 +49,18 @@ use std::{cell::UnsafeCell, marker::PhantomData};
|
||||||
/// - Methods can be implemented for the query items.
|
/// - Methods can be implemented for the query items.
|
||||||
/// - There is no hardcoded limit on the number of elements.
|
/// - There is no hardcoded limit on the number of elements.
|
||||||
///
|
///
|
||||||
/// This trait can only be derived for structs, if each field also implements `WorldQuery`.
|
/// This trait can only be derived for structs, if each field also implements `WorldQueryData`.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use bevy_ecs::prelude::*;
|
/// # use bevy_ecs::prelude::*;
|
||||||
/// use bevy_ecs::query::WorldQuery;
|
/// use bevy_ecs::query::WorldQueryData;
|
||||||
/// #
|
/// #
|
||||||
/// # #[derive(Component)]
|
/// # #[derive(Component)]
|
||||||
/// # struct ComponentA;
|
/// # struct ComponentA;
|
||||||
/// # #[derive(Component)]
|
/// # #[derive(Component)]
|
||||||
/// # struct ComponentB;
|
/// # struct ComponentB;
|
||||||
///
|
///
|
||||||
/// #[derive(WorldQuery)]
|
/// #[derive(WorldQueryData)]
|
||||||
/// struct MyQuery {
|
/// struct MyQuery {
|
||||||
/// entity: Entity,
|
/// entity: Entity,
|
||||||
/// // It is required that all reference lifetimes are explicitly annotated, just like in any
|
/// // It is required that all reference lifetimes are explicitly annotated, just like in any
|
||||||
|
@ -96,33 +90,33 @@ use std::{cell::UnsafeCell, marker::PhantomData};
|
||||||
///
|
///
|
||||||
/// ## Adding mutable references
|
/// ## Adding mutable references
|
||||||
///
|
///
|
||||||
/// Simply adding mutable references to a derived `WorldQuery` will result in a compilation error:
|
/// Simply adding mutable references to a derived `WorldQueryData` will result in a compilation error:
|
||||||
///
|
///
|
||||||
/// ```compile_fail
|
/// ```compile_fail
|
||||||
/// # use bevy_ecs::prelude::*;
|
/// # use bevy_ecs::prelude::*;
|
||||||
/// # use bevy_ecs::query::WorldQuery;
|
/// # use bevy_ecs::query::WorldQueryData;
|
||||||
/// #
|
/// #
|
||||||
/// # #[derive(Component)]
|
/// # #[derive(Component)]
|
||||||
/// # struct ComponentA;
|
/// # struct ComponentA;
|
||||||
/// #
|
/// #
|
||||||
/// #[derive(WorldQuery)]
|
/// #[derive(WorldQueryData)]
|
||||||
/// struct CustomQuery {
|
/// struct CustomQuery {
|
||||||
/// component_a: &'static mut ComponentA,
|
/// component_a: &'static mut ComponentA,
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// To grant mutable access to components, the struct must be marked with the `#[world_query(mutable)]` attribute.
|
/// To grant mutable access to components, the struct must be marked with the `#[world_query_data(mutable)]` attribute.
|
||||||
/// This will also create three more structs that will be used for accessing the query immutably (see table above).
|
/// This will also create three more structs that will be used for accessing the query immutably (see table above).
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use bevy_ecs::prelude::*;
|
/// # use bevy_ecs::prelude::*;
|
||||||
/// # use bevy_ecs::query::WorldQuery;
|
/// # use bevy_ecs::query::WorldQueryData;
|
||||||
/// #
|
/// #
|
||||||
/// # #[derive(Component)]
|
/// # #[derive(Component)]
|
||||||
/// # struct ComponentA;
|
/// # struct ComponentA;
|
||||||
/// #
|
/// #
|
||||||
/// #[derive(WorldQuery)]
|
/// #[derive(WorldQueryData)]
|
||||||
/// #[world_query(mutable)]
|
/// #[world_query_data(mutable)]
|
||||||
/// struct CustomQuery {
|
/// struct CustomQuery {
|
||||||
/// component_a: &'static mut ComponentA,
|
/// component_a: &'static mut ComponentA,
|
||||||
/// }
|
/// }
|
||||||
|
@ -136,7 +130,7 @@ use std::{cell::UnsafeCell, marker::PhantomData};
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use bevy_ecs::prelude::*;
|
/// # use bevy_ecs::prelude::*;
|
||||||
/// # use bevy_ecs::query::WorldQuery;
|
/// # use bevy_ecs::query::WorldQueryData;
|
||||||
/// #
|
/// #
|
||||||
/// #[derive(Component)]
|
/// #[derive(Component)]
|
||||||
/// struct Health(f32);
|
/// struct Health(f32);
|
||||||
|
@ -144,8 +138,8 @@ use std::{cell::UnsafeCell, marker::PhantomData};
|
||||||
/// #[derive(Component)]
|
/// #[derive(Component)]
|
||||||
/// struct Buff(f32);
|
/// struct Buff(f32);
|
||||||
///
|
///
|
||||||
/// #[derive(WorldQuery)]
|
/// #[derive(WorldQueryData)]
|
||||||
/// #[world_query(mutable)]
|
/// #[world_query_data(mutable)]
|
||||||
/// struct HealthQuery {
|
/// struct HealthQuery {
|
||||||
/// health: &'static mut Health,
|
/// health: &'static mut Health,
|
||||||
/// buff: Option<&'static mut Buff>,
|
/// buff: Option<&'static mut Buff>,
|
||||||
|
@ -185,19 +179,19 @@ use std::{cell::UnsafeCell, marker::PhantomData};
|
||||||
///
|
///
|
||||||
/// ## Deriving traits for query items
|
/// ## Deriving traits for query items
|
||||||
///
|
///
|
||||||
/// The `WorldQuery` derive macro does not automatically implement the traits of the struct to the query item types.
|
/// The `WorldQueryData` derive macro does not automatically implement the traits of the struct to the query item types.
|
||||||
/// Something similar can be done by using the `#[world_query(derive(...))]` attribute.
|
/// Something similar can be done by using the `#[world_query_data(derive(...))]` attribute.
|
||||||
/// This will apply the listed derivable traits to the query item structs.
|
/// This will apply the listed derivable traits to the query item structs.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use bevy_ecs::prelude::*;
|
/// # use bevy_ecs::prelude::*;
|
||||||
/// # use bevy_ecs::query::WorldQuery;
|
/// # use bevy_ecs::query::WorldQueryData;
|
||||||
/// #
|
/// #
|
||||||
/// # #[derive(Component, Debug)]
|
/// # #[derive(Component, Debug)]
|
||||||
/// # struct ComponentA;
|
/// # struct ComponentA;
|
||||||
/// #
|
/// #
|
||||||
/// #[derive(WorldQuery)]
|
/// #[derive(WorldQueryData)]
|
||||||
/// #[world_query(mutable, derive(Debug))]
|
/// #[world_query_data(mutable, derive(Debug))]
|
||||||
/// struct CustomQuery {
|
/// struct CustomQuery {
|
||||||
/// component_a: &'static ComponentA,
|
/// component_a: &'static ComponentA,
|
||||||
/// }
|
/// }
|
||||||
|
@ -211,12 +205,12 @@ use std::{cell::UnsafeCell, marker::PhantomData};
|
||||||
///
|
///
|
||||||
/// ## Query composition
|
/// ## Query composition
|
||||||
///
|
///
|
||||||
/// It is possible to use any `WorldQuery` as a field of another one.
|
/// It is possible to use any `WorldQueryData` as a field of another one.
|
||||||
/// This means that a `WorldQuery` can also be used as a subquery, potentially in multiple places.
|
/// This means that a `WorldQueryData` can also be used as a subquery, potentially in multiple places.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use bevy_ecs::prelude::*;
|
/// # use bevy_ecs::prelude::*;
|
||||||
/// # use bevy_ecs::query::WorldQuery;
|
/// # use bevy_ecs::query::WorldQueryData;
|
||||||
/// #
|
/// #
|
||||||
/// # #[derive(Component)]
|
/// # #[derive(Component)]
|
||||||
/// # struct ComponentA;
|
/// # struct ComponentA;
|
||||||
|
@ -225,62 +219,29 @@ use std::{cell::UnsafeCell, marker::PhantomData};
|
||||||
/// # #[derive(Component)]
|
/// # #[derive(Component)]
|
||||||
/// # struct ComponentC;
|
/// # struct ComponentC;
|
||||||
/// #
|
/// #
|
||||||
/// #[derive(WorldQuery)]
|
/// #[derive(WorldQueryData)]
|
||||||
/// struct SubQuery {
|
/// struct SubQuery {
|
||||||
/// component_a: &'static ComponentA,
|
/// component_a: &'static ComponentA,
|
||||||
/// component_b: &'static ComponentB,
|
/// component_b: &'static ComponentB,
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// #[derive(WorldQuery)]
|
/// #[derive(WorldQueryData)]
|
||||||
/// struct MyQuery {
|
/// struct MyQuery {
|
||||||
/// subquery: SubQuery,
|
/// subquery: SubQuery,
|
||||||
/// component_c: &'static ComponentC,
|
/// component_c: &'static ComponentC,
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// ## Filters
|
|
||||||
///
|
|
||||||
/// Since the query filter type parameter is `WorldQuery`, it is also possible to use this macro to create filters.
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # use bevy_ecs::prelude::*;
|
|
||||||
/// # use bevy_ecs::{query::WorldQuery, component::Component};
|
|
||||||
/// #
|
|
||||||
/// # #[derive(Component)]
|
|
||||||
/// # struct ComponentA;
|
|
||||||
/// # #[derive(Component)]
|
|
||||||
/// # struct ComponentB;
|
|
||||||
/// # #[derive(Component)]
|
|
||||||
/// # struct ComponentC;
|
|
||||||
/// # #[derive(Component)]
|
|
||||||
/// # struct ComponentD;
|
|
||||||
/// # #[derive(Component)]
|
|
||||||
/// # struct ComponentE;
|
|
||||||
/// #
|
|
||||||
/// #[derive(WorldQuery)]
|
|
||||||
/// struct MyFilter<T: Component, P: Component> {
|
|
||||||
/// // Field names are not relevant, since they are never manually accessed.
|
|
||||||
/// with_a: With<ComponentA>,
|
|
||||||
/// or_filter: Or<(With<ComponentC>, Added<ComponentB>)>,
|
|
||||||
/// generic_tuple: (With<T>, Without<P>),
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// fn my_system(query: Query<Entity, MyFilter<ComponentD, ComponentE>>) {
|
|
||||||
/// // ...
|
|
||||||
/// }
|
|
||||||
/// # bevy_ecs::system::assert_is_system(my_system);
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// # Generic Queries
|
/// # Generic Queries
|
||||||
///
|
///
|
||||||
/// When writing generic code, it is often necessary to use [`PhantomData`]
|
/// When writing generic code, it is often necessary to use [`PhantomData`]
|
||||||
/// to constrain type parameters. Since `WorldQuery` is implemented for all
|
/// to constrain type parameters. Since `WorldQueryData` is implemented for all
|
||||||
/// `PhantomData<T>` types, this pattern can be used with this macro.
|
/// `PhantomData<T>` types, this pattern can be used with this macro.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use bevy_ecs::{prelude::*, query::WorldQuery};
|
/// # use bevy_ecs::{prelude::*, query::WorldQueryData};
|
||||||
/// # use std::marker::PhantomData;
|
/// # use std::marker::PhantomData;
|
||||||
/// #[derive(WorldQuery)]
|
/// #[derive(WorldQueryData)]
|
||||||
/// pub struct GenericQuery<T> {
|
/// pub struct GenericQuery<T> {
|
||||||
/// id: Entity,
|
/// id: Entity,
|
||||||
/// marker: PhantomData<T>,
|
/// marker: PhantomData<T>,
|
||||||
|
@ -294,176 +255,31 @@ use std::{cell::UnsafeCell, marker::PhantomData};
|
||||||
/// Component access of `Self::ReadOnly` must be a subset of `Self`
|
/// Component access of `Self::ReadOnly` must be a subset of `Self`
|
||||||
/// and `Self::ReadOnly` must match exactly the same archetypes/tables as `Self`
|
/// and `Self::ReadOnly` must match exactly the same archetypes/tables as `Self`
|
||||||
///
|
///
|
||||||
/// Implementor must ensure that
|
|
||||||
/// [`update_component_access`] and [`update_archetype_component_access`]
|
|
||||||
/// exactly reflects the results of the following methods:
|
|
||||||
///
|
|
||||||
/// - [`matches_component_set`]
|
|
||||||
/// - [`fetch`]
|
|
||||||
///
|
|
||||||
/// [`Added`]: crate::query::Added
|
|
||||||
/// [`fetch`]: Self::fetch
|
|
||||||
/// [`Changed`]: crate::query::Changed
|
|
||||||
/// [`matches_component_set`]: Self::matches_component_set
|
|
||||||
/// [`Or`]: crate::query::Or
|
|
||||||
/// [`Query`]: crate::system::Query
|
/// [`Query`]: crate::system::Query
|
||||||
/// [`ReadOnly`]: Self::ReadOnly
|
/// [`ReadOnly`]: Self::ReadOnly
|
||||||
/// [`State`]: Self::State
|
pub unsafe trait WorldQueryData: WorldQuery {
|
||||||
/// [`update_archetype_component_access`]: Self::update_archetype_component_access
|
/// The read-only variant of this [`WorldQueryData`], which satisfies the [`ReadOnlyWorldQueryData`] trait.
|
||||||
/// [`update_component_access`]: Self::update_component_access
|
type ReadOnly: ReadOnlyWorldQueryData<State = <Self as WorldQuery>::State>;
|
||||||
/// [`With`]: crate::query::With
|
|
||||||
/// [`Without`]: crate::query::Without
|
|
||||||
pub unsafe trait WorldQuery {
|
|
||||||
/// The item returned by this [`WorldQuery`]
|
|
||||||
type Item<'a>;
|
|
||||||
|
|
||||||
/// Per archetype/table state used by this [`WorldQuery`] to fetch [`Self::Item`](crate::query::WorldQuery::Item)
|
|
||||||
type Fetch<'a>: Clone;
|
|
||||||
|
|
||||||
/// The read-only variant of this [`WorldQuery`], which satisfies the [`ReadOnlyWorldQuery`] trait.
|
|
||||||
type ReadOnly: ReadOnlyWorldQuery<State = Self::State>;
|
|
||||||
|
|
||||||
/// State used to construct a [`Self::Fetch`](crate::query::WorldQuery::Fetch). This will be cached inside [`QueryState`](crate::query::QueryState),
|
|
||||||
/// so it is best to move as much data / computation here as possible to reduce the cost of
|
|
||||||
/// constructing [`Self::Fetch`](crate::query::WorldQuery::Fetch).
|
|
||||||
type State: Send + Sync + Sized;
|
|
||||||
|
|
||||||
/// This function manually implements subtyping for the query items.
|
|
||||||
fn shrink<'wlong: 'wshort, 'wshort>(item: Self::Item<'wlong>) -> Self::Item<'wshort>;
|
|
||||||
|
|
||||||
/// Creates a new instance of this fetch.
|
|
||||||
///
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// - `world` must have permission to access any of the components specified in `Self::update_archetype_component_access`.
|
|
||||||
/// - `state` must have been initialized (via [`WorldQuery::init_state`]) using the same `world` passed
|
|
||||||
/// in to this function.
|
|
||||||
unsafe fn init_fetch<'w>(
|
|
||||||
world: UnsafeWorldCell<'w>,
|
|
||||||
state: &Self::State,
|
|
||||||
last_run: Tick,
|
|
||||||
this_run: Tick,
|
|
||||||
) -> Self::Fetch<'w>;
|
|
||||||
|
|
||||||
/// Returns true if (and only if) every table of every archetype matched by this fetch contains
|
|
||||||
/// all of the matched components. This is used to select a more efficient "table iterator"
|
|
||||||
/// for "dense" queries. If this returns true, [`WorldQuery::set_table`] must be used before
|
|
||||||
/// [`WorldQuery::fetch`] can be called for iterators. If this returns false,
|
|
||||||
/// [`WorldQuery::set_archetype`] must be used before [`WorldQuery::fetch`] can be called for
|
|
||||||
/// iterators.
|
|
||||||
const IS_DENSE: bool;
|
|
||||||
|
|
||||||
/// Returns true if (and only if) this Fetch relies strictly on archetypes to limit which
|
|
||||||
/// components are accessed by the Query.
|
|
||||||
///
|
|
||||||
/// This enables optimizations for [`crate::query::QueryIter`] that rely on knowing exactly how
|
|
||||||
/// many elements are being iterated (such as `Iterator::collect()`).
|
|
||||||
const IS_ARCHETYPAL: bool;
|
|
||||||
|
|
||||||
/// Adjusts internal state to account for the next [`Archetype`]. This will always be called on
|
|
||||||
/// archetypes that match this [`WorldQuery`].
|
|
||||||
///
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// - `archetype` and `tables` must be from the same [`World`] that [`WorldQuery::init_state`] was called on.
|
|
||||||
/// - [`Self::update_archetype_component_access`] must have been previously called with `archetype`.
|
|
||||||
/// - `table` must correspond to `archetype`.
|
|
||||||
/// - `state` must be the [`State`](Self::State) that `fetch` was initialized with.
|
|
||||||
unsafe fn set_archetype<'w>(
|
|
||||||
fetch: &mut Self::Fetch<'w>,
|
|
||||||
state: &Self::State,
|
|
||||||
archetype: &'w Archetype,
|
|
||||||
table: &'w Table,
|
|
||||||
);
|
|
||||||
|
|
||||||
/// Adjusts internal state to account for the next [`Table`]. This will always be called on tables
|
|
||||||
/// that match this [`WorldQuery`].
|
|
||||||
///
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// - `table` must be from the same [`World`] that [`WorldQuery::init_state`] was called on.
|
|
||||||
/// - `table` must belong to an archetype that was previously registered with
|
|
||||||
/// [`Self::update_archetype_component_access`].
|
|
||||||
/// - `state` must be the [`State`](Self::State) that `fetch` was initialized with.
|
|
||||||
unsafe fn set_table<'w>(fetch: &mut Self::Fetch<'w>, state: &Self::State, table: &'w Table);
|
|
||||||
|
|
||||||
/// Fetch [`Self::Item`](`WorldQuery::Item`) for either the given `entity` in the current [`Table`],
|
|
||||||
/// or for the given `entity` in the current [`Archetype`]. This must always be called after
|
|
||||||
/// [`WorldQuery::set_table`] with a `table_row` in the range of the current [`Table`] or after
|
|
||||||
/// [`WorldQuery::set_archetype`] with a `entity` in the current archetype.
|
|
||||||
///
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// Must always be called _after_ [`WorldQuery::set_table`] or [`WorldQuery::set_archetype`]. `entity` and
|
|
||||||
/// `table_row` must be in the range of the current table and archetype.
|
|
||||||
///
|
|
||||||
/// If `update_component_access` includes any mutable accesses, then the caller must ensure
|
|
||||||
/// that `fetch` is called no more than once for each `entity`/`table_row` in each archetype.
|
|
||||||
/// If `Self` implements [`ReadOnlyWorldQuery`], then this can safely be called multiple times.
|
|
||||||
unsafe fn fetch<'w>(
|
|
||||||
fetch: &mut Self::Fetch<'w>,
|
|
||||||
entity: Entity,
|
|
||||||
table_row: TableRow,
|
|
||||||
) -> Self::Item<'w>;
|
|
||||||
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// Must always be called _after_ [`WorldQuery::set_table`] or [`WorldQuery::set_archetype`]. `entity` and
|
|
||||||
/// `table_row` must be in the range of the current table and archetype.
|
|
||||||
///
|
|
||||||
/// If this includes any mutable access, then this should never be called
|
|
||||||
/// while the return value of [`WorldQuery::fetch`] for the same entity is live.
|
|
||||||
#[allow(unused_variables)]
|
|
||||||
#[inline(always)]
|
|
||||||
unsafe fn filter_fetch(
|
|
||||||
fetch: &mut Self::Fetch<'_>,
|
|
||||||
entity: Entity,
|
|
||||||
table_row: TableRow,
|
|
||||||
) -> bool {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Adds any component accesses used by this [`WorldQuery`] to `access`.
|
|
||||||
// This does not have a default body of `{}` because 99% of cases need to add accesses
|
|
||||||
// and forgetting to do so would be unsound.
|
|
||||||
fn update_component_access(state: &Self::State, access: &mut FilteredAccess<ComponentId>);
|
|
||||||
|
|
||||||
/// For the given `archetype`, adds any component accessed used by this [`WorldQuery`] to `access`.
|
|
||||||
// This does not have a default body of `{}` because 99% of cases need to add accesses
|
|
||||||
// and forgetting to do so would be unsound.
|
|
||||||
fn update_archetype_component_access(
|
|
||||||
state: &Self::State,
|
|
||||||
archetype: &Archetype,
|
|
||||||
access: &mut Access<ArchetypeComponentId>,
|
|
||||||
);
|
|
||||||
|
|
||||||
/// Creates and initializes a [`State`](WorldQuery::State) for this [`WorldQuery`] type.
|
|
||||||
fn init_state(world: &mut World) -> Self::State;
|
|
||||||
|
|
||||||
/// Returns `true` if this query matches a set of components. Otherwise, returns `false`.
|
|
||||||
fn matches_component_set(
|
|
||||||
state: &Self::State,
|
|
||||||
set_contains_id: &impl Fn(ComponentId) -> bool,
|
|
||||||
) -> bool;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A world query that is read only.
|
/// A [`WorldQueryData`] that is read only.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// This must only be implemented for read-only [`WorldQuery`]'s.
|
/// This must only be implemented for read-only [`WorldQueryData`]'s.
|
||||||
pub unsafe trait ReadOnlyWorldQuery: WorldQuery<ReadOnly = Self> {}
|
pub unsafe trait ReadOnlyWorldQueryData: WorldQueryData<ReadOnly = Self> {}
|
||||||
|
|
||||||
/// The item type returned when a [`WorldQuery`] is iterated over
|
/// The item type returned when a [`WorldQuery`] is iterated over
|
||||||
pub type QueryItem<'w, Q> = <Q as WorldQuery>::Item<'w>;
|
pub type QueryItem<'w, Q> = <Q as WorldQuery>::Item<'w>;
|
||||||
/// The read-only variant of the item type returned when a [`WorldQuery`] is iterated over immutably
|
/// The read-only variant of the item type returned when a [`WorldQueryData`] is iterated over immutably
|
||||||
pub type ROQueryItem<'w, Q> = QueryItem<'w, <Q as WorldQuery>::ReadOnly>;
|
pub type ROQueryItem<'w, Q> = QueryItem<'w, <Q as WorldQueryData>::ReadOnly>;
|
||||||
|
|
||||||
/// SAFETY: no component or archetype access
|
/// SAFETY:
|
||||||
|
/// `update_component_access` and `update_archetype_component_access` do nothing.
|
||||||
|
/// This is sound because `fetch` does not access components.
|
||||||
unsafe impl WorldQuery for Entity {
|
unsafe impl WorldQuery for Entity {
|
||||||
type Fetch<'w> = ();
|
type Fetch<'w> = ();
|
||||||
type Item<'w> = Entity;
|
type Item<'w> = Entity;
|
||||||
type ReadOnly = Self;
|
|
||||||
type State = ();
|
type State = ();
|
||||||
|
|
||||||
fn shrink<'wlong: 'wshort, 'wshort>(item: Self::Item<'wlong>) -> Self::Item<'wshort> {
|
fn shrink<'wlong: 'wshort, 'wshort>(item: Self::Item<'wlong>) -> Self::Item<'wshort> {
|
||||||
|
@ -472,8 +288,6 @@ unsafe impl WorldQuery for Entity {
|
||||||
|
|
||||||
const IS_DENSE: bool = true;
|
const IS_DENSE: bool = true;
|
||||||
|
|
||||||
const IS_ARCHETYPAL: bool = true;
|
|
||||||
|
|
||||||
unsafe fn init_fetch<'w>(
|
unsafe fn init_fetch<'w>(
|
||||||
_world: UnsafeWorldCell<'w>,
|
_world: UnsafeWorldCell<'w>,
|
||||||
_state: &Self::State,
|
_state: &Self::State,
|
||||||
|
@ -523,14 +337,21 @@ unsafe impl WorldQuery for Entity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// SAFETY: access is read only
|
|
||||||
unsafe impl ReadOnlyWorldQuery for Entity {}
|
|
||||||
|
|
||||||
/// SAFETY: `Self` is the same as `Self::ReadOnly`
|
/// SAFETY: `Self` is the same as `Self::ReadOnly`
|
||||||
unsafe impl WorldQuery for EntityRef<'_> {
|
unsafe impl WorldQueryData for Entity {
|
||||||
|
type ReadOnly = Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// SAFETY: access is read only
|
||||||
|
unsafe impl ReadOnlyWorldQueryData for Entity {}
|
||||||
|
|
||||||
|
/// SAFETY:
|
||||||
|
/// `fetch` accesses all components in a readonly way.
|
||||||
|
/// This is sound because `update_component_access` and `update_archetype_component_access` set read access for all components and panic when appropriate.
|
||||||
|
/// Filters are unchanged.
|
||||||
|
unsafe impl<'a> WorldQuery for EntityRef<'a> {
|
||||||
type Fetch<'w> = UnsafeWorldCell<'w>;
|
type Fetch<'w> = UnsafeWorldCell<'w>;
|
||||||
type Item<'w> = EntityRef<'w>;
|
type Item<'w> = EntityRef<'w>;
|
||||||
type ReadOnly = Self;
|
|
||||||
type State = ();
|
type State = ();
|
||||||
|
|
||||||
fn shrink<'wlong: 'wshort, 'wshort>(item: Self::Item<'wlong>) -> Self::Item<'wshort> {
|
fn shrink<'wlong: 'wshort, 'wshort>(item: Self::Item<'wlong>) -> Self::Item<'wshort> {
|
||||||
|
@ -539,8 +360,6 @@ unsafe impl WorldQuery for EntityRef<'_> {
|
||||||
|
|
||||||
const IS_DENSE: bool = true;
|
const IS_DENSE: bool = true;
|
||||||
|
|
||||||
const IS_ARCHETYPAL: bool = true;
|
|
||||||
|
|
||||||
unsafe fn init_fetch<'w>(
|
unsafe fn init_fetch<'w>(
|
||||||
world: UnsafeWorldCell<'w>,
|
world: UnsafeWorldCell<'w>,
|
||||||
_state: &Self::State,
|
_state: &Self::State,
|
||||||
|
@ -603,14 +422,18 @@ unsafe impl WorldQuery for EntityRef<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// SAFETY: Access is read-only.
|
/// SAFETY: `Self` is the same as `Self::ReadOnly`
|
||||||
unsafe impl ReadOnlyWorldQuery for EntityRef<'_> {}
|
unsafe impl<'a> WorldQueryData for EntityRef<'a> {
|
||||||
|
type ReadOnly = Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// SAFETY: access is read only
|
||||||
|
unsafe impl ReadOnlyWorldQueryData for EntityRef<'_> {}
|
||||||
|
|
||||||
/// SAFETY: The accesses of `Self::ReadOnly` are a subset of the accesses of `Self`
|
/// SAFETY: The accesses of `Self::ReadOnly` are a subset of the accesses of `Self`
|
||||||
unsafe impl<'a> WorldQuery for EntityMut<'a> {
|
unsafe impl<'a> WorldQuery for EntityMut<'a> {
|
||||||
type Fetch<'w> = UnsafeWorldCell<'w>;
|
type Fetch<'w> = UnsafeWorldCell<'w>;
|
||||||
type Item<'w> = EntityMut<'w>;
|
type Item<'w> = EntityMut<'w>;
|
||||||
type ReadOnly = EntityRef<'a>;
|
|
||||||
type State = ();
|
type State = ();
|
||||||
|
|
||||||
fn shrink<'wlong: 'wshort, 'wshort>(item: Self::Item<'wlong>) -> Self::Item<'wshort> {
|
fn shrink<'wlong: 'wshort, 'wshort>(item: Self::Item<'wlong>) -> Self::Item<'wshort> {
|
||||||
|
@ -619,8 +442,6 @@ unsafe impl<'a> WorldQuery for EntityMut<'a> {
|
||||||
|
|
||||||
const IS_DENSE: bool = true;
|
const IS_DENSE: bool = true;
|
||||||
|
|
||||||
const IS_ARCHETYPAL: bool = true;
|
|
||||||
|
|
||||||
unsafe fn init_fetch<'w>(
|
unsafe fn init_fetch<'w>(
|
||||||
world: UnsafeWorldCell<'w>,
|
world: UnsafeWorldCell<'w>,
|
||||||
_state: &Self::State,
|
_state: &Self::State,
|
||||||
|
@ -683,6 +504,11 @@ unsafe impl<'a> WorldQuery for EntityMut<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// SAFETY: access of `EntityRef` is a subset of `EntityMut`
|
||||||
|
unsafe impl<'a> WorldQueryData for EntityMut<'a> {
|
||||||
|
type ReadOnly = EntityRef<'a>;
|
||||||
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub struct ReadFetch<'w, T> {
|
pub struct ReadFetch<'w, T> {
|
||||||
// T::Storage = TableStorage
|
// T::Storage = TableStorage
|
||||||
|
@ -698,11 +524,14 @@ impl<T> Clone for ReadFetch<'_, T> {
|
||||||
}
|
}
|
||||||
impl<T> Copy for ReadFetch<'_, T> {}
|
impl<T> Copy for ReadFetch<'_, T> {}
|
||||||
|
|
||||||
/// SAFETY: `Self` is the same as `Self::ReadOnly`
|
/// SAFETY:
|
||||||
|
/// `fetch` accesses a single component in a readonly way.
|
||||||
|
/// This is sound because `update_component_access` and `update_archetype_component_access` add read access for that component and panic when appropriate.
|
||||||
|
/// `update_component_access` adds a `With` filter for a component.
|
||||||
|
/// This is sound because `matches_component_set` returns whether the set contains that component.
|
||||||
unsafe impl<T: Component> WorldQuery for &T {
|
unsafe impl<T: Component> WorldQuery for &T {
|
||||||
type Fetch<'w> = ReadFetch<'w, T>;
|
type Fetch<'w> = ReadFetch<'w, T>;
|
||||||
type Item<'w> = &'w T;
|
type Item<'w> = &'w T;
|
||||||
type ReadOnly = Self;
|
|
||||||
type State = ComponentId;
|
type State = ComponentId;
|
||||||
|
|
||||||
fn shrink<'wlong: 'wshort, 'wshort>(item: &'wlong T) -> &'wshort T {
|
fn shrink<'wlong: 'wshort, 'wshort>(item: &'wlong T) -> &'wshort T {
|
||||||
|
@ -716,8 +545,6 @@ unsafe impl<T: Component> WorldQuery for &T {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const IS_ARCHETYPAL: bool = true;
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn init_fetch<'w>(
|
unsafe fn init_fetch<'w>(
|
||||||
world: UnsafeWorldCell<'w>,
|
world: UnsafeWorldCell<'w>,
|
||||||
|
@ -823,8 +650,13 @@ unsafe impl<T: Component> WorldQuery for &T {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// SAFETY: `Self` is the same as `Self::ReadOnly`
|
||||||
|
unsafe impl<T: Component> WorldQueryData for &T {
|
||||||
|
type ReadOnly = Self;
|
||||||
|
}
|
||||||
|
|
||||||
/// SAFETY: access is read only
|
/// SAFETY: access is read only
|
||||||
unsafe impl<T: Component> ReadOnlyWorldQuery for &T {}
|
unsafe impl<T: Component> ReadOnlyWorldQueryData for &T {}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub struct RefFetch<'w, T> {
|
pub struct RefFetch<'w, T> {
|
||||||
|
@ -848,11 +680,14 @@ impl<T> Clone for RefFetch<'_, T> {
|
||||||
}
|
}
|
||||||
impl<T> Copy for RefFetch<'_, T> {}
|
impl<T> Copy for RefFetch<'_, T> {}
|
||||||
|
|
||||||
/// SAFETY: `Self` is the same as `Self::ReadOnly`
|
/// SAFETY:
|
||||||
|
/// `fetch` accesses a single component in a readonly way.
|
||||||
|
/// This is sound because `update_component_access` and `update_archetype_component_access` add read access for that component and panic when appropriate.
|
||||||
|
/// `update_component_access` adds a `With` filter for a component.
|
||||||
|
/// This is sound because `matches_component_set` returns whether the set contains that component.
|
||||||
unsafe impl<'__w, T: Component> WorldQuery for Ref<'__w, T> {
|
unsafe impl<'__w, T: Component> WorldQuery for Ref<'__w, T> {
|
||||||
type Fetch<'w> = RefFetch<'w, T>;
|
type Fetch<'w> = RefFetch<'w, T>;
|
||||||
type Item<'w> = Ref<'w, T>;
|
type Item<'w> = Ref<'w, T>;
|
||||||
type ReadOnly = Self;
|
|
||||||
type State = ComponentId;
|
type State = ComponentId;
|
||||||
|
|
||||||
fn shrink<'wlong: 'wshort, 'wshort>(item: Ref<'wlong, T>) -> Ref<'wshort, T> {
|
fn shrink<'wlong: 'wshort, 'wshort>(item: Ref<'wlong, T>) -> Ref<'wshort, T> {
|
||||||
|
@ -866,8 +701,6 @@ unsafe impl<'__w, T: Component> WorldQuery for Ref<'__w, T> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const IS_ARCHETYPAL: bool = true;
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn init_fetch<'w>(
|
unsafe fn init_fetch<'w>(
|
||||||
world: UnsafeWorldCell<'w>,
|
world: UnsafeWorldCell<'w>,
|
||||||
|
@ -984,8 +817,13 @@ unsafe impl<'__w, T: Component> WorldQuery for Ref<'__w, T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// SAFETY: `Self` is the same as `Self::ReadOnly`
|
||||||
|
unsafe impl<'__w, T: Component> WorldQueryData for Ref<'__w, T> {
|
||||||
|
type ReadOnly = Self;
|
||||||
|
}
|
||||||
|
|
||||||
/// SAFETY: access is read only
|
/// SAFETY: access is read only
|
||||||
unsafe impl<'__w, T: Component> ReadOnlyWorldQuery for Ref<'__w, T> {}
|
unsafe impl<'__w, T: Component> ReadOnlyWorldQueryData for Ref<'__w, T> {}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub struct WriteFetch<'w, T> {
|
pub struct WriteFetch<'w, T> {
|
||||||
|
@ -1009,11 +847,14 @@ impl<T> Clone for WriteFetch<'_, T> {
|
||||||
}
|
}
|
||||||
impl<T> Copy for WriteFetch<'_, T> {}
|
impl<T> Copy for WriteFetch<'_, T> {}
|
||||||
|
|
||||||
/// SAFETY: access of `&T` is a subset of `&mut T`
|
/// SAFETY:
|
||||||
|
/// `fetch` accesses a single component mutably.
|
||||||
|
/// This is sound because `update_component_access` and `update_archetype_component_access` add write access for that component and panic when appropriate.
|
||||||
|
/// `update_component_access` adds a `With` filter for a component.
|
||||||
|
/// This is sound because `matches_component_set` returns whether the set contains that component.
|
||||||
unsafe impl<'__w, T: Component> WorldQuery for &'__w mut T {
|
unsafe impl<'__w, T: Component> WorldQuery for &'__w mut T {
|
||||||
type Fetch<'w> = WriteFetch<'w, T>;
|
type Fetch<'w> = WriteFetch<'w, T>;
|
||||||
type Item<'w> = Mut<'w, T>;
|
type Item<'w> = Mut<'w, T>;
|
||||||
type ReadOnly = &'__w T;
|
|
||||||
type State = ComponentId;
|
type State = ComponentId;
|
||||||
|
|
||||||
fn shrink<'wlong: 'wshort, 'wshort>(item: Mut<'wlong, T>) -> Mut<'wshort, T> {
|
fn shrink<'wlong: 'wshort, 'wshort>(item: Mut<'wlong, T>) -> Mut<'wshort, T> {
|
||||||
|
@ -1027,8 +868,6 @@ unsafe impl<'__w, T: Component> WorldQuery for &'__w mut T {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const IS_ARCHETYPAL: bool = true;
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn init_fetch<'w>(
|
unsafe fn init_fetch<'w>(
|
||||||
world: UnsafeWorldCell<'w>,
|
world: UnsafeWorldCell<'w>,
|
||||||
|
@ -1145,6 +984,11 @@ unsafe impl<'__w, T: Component> WorldQuery for &'__w mut T {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// SAFETY: access of `&T` is a subset of `&mut T`
|
||||||
|
unsafe impl<'__w, T: Component> WorldQueryData for &'__w mut T {
|
||||||
|
type ReadOnly = &'__w T;
|
||||||
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub struct OptionFetch<'w, T: WorldQuery> {
|
pub struct OptionFetch<'w, T: WorldQuery> {
|
||||||
fetch: T::Fetch<'w>,
|
fetch: T::Fetch<'w>,
|
||||||
|
@ -1160,11 +1004,13 @@ impl<T: WorldQuery> Clone for OptionFetch<'_, T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SAFETY: defers to soundness of `T: WorldQuery` impl
|
/// SAFETY:
|
||||||
|
/// `fetch` might access any components that `T` accesses.
|
||||||
|
/// This is sound because `update_component_access` and `update_archetype_component_access` add the same accesses as `T`.
|
||||||
|
/// Filters are unchanged.
|
||||||
unsafe impl<T: WorldQuery> WorldQuery for Option<T> {
|
unsafe impl<T: WorldQuery> WorldQuery for Option<T> {
|
||||||
type Fetch<'w> = OptionFetch<'w, T>;
|
type Fetch<'w> = OptionFetch<'w, T>;
|
||||||
type Item<'w> = Option<T::Item<'w>>;
|
type Item<'w> = Option<T::Item<'w>>;
|
||||||
type ReadOnly = Option<T::ReadOnly>;
|
|
||||||
type State = T::State;
|
type State = T::State;
|
||||||
|
|
||||||
fn shrink<'wlong: 'wshort, 'wshort>(item: Self::Item<'wlong>) -> Self::Item<'wshort> {
|
fn shrink<'wlong: 'wshort, 'wshort>(item: Self::Item<'wlong>) -> Self::Item<'wshort> {
|
||||||
|
@ -1173,8 +1019,6 @@ unsafe impl<T: WorldQuery> WorldQuery for Option<T> {
|
||||||
|
|
||||||
const IS_DENSE: bool = T::IS_DENSE;
|
const IS_DENSE: bool = T::IS_DENSE;
|
||||||
|
|
||||||
const IS_ARCHETYPAL: bool = T::IS_ARCHETYPAL;
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn init_fetch<'w>(
|
unsafe fn init_fetch<'w>(
|
||||||
world: UnsafeWorldCell<'w>,
|
world: UnsafeWorldCell<'w>,
|
||||||
|
@ -1257,8 +1101,13 @@ unsafe impl<T: WorldQuery> WorldQuery for Option<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SAFETY: defers to soundness of `T: WorldQuery` impl
|
||||||
|
unsafe impl<T: WorldQueryData> WorldQueryData for Option<T> {
|
||||||
|
type ReadOnly = Option<T::ReadOnly>;
|
||||||
|
}
|
||||||
|
|
||||||
/// SAFETY: [`OptionFetch`] is read only because `T` is read only
|
/// SAFETY: [`OptionFetch`] is read only because `T` is read only
|
||||||
unsafe impl<T: ReadOnlyWorldQuery> ReadOnlyWorldQuery for Option<T> {}
|
unsafe impl<T: ReadOnlyWorldQueryData> ReadOnlyWorldQueryData for Option<T> {}
|
||||||
|
|
||||||
/// Returns a bool that describes if an entity has the component `T`.
|
/// Returns a bool that describes if an entity has the component `T`.
|
||||||
///
|
///
|
||||||
|
@ -1315,11 +1164,12 @@ unsafe impl<T: ReadOnlyWorldQuery> ReadOnlyWorldQuery for Option<T> {}
|
||||||
/// ```
|
/// ```
|
||||||
pub struct Has<T>(PhantomData<T>);
|
pub struct Has<T>(PhantomData<T>);
|
||||||
|
|
||||||
// SAFETY: `Self::ReadOnly` is the same as `Self`
|
/// SAFETY:
|
||||||
|
/// `update_component_access` and `update_archetype_component_access` do nothing.
|
||||||
|
/// This is sound because `fetch` does not access components.
|
||||||
unsafe impl<T: Component> WorldQuery for Has<T> {
|
unsafe impl<T: Component> WorldQuery for Has<T> {
|
||||||
type Fetch<'w> = bool;
|
type Fetch<'w> = bool;
|
||||||
type Item<'w> = bool;
|
type Item<'w> = bool;
|
||||||
type ReadOnly = Self;
|
|
||||||
type State = ComponentId;
|
type State = ComponentId;
|
||||||
|
|
||||||
fn shrink<'wlong: 'wshort, 'wshort>(item: Self::Item<'wlong>) -> Self::Item<'wshort> {
|
fn shrink<'wlong: 'wshort, 'wshort>(item: Self::Item<'wlong>) -> Self::Item<'wshort> {
|
||||||
|
@ -1333,8 +1183,6 @@ unsafe impl<T: Component> WorldQuery for Has<T> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const IS_ARCHETYPAL: bool = true;
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn init_fetch<'w>(
|
unsafe fn init_fetch<'w>(
|
||||||
_world: UnsafeWorldCell<'w>,
|
_world: UnsafeWorldCell<'w>,
|
||||||
|
@ -1393,105 +1241,14 @@ unsafe impl<T: Component> WorldQuery for Has<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// SAFETY: [`Has`] is read only
|
/// SAFETY: `Self` is the same as `Self::ReadOnly`
|
||||||
unsafe impl<T: Component> ReadOnlyWorldQuery for Has<T> {}
|
unsafe impl<T: Component> WorldQueryData for Has<T> {
|
||||||
|
type ReadOnly = Self;
|
||||||
macro_rules! impl_tuple_fetch {
|
|
||||||
($(($name: ident, $state: ident)),*) => {
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
#[allow(clippy::unused_unit)]
|
|
||||||
// SAFETY: defers to soundness `$name: WorldQuery` impl
|
|
||||||
unsafe impl<$($name: WorldQuery),*> WorldQuery for ($($name,)*) {
|
|
||||||
type Fetch<'w> = ($($name::Fetch<'w>,)*);
|
|
||||||
type Item<'w> = ($($name::Item<'w>,)*);
|
|
||||||
type ReadOnly = ($($name::ReadOnly,)*);
|
|
||||||
type State = ($($name::State,)*);
|
|
||||||
|
|
||||||
fn shrink<'wlong: 'wshort, 'wshort>(item: Self::Item<'wlong>) -> Self::Item<'wshort> {
|
|
||||||
let ($($name,)*) = item;
|
|
||||||
($(
|
|
||||||
$name::shrink($name),
|
|
||||||
)*)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
#[allow(clippy::unused_unit)]
|
|
||||||
unsafe fn init_fetch<'w>(_world: UnsafeWorldCell<'w>, state: &Self::State, _last_run: Tick, _this_run: Tick) -> Self::Fetch<'w> {
|
|
||||||
let ($($name,)*) = state;
|
|
||||||
($($name::init_fetch(_world, $name, _last_run, _this_run),)*)
|
|
||||||
}
|
|
||||||
|
|
||||||
const IS_DENSE: bool = true $(&& $name::IS_DENSE)*;
|
|
||||||
|
|
||||||
const IS_ARCHETYPAL: bool = true $(&& $name::IS_ARCHETYPAL)*;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
unsafe fn set_archetype<'w>(
|
|
||||||
_fetch: &mut Self::Fetch<'w>,
|
|
||||||
_state: &Self::State,
|
|
||||||
_archetype: &'w Archetype,
|
|
||||||
_table: &'w Table
|
|
||||||
) {
|
|
||||||
let ($($name,)*) = _fetch;
|
|
||||||
let ($($state,)*) = _state;
|
|
||||||
$($name::set_archetype($name, $state, _archetype, _table);)*
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
unsafe fn set_table<'w>(_fetch: &mut Self::Fetch<'w>, _state: &Self::State, _table: &'w Table) {
|
|
||||||
let ($($name,)*) = _fetch;
|
|
||||||
let ($($state,)*) = _state;
|
|
||||||
$($name::set_table($name, $state, _table);)*
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
#[allow(clippy::unused_unit)]
|
|
||||||
unsafe fn fetch<'w>(
|
|
||||||
_fetch: &mut Self::Fetch<'w>,
|
|
||||||
_entity: Entity,
|
|
||||||
_table_row: TableRow
|
|
||||||
) -> Self::Item<'w> {
|
|
||||||
let ($($name,)*) = _fetch;
|
|
||||||
($($name::fetch($name, _entity, _table_row),)*)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
unsafe fn filter_fetch(
|
|
||||||
_fetch: &mut Self::Fetch<'_>,
|
|
||||||
_entity: Entity,
|
|
||||||
_table_row: TableRow
|
|
||||||
) -> bool {
|
|
||||||
let ($($name,)*) = _fetch;
|
|
||||||
true $(&& $name::filter_fetch($name, _entity, _table_row))*
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update_component_access(state: &Self::State, _access: &mut FilteredAccess<ComponentId>) {
|
|
||||||
let ($($name,)*) = state;
|
|
||||||
$($name::update_component_access($name, _access);)*
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update_archetype_component_access(state: &Self::State, _archetype: &Archetype, _access: &mut Access<ArchetypeComponentId>) {
|
|
||||||
let ($($name,)*) = state;
|
|
||||||
$($name::update_archetype_component_access($name, _archetype, _access);)*
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fn init_state(_world: &mut World) -> Self::State {
|
|
||||||
($($name::init_state(_world),)*)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn matches_component_set(state: &Self::State, _set_contains_id: &impl Fn(ComponentId) -> bool) -> bool {
|
|
||||||
let ($($name,)*) = state;
|
|
||||||
true $(&& $name::matches_component_set($name, _set_contains_id))*
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// SAFETY: each item in the tuple is read only
|
|
||||||
unsafe impl<$($name: ReadOnlyWorldQuery),*> ReadOnlyWorldQuery for ($($name,)*) {}
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// SAFETY: [`Has`] is read only
|
||||||
|
unsafe impl<T: Component> ReadOnlyWorldQueryData for Has<T> {}
|
||||||
|
|
||||||
/// The `AnyOf` query parameter fetches entities with any of the component types included in T.
|
/// The `AnyOf` query parameter fetches entities with any of the component types included in T.
|
||||||
///
|
///
|
||||||
/// `Query<AnyOf<(&A, &B, &mut C)>>` is equivalent to `Query<(Option<&A>, Option<&B>, Option<&mut C>), Or<(With<A>, With<B>, With<C>)>>`.
|
/// `Query<AnyOf<(&A, &B, &mut C)>>` is equivalent to `Query<(Option<&A>, Option<&B>, Option<&mut C>), Or<(With<A>, With<B>, With<C>)>>`.
|
||||||
|
@ -1499,15 +1256,35 @@ macro_rules! impl_tuple_fetch {
|
||||||
/// Entities are guaranteed to have at least one of the components in `T`.
|
/// Entities are guaranteed to have at least one of the components in `T`.
|
||||||
pub struct AnyOf<T>(PhantomData<T>);
|
pub struct AnyOf<T>(PhantomData<T>);
|
||||||
|
|
||||||
macro_rules! impl_anytuple_fetch {
|
macro_rules! impl_tuple_world_query_data {
|
||||||
($(($name: ident, $state: ident)),*) => {
|
($(($name: ident, $state: ident)),*) => {
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
#[allow(clippy::unused_unit)]
|
#[allow(clippy::unused_unit)]
|
||||||
// SAFETY: defers to soundness of `$name: WorldQuery` impl
|
// SAFETY: defers to soundness `$name: WorldQuery` impl
|
||||||
|
unsafe impl<$($name: WorldQueryData),*> WorldQueryData for ($($name,)*) {
|
||||||
|
type ReadOnly = ($($name::ReadOnly,)*);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// SAFETY: each item in the tuple is read only
|
||||||
|
unsafe impl<$($name: ReadOnlyWorldQueryData),*> ReadOnlyWorldQueryData for ($($name,)*) {}
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_anytuple_fetch {
|
||||||
|
($(($name: ident, $state: ident)),*) => {
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
#[allow(clippy::unused_unit)]
|
||||||
|
/// SAFETY:
|
||||||
|
/// `fetch` accesses are a subset of the subqueries' accesses
|
||||||
|
/// This is sound because `update_component_access` and `update_archetype_component_access` adds accesses according to the implementations of all the subqueries.
|
||||||
|
/// `update_component_access` replaces the filters with a disjunction where every element is a conjunction of the previous filters and the filters of one of the subqueries.
|
||||||
|
/// This is sound because `matches_component_set` returns a disjunction of the results of the subqueries' implementations.
|
||||||
unsafe impl<$($name: WorldQuery),*> WorldQuery for AnyOf<($($name,)*)> {
|
unsafe impl<$($name: WorldQuery),*> WorldQuery for AnyOf<($($name,)*)> {
|
||||||
type Fetch<'w> = ($(($name::Fetch<'w>, bool),)*);
|
type Fetch<'w> = ($(($name::Fetch<'w>, bool),)*);
|
||||||
type Item<'w> = ($(Option<$name::Item<'w>>,)*);
|
type Item<'w> = ($(Option<$name::Item<'w>>,)*);
|
||||||
type ReadOnly = AnyOf<($($name::ReadOnly,)*)>;
|
|
||||||
type State = ($($name::State,)*);
|
type State = ($($name::State,)*);
|
||||||
|
|
||||||
fn shrink<'wlong: 'wshort, 'wshort>(item: Self::Item<'wlong>) -> Self::Item<'wshort> {
|
fn shrink<'wlong: 'wshort, 'wshort>(item: Self::Item<'wlong>) -> Self::Item<'wshort> {
|
||||||
|
@ -1526,8 +1303,6 @@ macro_rules! impl_anytuple_fetch {
|
||||||
|
|
||||||
const IS_DENSE: bool = true $(&& $name::IS_DENSE)*;
|
const IS_DENSE: bool = true $(&& $name::IS_DENSE)*;
|
||||||
|
|
||||||
const IS_ARCHETYPAL: bool = true $(&& $name::IS_ARCHETYPAL)*;
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn set_archetype<'w>(
|
unsafe fn set_archetype<'w>(
|
||||||
_fetch: &mut Self::Fetch<'w>,
|
_fetch: &mut Self::Fetch<'w>,
|
||||||
|
@ -1609,32 +1384,38 @@ macro_rules! impl_anytuple_fetch {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
#[allow(clippy::unused_unit)]
|
||||||
|
// SAFETY: defers to soundness of `$name: WorldQuery` impl
|
||||||
|
unsafe impl<$($name: WorldQueryData),*> WorldQueryData for AnyOf<($($name,)*)> {
|
||||||
|
type ReadOnly = AnyOf<($($name::ReadOnly,)*)>;
|
||||||
|
}
|
||||||
|
|
||||||
/// SAFETY: each item in the tuple is read only
|
/// SAFETY: each item in the tuple is read only
|
||||||
unsafe impl<$($name: ReadOnlyWorldQuery),*> ReadOnlyWorldQuery for AnyOf<($($name,)*)> {}
|
unsafe impl<$($name: ReadOnlyWorldQueryData),*> ReadOnlyWorldQueryData for AnyOf<($($name,)*)> {}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
all_tuples!(impl_tuple_fetch, 0, 15, F, S);
|
all_tuples!(impl_tuple_world_query_data, 0, 15, F, S);
|
||||||
all_tuples!(impl_anytuple_fetch, 0, 15, F, S);
|
all_tuples!(impl_anytuple_fetch, 0, 15, F, S);
|
||||||
|
|
||||||
/// [`WorldQuery`] used to nullify queries by turning `Query<Q>` into `Query<NopWorldQuery<Q>>`
|
/// [`WorldQuery`] used to nullify queries by turning `Query<Q>` into `Query<NopWorldQuery<Q>>`
|
||||||
///
|
///
|
||||||
/// This will rarely be useful to consumers of `bevy_ecs`.
|
/// This will rarely be useful to consumers of `bevy_ecs`.
|
||||||
pub struct NopWorldQuery<Q: WorldQuery>(PhantomData<Q>);
|
pub struct NopWorldQuery<Q: WorldQueryData>(PhantomData<Q>);
|
||||||
|
|
||||||
/// SAFETY: `Self::ReadOnly` is `Self`
|
/// SAFETY:
|
||||||
unsafe impl<Q: WorldQuery> WorldQuery for NopWorldQuery<Q> {
|
/// `update_component_access` and `update_archetype_component_access` do nothing.
|
||||||
|
/// This is sound because `fetch` does not access components.
|
||||||
|
unsafe impl<Q: WorldQueryData> WorldQuery for NopWorldQuery<Q> {
|
||||||
type Fetch<'w> = ();
|
type Fetch<'w> = ();
|
||||||
type Item<'w> = ();
|
type Item<'w> = ();
|
||||||
type ReadOnly = Self;
|
|
||||||
type State = Q::State;
|
type State = Q::State;
|
||||||
|
|
||||||
fn shrink<'wlong: 'wshort, 'wshort>(_: ()) {}
|
fn shrink<'wlong: 'wshort, 'wshort>(_: ()) {}
|
||||||
|
|
||||||
const IS_DENSE: bool = Q::IS_DENSE;
|
const IS_DENSE: bool = Q::IS_DENSE;
|
||||||
|
|
||||||
const IS_ARCHETYPAL: bool = true;
|
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
unsafe fn init_fetch(
|
unsafe fn init_fetch(
|
||||||
_world: UnsafeWorldCell,
|
_world: UnsafeWorldCell,
|
||||||
|
@ -1685,14 +1466,21 @@ unsafe impl<Q: WorldQuery> WorldQuery for NopWorldQuery<Q> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// SAFETY: `NopFetch` never accesses any data
|
/// SAFETY: `Self::ReadOnly` is `Self`
|
||||||
unsafe impl<Q: WorldQuery> ReadOnlyWorldQuery for NopWorldQuery<Q> {}
|
unsafe impl<Q: WorldQueryData> WorldQueryData for NopWorldQuery<Q> {
|
||||||
|
type ReadOnly = Self;
|
||||||
|
}
|
||||||
|
|
||||||
/// SAFETY: `PhantomData` never accesses any world data.
|
/// SAFETY: `NopFetch` never accesses any data
|
||||||
|
unsafe impl<Q: WorldQueryData> ReadOnlyWorldQueryData for NopWorldQuery<Q> {}
|
||||||
|
|
||||||
|
/// SAFETY:
|
||||||
|
/// `update_component_access` and `update_archetype_component_access` do nothing.
|
||||||
|
/// This is sound because `fetch` does not access components.
|
||||||
unsafe impl<T: ?Sized> WorldQuery for PhantomData<T> {
|
unsafe impl<T: ?Sized> WorldQuery for PhantomData<T> {
|
||||||
type Item<'a> = ();
|
type Item<'a> = ();
|
||||||
type Fetch<'a> = ();
|
type Fetch<'a> = ();
|
||||||
type ReadOnly = Self;
|
|
||||||
type State = ();
|
type State = ();
|
||||||
|
|
||||||
fn shrink<'wlong: 'wshort, 'wshort>(_item: Self::Item<'wlong>) -> Self::Item<'wshort> {}
|
fn shrink<'wlong: 'wshort, 'wshort>(_item: Self::Item<'wlong>) -> Self::Item<'wshort> {}
|
||||||
|
@ -1708,8 +1496,6 @@ unsafe impl<T: ?Sized> WorldQuery for PhantomData<T> {
|
||||||
// `PhantomData` does not match any components, so all components it matches
|
// `PhantomData` does not match any components, so all components it matches
|
||||||
// are stored in a Table (vacuous truth).
|
// are stored in a Table (vacuous truth).
|
||||||
const IS_DENSE: bool = true;
|
const IS_DENSE: bool = true;
|
||||||
// `PhantomData` matches every entity in each archetype.
|
|
||||||
const IS_ARCHETYPAL: bool = true;
|
|
||||||
|
|
||||||
unsafe fn set_archetype<'w>(
|
unsafe fn set_archetype<'w>(
|
||||||
_fetch: &mut Self::Fetch<'w>,
|
_fetch: &mut Self::Fetch<'w>,
|
||||||
|
@ -1748,11 +1534,18 @@ unsafe impl<T: ?Sized> WorldQuery for PhantomData<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// SAFETY: `Self::ReadOnly` is `Self`
|
||||||
|
unsafe impl<T: ?Sized> WorldQueryData for PhantomData<T> {
|
||||||
|
type ReadOnly = Self;
|
||||||
|
}
|
||||||
|
|
||||||
/// SAFETY: `PhantomData` never accesses any world data.
|
/// SAFETY: `PhantomData` never accesses any world data.
|
||||||
unsafe impl<T: ?Sized> ReadOnlyWorldQuery for PhantomData<T> {}
|
unsafe impl<T: ?Sized> ReadOnlyWorldQueryData for PhantomData<T> {}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use bevy_ecs_macros::WorldQueryData;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
self as bevy_ecs,
|
self as bevy_ecs,
|
||||||
|
@ -1768,16 +1561,16 @@ mod tests {
|
||||||
// Tests that each variant of struct can be used as a `WorldQuery`.
|
// Tests that each variant of struct can be used as a `WorldQuery`.
|
||||||
#[test]
|
#[test]
|
||||||
fn world_query_struct_variants() {
|
fn world_query_struct_variants() {
|
||||||
#[derive(WorldQuery)]
|
#[derive(WorldQueryData)]
|
||||||
pub struct NamedQuery {
|
pub struct NamedQuery {
|
||||||
id: Entity,
|
id: Entity,
|
||||||
a: &'static A,
|
a: &'static A,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(WorldQuery)]
|
#[derive(WorldQueryData)]
|
||||||
pub struct TupleQuery(&'static A, &'static B);
|
pub struct TupleQuery(&'static A, &'static B);
|
||||||
|
|
||||||
#[derive(WorldQuery)]
|
#[derive(WorldQueryData)]
|
||||||
pub struct UnitQuery;
|
pub struct UnitQuery;
|
||||||
|
|
||||||
fn my_system(_: Query<(NamedQuery, TupleQuery, UnitQuery)>) {}
|
fn my_system(_: Query<(NamedQuery, TupleQuery, UnitQuery)>) {}
|
||||||
|
@ -1788,7 +1581,7 @@ mod tests {
|
||||||
// Compile test for https://github.com/bevyengine/bevy/pull/8030.
|
// Compile test for https://github.com/bevyengine/bevy/pull/8030.
|
||||||
#[test]
|
#[test]
|
||||||
fn world_query_phantom_data() {
|
fn world_query_phantom_data() {
|
||||||
#[derive(WorldQuery)]
|
#[derive(WorldQueryData)]
|
||||||
pub struct IgnoredQuery<Marker> {
|
pub struct IgnoredQuery<Marker> {
|
||||||
id: Entity,
|
id: Entity,
|
||||||
_marker: PhantomData<Marker>,
|
_marker: PhantomData<Marker>,
|
||||||
|
@ -1806,8 +1599,8 @@ mod tests {
|
||||||
mod private {
|
mod private {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[derive(WorldQuery)]
|
#[derive(WorldQueryData)]
|
||||||
#[world_query(mutable)]
|
#[world_query_data(mutable)]
|
||||||
pub struct Q {
|
pub struct Q {
|
||||||
pub a: &'static mut A,
|
pub a: &'static mut A,
|
||||||
}
|
}
|
||||||
|
@ -1831,7 +1624,7 @@ mod tests {
|
||||||
fn world_query_metadata_collision() {
|
fn world_query_metadata_collision() {
|
||||||
// The metadata types generated would be named `ClientState` and `ClientFetch`,
|
// The metadata types generated would be named `ClientState` and `ClientFetch`,
|
||||||
// but they should rename themselves to avoid conflicts.
|
// but they should rename themselves to avoid conflicts.
|
||||||
#[derive(WorldQuery)]
|
#[derive(WorldQueryData)]
|
||||||
pub struct Client<S: ClientState> {
|
pub struct Client<S: ClientState> {
|
||||||
pub state: &'static S,
|
pub state: &'static S,
|
||||||
pub fetch: &'static ClientFetch,
|
pub fetch: &'static ClientFetch,
|
||||||
|
|
|
@ -10,7 +10,92 @@ use bevy_ptr::{ThinSlicePtr, UnsafeCellDeref};
|
||||||
use bevy_utils::all_tuples;
|
use bevy_utils::all_tuples;
|
||||||
use std::{cell::UnsafeCell, marker::PhantomData};
|
use std::{cell::UnsafeCell, marker::PhantomData};
|
||||||
|
|
||||||
use super::ReadOnlyWorldQuery;
|
/// Types that filter the results of a [`Query`].
|
||||||
|
///
|
||||||
|
/// There are many types that natively implement this trait:
|
||||||
|
/// - **Component filters.**
|
||||||
|
/// [`With`] and [`Without`] filters can be applied to check if the queried entity does or does not contain a particular component.
|
||||||
|
/// - **Change detection filters.**
|
||||||
|
/// [`Added`] and [`Changed`] filters can be applied to detect component changes to an entity.
|
||||||
|
/// - **`WorldQueryFilter` tuples.**
|
||||||
|
/// If every element of a tuple implements `WorldQueryFilter`, then the tuple itself also implements the same trait.
|
||||||
|
/// This enables a single `Query` to filter over multiple conditions.
|
||||||
|
/// Due to the current lack of variadic generics in Rust, the trait has been implemented for tuples from 0 to 15 elements,
|
||||||
|
/// but nesting of tuples allows infinite `WorldQueryFilter`s.
|
||||||
|
/// - **Filter disjunction operator.**
|
||||||
|
/// By default, tuples compose query filters in such a way that all conditions must be satisfied to generate a query item for a given entity.
|
||||||
|
/// Wrapping a tuple inside an [`Or`] operator will relax the requirement to just one condition.
|
||||||
|
///
|
||||||
|
/// Implementing the trait manually can allow for a fundamentally new type of behavior.
|
||||||
|
///
|
||||||
|
/// Query design can be easily structured by deriving `WorldQueryFilter` for custom types.
|
||||||
|
/// Despite the added complexity, this approach has several advantages over using `WorldQueryFilter` tuples.
|
||||||
|
/// The most relevant improvements are:
|
||||||
|
///
|
||||||
|
/// - Reusability across multiple systems.
|
||||||
|
/// - Filters can be composed together to create a more complex filter.
|
||||||
|
///
|
||||||
|
/// This trait can only be derived for structs if each field also implements `WorldQueryFilter`.
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use bevy_ecs::prelude::*;
|
||||||
|
/// # use bevy_ecs::{query::WorldQueryFilter, component::Component};
|
||||||
|
/// #
|
||||||
|
/// # #[derive(Component)]
|
||||||
|
/// # struct ComponentA;
|
||||||
|
/// # #[derive(Component)]
|
||||||
|
/// # struct ComponentB;
|
||||||
|
/// # #[derive(Component)]
|
||||||
|
/// # struct ComponentC;
|
||||||
|
/// # #[derive(Component)]
|
||||||
|
/// # struct ComponentD;
|
||||||
|
/// # #[derive(Component)]
|
||||||
|
/// # struct ComponentE;
|
||||||
|
/// #
|
||||||
|
/// #[derive(WorldQueryFilter)]
|
||||||
|
/// struct MyFilter<T: Component, P: Component> {
|
||||||
|
/// // Field names are not relevant, since they are never manually accessed.
|
||||||
|
/// with_a: With<ComponentA>,
|
||||||
|
/// or_filter: Or<(With<ComponentC>, Added<ComponentB>)>,
|
||||||
|
/// generic_tuple: (With<T>, Without<P>),
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// fn my_system(query: Query<Entity, MyFilter<ComponentD, ComponentE>>) {
|
||||||
|
/// // ...
|
||||||
|
/// }
|
||||||
|
/// # bevy_ecs::system::assert_is_system(my_system);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// [`fetch`]: Self::fetch
|
||||||
|
/// [`Changed`]: crate::query::Changed
|
||||||
|
/// [`matches_component_set`]: Self::matches_component_set
|
||||||
|
/// [`Or`]: crate::query::Or
|
||||||
|
/// [`Query`]: crate::system::Query
|
||||||
|
/// [`State`]: Self::State
|
||||||
|
/// [`update_archetype_component_access`]: Self::update_archetype_component_access
|
||||||
|
/// [`update_component_access`]: Self::update_component_access
|
||||||
|
/// [`With`]: crate::query::With
|
||||||
|
/// [`Without`]: crate::query::Without
|
||||||
|
|
||||||
|
pub trait WorldQueryFilter: WorldQuery {
|
||||||
|
/// Returns true if (and only if) this Filter relies strictly on archetypes to limit which
|
||||||
|
/// components are accessed by the Query.
|
||||||
|
///
|
||||||
|
/// This enables optimizations for [`crate::query::QueryIter`] that rely on knowing exactly how
|
||||||
|
/// many elements are being iterated (such as `Iterator::collect()`).
|
||||||
|
const IS_ARCHETYPAL: bool;
|
||||||
|
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// Must always be called _after_ [`WorldQuery::set_table`] or [`WorldQuery::set_archetype`]. `entity` and
|
||||||
|
/// `table_row` must be in the range of the current table and archetype.
|
||||||
|
#[allow(unused_variables)]
|
||||||
|
unsafe fn filter_fetch(
|
||||||
|
fetch: &mut Self::Fetch<'_>,
|
||||||
|
entity: Entity,
|
||||||
|
table_row: TableRow,
|
||||||
|
) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
/// Filter that selects entities with a component `T`.
|
/// Filter that selects entities with a component `T`.
|
||||||
///
|
///
|
||||||
|
@ -41,11 +126,14 @@ use super::ReadOnlyWorldQuery;
|
||||||
/// ```
|
/// ```
|
||||||
pub struct With<T>(PhantomData<T>);
|
pub struct With<T>(PhantomData<T>);
|
||||||
|
|
||||||
// SAFETY: `Self::ReadOnly` is the same as `Self`
|
/// SAFETY:
|
||||||
|
/// `update_component_access` and `update_archetype_component_access` do not add any accesses.
|
||||||
|
/// This is sound because `fetch` does not access any components.
|
||||||
|
/// `update_component_access` adds a `With` filter for `T`.
|
||||||
|
/// This is sound because `matches_component_set` returns whether the set contains the component.
|
||||||
unsafe impl<T: Component> WorldQuery for With<T> {
|
unsafe impl<T: Component> WorldQuery for With<T> {
|
||||||
type Fetch<'w> = ();
|
type Fetch<'w> = ();
|
||||||
type Item<'w> = ();
|
type Item<'w> = ();
|
||||||
type ReadOnly = Self;
|
|
||||||
type State = ComponentId;
|
type State = ComponentId;
|
||||||
|
|
||||||
fn shrink<'wlong: 'wshort, 'wshort>(_: Self::Item<'wlong>) -> Self::Item<'wshort> {}
|
fn shrink<'wlong: 'wshort, 'wshort>(_: Self::Item<'wlong>) -> Self::Item<'wshort> {}
|
||||||
|
@ -66,8 +154,6 @@ unsafe impl<T: Component> WorldQuery for With<T> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const IS_ARCHETYPAL: bool = true;
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn set_table(_fetch: &mut (), _state: &ComponentId, _table: &Table) {}
|
unsafe fn set_table(_fetch: &mut (), _state: &ComponentId, _table: &Table) {}
|
||||||
|
|
||||||
|
@ -113,8 +199,18 @@ unsafe impl<T: Component> WorldQuery for With<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SAFETY: no component access or archetype component access
|
impl<T: Component> WorldQueryFilter for With<T> {
|
||||||
unsafe impl<T: Component> ReadOnlyWorldQuery for With<T> {}
|
const IS_ARCHETYPAL: bool = true;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn filter_fetch(
|
||||||
|
_fetch: &mut Self::Fetch<'_>,
|
||||||
|
_entity: Entity,
|
||||||
|
_table_row: TableRow,
|
||||||
|
) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Filter that selects entities without a component `T`.
|
/// Filter that selects entities without a component `T`.
|
||||||
///
|
///
|
||||||
|
@ -142,11 +238,14 @@ unsafe impl<T: Component> ReadOnlyWorldQuery for With<T> {}
|
||||||
/// ```
|
/// ```
|
||||||
pub struct Without<T>(PhantomData<T>);
|
pub struct Without<T>(PhantomData<T>);
|
||||||
|
|
||||||
// SAFETY: `Self::ReadOnly` is the same as `Self`
|
/// SAFETY:
|
||||||
|
/// `update_component_access` and `update_archetype_component_access` do not add any accesses.
|
||||||
|
/// This is sound because `fetch` does not access any components.
|
||||||
|
/// `update_component_access` adds a `Without` filter for `T`.
|
||||||
|
/// This is sound because `matches_component_set` returns whether the set does not contain the component.
|
||||||
unsafe impl<T: Component> WorldQuery for Without<T> {
|
unsafe impl<T: Component> WorldQuery for Without<T> {
|
||||||
type Fetch<'w> = ();
|
type Fetch<'w> = ();
|
||||||
type Item<'w> = ();
|
type Item<'w> = ();
|
||||||
type ReadOnly = Self;
|
|
||||||
type State = ComponentId;
|
type State = ComponentId;
|
||||||
|
|
||||||
fn shrink<'wlong: 'wshort, 'wshort>(_: Self::Item<'wlong>) -> Self::Item<'wshort> {}
|
fn shrink<'wlong: 'wshort, 'wshort>(_: Self::Item<'wlong>) -> Self::Item<'wshort> {}
|
||||||
|
@ -167,8 +266,6 @@ unsafe impl<T: Component> WorldQuery for Without<T> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const IS_ARCHETYPAL: bool = true;
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn set_table(_fetch: &mut (), _state: &Self::State, _table: &Table) {}
|
unsafe fn set_table(_fetch: &mut (), _state: &Self::State, _table: &Table) {}
|
||||||
|
|
||||||
|
@ -214,8 +311,18 @@ unsafe impl<T: Component> WorldQuery for Without<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SAFETY: no component access or archetype component access
|
impl<T: Component> WorldQueryFilter for Without<T> {
|
||||||
unsafe impl<T: Component> ReadOnlyWorldQuery for Without<T> {}
|
const IS_ARCHETYPAL: bool = true;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn filter_fetch(
|
||||||
|
_fetch: &mut Self::Fetch<'_>,
|
||||||
|
_entity: Entity,
|
||||||
|
_table_row: TableRow,
|
||||||
|
) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A filter that tests if any of the given filters apply.
|
/// A filter that tests if any of the given filters apply.
|
||||||
///
|
///
|
||||||
|
@ -269,11 +376,14 @@ macro_rules! impl_query_filter_tuple {
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
#[allow(clippy::unused_unit)]
|
#[allow(clippy::unused_unit)]
|
||||||
// SAFETY: defers to soundness of `$filter: WorldQuery` impl
|
/// SAFETY:
|
||||||
unsafe impl<$($filter: WorldQuery),*> WorldQuery for Or<($($filter,)*)> {
|
/// `fetch` accesses are a subset of the subqueries' accesses
|
||||||
|
/// This is sound because `update_component_access` and `update_archetype_component_access` adds accesses according to the implementations of all the subqueries.
|
||||||
|
/// `update_component_access` replace the filters with a disjunction where every element is a conjunction of the previous filters and the filters of one of the subqueries.
|
||||||
|
/// This is sound because `matches_component_set` returns a disjunction of the results of the subqueries' implementations.
|
||||||
|
unsafe impl<$($filter: WorldQueryFilter),*> WorldQuery for Or<($($filter,)*)> {
|
||||||
type Fetch<'w> = ($(OrFetch<'w, $filter>,)*);
|
type Fetch<'w> = ($(OrFetch<'w, $filter>,)*);
|
||||||
type Item<'w> = bool;
|
type Item<'w> = bool;
|
||||||
type ReadOnly = Or<($($filter::ReadOnly,)*)>;
|
|
||||||
type State = ($($filter::State,)*);
|
type State = ($($filter::State,)*);
|
||||||
|
|
||||||
fn shrink<'wlong: 'wshort, 'wshort>(item: Self::Item<'wlong>) -> Self::Item<'wshort> {
|
fn shrink<'wlong: 'wshort, 'wshort>(item: Self::Item<'wlong>) -> Self::Item<'wshort> {
|
||||||
|
@ -282,8 +392,6 @@ macro_rules! impl_query_filter_tuple {
|
||||||
|
|
||||||
const IS_DENSE: bool = true $(&& $filter::IS_DENSE)*;
|
const IS_DENSE: bool = true $(&& $filter::IS_DENSE)*;
|
||||||
|
|
||||||
const IS_ARCHETYPAL: bool = true $(&& $filter::IS_ARCHETYPAL)*;
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn init_fetch<'w>(world: UnsafeWorldCell<'w>, state: &Self::State, last_run: Tick, this_run: Tick) -> Self::Fetch<'w> {
|
unsafe fn init_fetch<'w>(world: UnsafeWorldCell<'w>, state: &Self::State, last_run: Tick, this_run: Tick) -> Self::Fetch<'w> {
|
||||||
let ($($filter,)*) = state;
|
let ($($filter,)*) = state;
|
||||||
|
@ -332,15 +440,6 @@ macro_rules! impl_query_filter_tuple {
|
||||||
false $(|| ($filter.matches && $filter::filter_fetch(&mut $filter.fetch, _entity, _table_row)))*
|
false $(|| ($filter.matches && $filter::filter_fetch(&mut $filter.fetch, _entity, _table_row)))*
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
unsafe fn filter_fetch(
|
|
||||||
fetch: &mut Self::Fetch<'_>,
|
|
||||||
entity: Entity,
|
|
||||||
table_row: TableRow
|
|
||||||
) -> bool {
|
|
||||||
Self::fetch(fetch, entity, table_row)
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
let ($($filter,)*) = state;
|
||||||
|
|
||||||
|
@ -376,40 +475,98 @@ macro_rules! impl_query_filter_tuple {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SAFETY: filters are read only
|
impl<$($filter: WorldQueryFilter),*> WorldQueryFilter for Or<($($filter,)*)> {
|
||||||
unsafe impl<$($filter: ReadOnlyWorldQuery),*> ReadOnlyWorldQuery for Or<($($filter,)*)> {}
|
const IS_ARCHETYPAL: bool = true $(&& $filter::IS_ARCHETYPAL)*;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn filter_fetch(
|
||||||
|
fetch: &mut Self::Fetch<'_>,
|
||||||
|
entity: Entity,
|
||||||
|
table_row: TableRow
|
||||||
|
) -> bool {
|
||||||
|
Self::fetch(fetch, entity, table_row)
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_tuple_world_query_filter {
|
||||||
|
($($name: ident),*) => {
|
||||||
|
#[allow(unused_variables)]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
#[allow(clippy::unused_unit)]
|
||||||
|
|
||||||
|
impl<$($name: WorldQueryFilter),*> WorldQueryFilter for ($($name,)*) {
|
||||||
|
const IS_ARCHETYPAL: bool = true $(&& $name::IS_ARCHETYPAL)*;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn filter_fetch(
|
||||||
|
fetch: &mut Self::Fetch<'_>,
|
||||||
|
_entity: Entity,
|
||||||
|
_table_row: TableRow
|
||||||
|
) -> bool {
|
||||||
|
let ($($name,)*) = fetch;
|
||||||
|
true $(&& $name::filter_fetch($name, _entity, _table_row))*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
all_tuples!(impl_tuple_world_query_filter, 0, 15, F);
|
||||||
all_tuples!(impl_query_filter_tuple, 0, 15, F, S);
|
all_tuples!(impl_query_filter_tuple, 0, 15, F, S);
|
||||||
|
|
||||||
macro_rules! impl_tick_filter {
|
/// A filter on a component that only retains results added after the system last ran.
|
||||||
(
|
///
|
||||||
$(#[$meta:meta])*
|
/// A common use for this filter is one-time initialization.
|
||||||
$name: ident,
|
///
|
||||||
$(#[$fetch_meta:meta])*
|
/// To retain all results without filtering but still check whether they were added after the
|
||||||
$fetch_name: ident,
|
/// system last ran, use [`Ref<T>`](crate::change_detection::Ref).
|
||||||
$get_slice: expr,
|
///
|
||||||
$get_sparse_set: expr
|
/// # Deferred
|
||||||
) => {
|
///
|
||||||
$(#[$meta])*
|
/// Note, that entity modifications issued with [`Commands`](crate::system::Commands)
|
||||||
pub struct $name<T>(PhantomData<T>);
|
/// are visible only after deferred operations are applied,
|
||||||
|
/// typically at the end of the schedule iteration.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use bevy_ecs::component::Component;
|
||||||
|
/// # use bevy_ecs::query::Added;
|
||||||
|
/// # use bevy_ecs::system::IntoSystem;
|
||||||
|
/// # use bevy_ecs::system::Query;
|
||||||
|
/// #
|
||||||
|
/// # #[derive(Component, Debug)]
|
||||||
|
/// # struct Name {};
|
||||||
|
///
|
||||||
|
/// fn print_add_name_component(query: Query<&Name, Added<Name>>) {
|
||||||
|
/// for name in &query {
|
||||||
|
/// println!("Named entity created: {:?}", name)
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// # bevy_ecs::system::assert_is_system(print_add_name_component);
|
||||||
|
/// ```
|
||||||
|
pub struct Added<T>(PhantomData<T>);
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
$(#[$fetch_meta])*
|
pub struct AddedFetch<'w> {
|
||||||
pub struct $fetch_name<'w> {
|
|
||||||
table_ticks: Option<ThinSlicePtr<'w, UnsafeCell<Tick>>>,
|
table_ticks: Option<ThinSlicePtr<'w, UnsafeCell<Tick>>>,
|
||||||
sparse_set: Option<&'w ComponentSparseSet>,
|
sparse_set: Option<&'w ComponentSparseSet>,
|
||||||
last_run: Tick,
|
last_run: Tick,
|
||||||
this_run: Tick,
|
this_run: Tick,
|
||||||
}
|
}
|
||||||
|
|
||||||
// SAFETY: `Self::ReadOnly` is the same as `Self`
|
/// SAFETY:
|
||||||
unsafe impl<T: Component> WorldQuery for $name<T> {
|
/// `fetch` accesses a single component in a readonly way.
|
||||||
type Fetch<'w> = $fetch_name<'w>;
|
/// This is sound because `update_component_access` and `update_archetype_component_access` add read access for that component and panic when appropriate.
|
||||||
|
/// `update_component_access` adds a `With` filter for a component.
|
||||||
|
/// This is sound because `matches_component_set` returns whether the set contains that component.
|
||||||
|
unsafe impl<T: Component> WorldQuery for Added<T> {
|
||||||
|
type Fetch<'w> = AddedFetch<'w>;
|
||||||
type Item<'w> = bool;
|
type Item<'w> = bool;
|
||||||
type ReadOnly = Self;
|
|
||||||
type State = ComponentId;
|
type State = ComponentId;
|
||||||
|
|
||||||
fn shrink<'wlong: 'wshort, 'wshort>(item: Self::Item<'wlong>) -> Self::Item<'wshort> {
|
fn shrink<'wlong: 'wshort, 'wshort>(item: Self::Item<'wlong>) -> Self::Item<'wshort> {
|
||||||
|
@ -421,17 +578,12 @@ macro_rules! impl_tick_filter {
|
||||||
world: UnsafeWorldCell<'w>,
|
world: UnsafeWorldCell<'w>,
|
||||||
&id: &ComponentId,
|
&id: &ComponentId,
|
||||||
last_run: Tick,
|
last_run: Tick,
|
||||||
this_run: Tick
|
this_run: Tick,
|
||||||
) -> Self::Fetch<'w> {
|
) -> Self::Fetch<'w> {
|
||||||
Self::Fetch::<'w> {
|
Self::Fetch::<'w> {
|
||||||
table_ticks: None,
|
table_ticks: None,
|
||||||
sparse_set: (T::Storage::STORAGE_TYPE == StorageType::SparseSet)
|
sparse_set: (T::Storage::STORAGE_TYPE == StorageType::SparseSet)
|
||||||
.then(|| {
|
.then(|| world.storages().sparse_sets.get(id).debug_checked_unwrap()),
|
||||||
world.storages()
|
|
||||||
.sparse_sets
|
|
||||||
.get(id)
|
|
||||||
.debug_checked_unwrap()
|
|
||||||
}),
|
|
||||||
last_run,
|
last_run,
|
||||||
this_run,
|
this_run,
|
||||||
}
|
}
|
||||||
|
@ -444,20 +596,15 @@ macro_rules! impl_tick_filter {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const IS_ARCHETYPAL: bool = false;
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn set_table<'w>(
|
unsafe fn set_table<'w>(
|
||||||
fetch: &mut Self::Fetch<'w>,
|
fetch: &mut Self::Fetch<'w>,
|
||||||
&component_id: &ComponentId,
|
&component_id: &ComponentId,
|
||||||
table: &'w Table
|
table: &'w Table,
|
||||||
) {
|
) {
|
||||||
fetch.table_ticks = Some(
|
fetch.table_ticks = Some(
|
||||||
$get_slice(
|
Column::get_added_ticks_slice(table.get_column(component_id).debug_checked_unwrap())
|
||||||
&table
|
.into(),
|
||||||
.get_column(component_id)
|
|
||||||
.debug_checked_unwrap()
|
|
||||||
).into(),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -466,7 +613,7 @@ macro_rules! impl_tick_filter {
|
||||||
fetch: &mut Self::Fetch<'w>,
|
fetch: &mut Self::Fetch<'w>,
|
||||||
component_id: &ComponentId,
|
component_id: &ComponentId,
|
||||||
_archetype: &'w Archetype,
|
_archetype: &'w Archetype,
|
||||||
table: &'w Table
|
table: &'w Table,
|
||||||
) {
|
) {
|
||||||
if Self::IS_DENSE {
|
if Self::IS_DENSE {
|
||||||
Self::set_table(fetch, component_id, table);
|
Self::set_table(fetch, component_id, table);
|
||||||
|
@ -477,22 +624,18 @@ macro_rules! impl_tick_filter {
|
||||||
unsafe fn fetch<'w>(
|
unsafe fn fetch<'w>(
|
||||||
fetch: &mut Self::Fetch<'w>,
|
fetch: &mut Self::Fetch<'w>,
|
||||||
entity: Entity,
|
entity: Entity,
|
||||||
table_row: TableRow
|
table_row: TableRow,
|
||||||
) -> Self::Item<'w> {
|
) -> Self::Item<'w> {
|
||||||
match T::Storage::STORAGE_TYPE {
|
match T::Storage::STORAGE_TYPE {
|
||||||
StorageType::Table => {
|
StorageType::Table => fetch
|
||||||
fetch
|
|
||||||
.table_ticks
|
.table_ticks
|
||||||
.debug_checked_unwrap()
|
.debug_checked_unwrap()
|
||||||
.get(table_row.index())
|
.get(table_row.index())
|
||||||
.deref()
|
.deref()
|
||||||
.is_newer_than(fetch.last_run, fetch.this_run)
|
.is_newer_than(fetch.last_run, fetch.this_run),
|
||||||
}
|
|
||||||
StorageType::SparseSet => {
|
StorageType::SparseSet => {
|
||||||
let sparse_set = &fetch
|
let sparse_set = &fetch.sparse_set.debug_checked_unwrap();
|
||||||
.sparse_set
|
ComponentSparseSet::get_added_tick(sparse_set, entity)
|
||||||
.debug_checked_unwrap();
|
|
||||||
$get_sparse_set(sparse_set, entity)
|
|
||||||
.debug_checked_unwrap()
|
.debug_checked_unwrap()
|
||||||
.deref()
|
.deref()
|
||||||
.is_newer_than(fetch.last_run, fetch.this_run)
|
.is_newer_than(fetch.last_run, fetch.this_run)
|
||||||
|
@ -500,20 +643,10 @@ macro_rules! impl_tick_filter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
unsafe fn filter_fetch(
|
|
||||||
fetch: &mut Self::Fetch<'_>,
|
|
||||||
entity: Entity,
|
|
||||||
table_row: TableRow
|
|
||||||
) -> bool {
|
|
||||||
Self::fetch(fetch, entity, table_row)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn update_component_access(&id: &ComponentId, access: &mut FilteredAccess<ComponentId>) {
|
fn update_component_access(&id: &ComponentId, access: &mut FilteredAccess<ComponentId>) {
|
||||||
if access.access().has_write(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(id);
|
access.add_read(id);
|
||||||
}
|
}
|
||||||
|
@ -533,116 +666,219 @@ macro_rules! impl_tick_filter {
|
||||||
world.init_component::<T>()
|
world.init_component::<T>()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn matches_component_set(&id: &ComponentId, set_contains_id: &impl Fn(ComponentId) -> bool) -> bool {
|
fn matches_component_set(
|
||||||
|
&id: &ComponentId,
|
||||||
|
set_contains_id: &impl Fn(ComponentId) -> bool,
|
||||||
|
) -> bool {
|
||||||
set_contains_id(id)
|
set_contains_id(id)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// SAFETY: read-only access
|
|
||||||
unsafe impl<T: Component> ReadOnlyWorldQuery for $name<T> {}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_tick_filter!(
|
impl<T: Component> WorldQueryFilter for Added<T> {
|
||||||
/// A filter on a component that only retains results added after the system last ran.
|
const IS_ARCHETYPAL: bool = false;
|
||||||
///
|
#[inline(always)]
|
||||||
/// A common use for this filter is one-time initialization.
|
unsafe fn filter_fetch(
|
||||||
///
|
fetch: &mut Self::Fetch<'_>,
|
||||||
/// To retain all results without filtering but still check whether they were added after the
|
entity: Entity,
|
||||||
/// system last ran, use [`Ref<T>`](crate::change_detection::Ref).
|
table_row: TableRow,
|
||||||
///
|
) -> bool {
|
||||||
/// # Deferred
|
Self::fetch(fetch, entity, table_row)
|
||||||
///
|
}
|
||||||
/// Note, that entity modifications issued with [`Commands`](crate::system::Commands)
|
}
|
||||||
/// are visible only after deferred operations are applied,
|
|
||||||
/// typically at the end of the schedule iteration.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// # use bevy_ecs::component::Component;
|
|
||||||
/// # use bevy_ecs::query::Added;
|
|
||||||
/// # use bevy_ecs::system::IntoSystem;
|
|
||||||
/// # use bevy_ecs::system::Query;
|
|
||||||
/// #
|
|
||||||
/// # #[derive(Component, Debug)]
|
|
||||||
/// # struct Name {};
|
|
||||||
///
|
|
||||||
/// fn print_add_name_component(query: Query<&Name, Added<Name>>) {
|
|
||||||
/// for name in &query {
|
|
||||||
/// println!("Named entity created: {:?}", name)
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
///
|
|
||||||
/// # bevy_ecs::system::assert_is_system(print_add_name_component);
|
|
||||||
/// ```
|
|
||||||
Added,
|
|
||||||
AddedFetch,
|
|
||||||
Column::get_added_ticks_slice,
|
|
||||||
ComponentSparseSet::get_added_tick
|
|
||||||
);
|
|
||||||
|
|
||||||
impl_tick_filter!(
|
/// A filter on a component that only retains results added or mutably dereferenced after the system last ran.
|
||||||
/// A filter on a component that only retains results added or mutably dereferenced after the system last ran.
|
///
|
||||||
///
|
/// A common use for this filter is avoiding redundant work when values have not changed.
|
||||||
/// A common use for this filter is avoiding redundant work when values have not changed.
|
///
|
||||||
///
|
/// **Note** that simply *mutably dereferencing* a component is considered a change ([`DerefMut`](std::ops::DerefMut)).
|
||||||
/// **Note** that simply *mutably dereferencing* a component is considered a change ([`DerefMut`](std::ops::DerefMut)).
|
/// Bevy does not compare components to their previous values.
|
||||||
/// Bevy does not compare components to their previous values.
|
///
|
||||||
///
|
/// To retain all results without filtering but still check whether they were changed after the
|
||||||
/// To retain all results without filtering but still check whether they were changed after the
|
/// system last ran, use [`Ref<T>`](crate::change_detection::Ref).
|
||||||
/// system last ran, use [`Ref<T>`](crate::change_detection::Ref).
|
///
|
||||||
///
|
/// # Deferred
|
||||||
/// # Deferred
|
///
|
||||||
///
|
/// Note, that entity modifications issued with [`Commands`](crate::system::Commands)
|
||||||
/// Note, that entity modifications issued with [`Commands`](crate::system::Commands)
|
/// (like entity creation or entity component addition or removal)
|
||||||
/// (like entity creation or entity component addition or removal)
|
/// are visible only after deferred operations are applied,
|
||||||
/// are visible only after deferred operations are applied,
|
/// typically at the end of the schedule iteration.
|
||||||
/// typically at the end of the schedule iteration.
|
///
|
||||||
///
|
/// # Examples
|
||||||
/// # Examples
|
///
|
||||||
///
|
/// ```
|
||||||
/// ```
|
/// # use bevy_ecs::component::Component;
|
||||||
/// # use bevy_ecs::component::Component;
|
/// # use bevy_ecs::query::Changed;
|
||||||
/// # use bevy_ecs::query::Changed;
|
/// # use bevy_ecs::system::IntoSystem;
|
||||||
/// # use bevy_ecs::system::IntoSystem;
|
/// # use bevy_ecs::system::Query;
|
||||||
/// # use bevy_ecs::system::Query;
|
/// #
|
||||||
/// #
|
/// # #[derive(Component, Debug)]
|
||||||
/// # #[derive(Component, Debug)]
|
/// # struct Name {};
|
||||||
/// # struct Name {};
|
/// # #[derive(Component)]
|
||||||
/// # #[derive(Component)]
|
/// # struct Transform {};
|
||||||
/// # struct Transform {};
|
///
|
||||||
///
|
/// fn print_moving_objects_system(query: Query<&Name, Changed<Transform>>) {
|
||||||
/// fn print_moving_objects_system(query: Query<&Name, Changed<Transform>>) {
|
/// for name in &query {
|
||||||
/// for name in &query {
|
/// println!("Entity Moved: {:?}", name);
|
||||||
/// println!("Entity Moved: {:?}", name);
|
/// }
|
||||||
/// }
|
/// }
|
||||||
/// }
|
///
|
||||||
///
|
/// # bevy_ecs::system::assert_is_system(print_moving_objects_system);
|
||||||
/// # bevy_ecs::system::assert_is_system(print_moving_objects_system);
|
/// ```
|
||||||
/// ```
|
pub struct Changed<T>(PhantomData<T>);
|
||||||
Changed,
|
|
||||||
ChangedFetch,
|
#[doc(hidden)]
|
||||||
Column::get_changed_ticks_slice,
|
#[derive(Clone)]
|
||||||
ComponentSparseSet::get_changed_tick
|
pub struct ChangedFetch<'w> {
|
||||||
);
|
table_ticks: Option<ThinSlicePtr<'w, UnsafeCell<Tick>>>,
|
||||||
|
sparse_set: Option<&'w ComponentSparseSet>,
|
||||||
|
last_run: Tick,
|
||||||
|
this_run: Tick,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// SAFETY:
|
||||||
|
/// `fetch` accesses a single component in a readonly way.
|
||||||
|
/// This is sound because `update_component_access` and `update_archetype_component_access` add read access for that component and panic when appropriate.
|
||||||
|
/// `update_component_access` adds a `With` filter for a component.
|
||||||
|
/// This is sound because `matches_component_set` returns whether the set contains that component.
|
||||||
|
unsafe impl<T: Component> WorldQuery for Changed<T> {
|
||||||
|
type Fetch<'w> = ChangedFetch<'w>;
|
||||||
|
type Item<'w> = bool;
|
||||||
|
type State = ComponentId;
|
||||||
|
|
||||||
|
fn shrink<'wlong: 'wshort, 'wshort>(item: Self::Item<'wlong>) -> Self::Item<'wshort> {
|
||||||
|
item
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn init_fetch<'w>(
|
||||||
|
world: UnsafeWorldCell<'w>,
|
||||||
|
&id: &ComponentId,
|
||||||
|
last_run: Tick,
|
||||||
|
this_run: Tick,
|
||||||
|
) -> Self::Fetch<'w> {
|
||||||
|
Self::Fetch::<'w> {
|
||||||
|
table_ticks: None,
|
||||||
|
sparse_set: (T::Storage::STORAGE_TYPE == StorageType::SparseSet)
|
||||||
|
.then(|| world.storages().sparse_sets.get(id).debug_checked_unwrap()),
|
||||||
|
last_run,
|
||||||
|
this_run,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const IS_DENSE: bool = {
|
||||||
|
match T::Storage::STORAGE_TYPE {
|
||||||
|
StorageType::Table => true,
|
||||||
|
StorageType::SparseSet => false,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn set_table<'w>(
|
||||||
|
fetch: &mut Self::Fetch<'w>,
|
||||||
|
&component_id: &ComponentId,
|
||||||
|
table: &'w Table,
|
||||||
|
) {
|
||||||
|
fetch.table_ticks = Some(
|
||||||
|
Column::get_changed_ticks_slice(table.get_column(component_id).debug_checked_unwrap())
|
||||||
|
.into(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn set_archetype<'w>(
|
||||||
|
fetch: &mut Self::Fetch<'w>,
|
||||||
|
component_id: &ComponentId,
|
||||||
|
_archetype: &'w Archetype,
|
||||||
|
table: &'w Table,
|
||||||
|
) {
|
||||||
|
if Self::IS_DENSE {
|
||||||
|
Self::set_table(fetch, component_id, table);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn fetch<'w>(
|
||||||
|
fetch: &mut Self::Fetch<'w>,
|
||||||
|
entity: Entity,
|
||||||
|
table_row: TableRow,
|
||||||
|
) -> Self::Item<'w> {
|
||||||
|
match T::Storage::STORAGE_TYPE {
|
||||||
|
StorageType::Table => fetch
|
||||||
|
.table_ticks
|
||||||
|
.debug_checked_unwrap()
|
||||||
|
.get(table_row.index())
|
||||||
|
.deref()
|
||||||
|
.is_newer_than(fetch.last_run, fetch.this_run),
|
||||||
|
StorageType::SparseSet => {
|
||||||
|
let sparse_set = &fetch.sparse_set.debug_checked_unwrap();
|
||||||
|
ComponentSparseSet::get_changed_tick(sparse_set, entity)
|
||||||
|
.debug_checked_unwrap()
|
||||||
|
.deref()
|
||||||
|
.is_newer_than(fetch.last_run, fetch.this_run)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn update_component_access(&id: &ComponentId, access: &mut FilteredAccess<ComponentId>) {
|
||||||
|
if access.access().has_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(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn update_archetype_component_access(
|
||||||
|
&id: &ComponentId,
|
||||||
|
archetype: &Archetype,
|
||||||
|
access: &mut Access<ArchetypeComponentId>,
|
||||||
|
) {
|
||||||
|
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<T: Component> WorldQueryFilter for Changed<T> {
|
||||||
|
const IS_ARCHETYPAL: bool = false;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn filter_fetch(
|
||||||
|
fetch: &mut Self::Fetch<'_>,
|
||||||
|
entity: Entity,
|
||||||
|
table_row: TableRow,
|
||||||
|
) -> bool {
|
||||||
|
Self::fetch(fetch, entity, table_row)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A marker trait to indicate that the filter works at an archetype level.
|
/// A marker trait to indicate that the filter works at an archetype level.
|
||||||
///
|
///
|
||||||
/// This is needed to implement [`ExactSizeIterator`] for
|
/// This is needed to implement [`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 [`WorldQuery::IS_ARCHETYPAL`]
|
/// The trait must only be implemented for filters where its corresponding [`WorldQueryFilter::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.
|
||||||
///
|
///
|
||||||
/// [`Added`] and [`Changed`] works with entities, and therefore are not archetypal. As such
|
/// [`Added`] and [`Changed`] works with entities, and therefore are not archetypal. As such
|
||||||
/// they do not implement [`ArchetypeFilter`].
|
/// they do not implement [`ArchetypeFilter`].
|
||||||
pub trait ArchetypeFilter {}
|
pub trait ArchetypeFilter: WorldQueryFilter {}
|
||||||
|
|
||||||
impl<T> ArchetypeFilter for With<T> {}
|
impl<T: Component> ArchetypeFilter for With<T> {}
|
||||||
impl<T> ArchetypeFilter for Without<T> {}
|
impl<T: Component> ArchetypeFilter for Without<T> {}
|
||||||
|
|
||||||
macro_rules! impl_archetype_filter_tuple {
|
macro_rules! impl_archetype_filter_tuple {
|
||||||
($($filter: ident),*) => {
|
($($filter: ident),*) => {
|
||||||
|
|
|
@ -2,26 +2,26 @@ use crate::{
|
||||||
archetype::{ArchetypeEntity, ArchetypeId, Archetypes},
|
archetype::{ArchetypeEntity, ArchetypeId, Archetypes},
|
||||||
component::Tick,
|
component::Tick,
|
||||||
entity::{Entities, Entity},
|
entity::{Entities, Entity},
|
||||||
query::{ArchetypeFilter, DebugCheckedUnwrap, QueryState, WorldQuery},
|
query::{ArchetypeFilter, DebugCheckedUnwrap, QueryState},
|
||||||
storage::{TableId, TableRow, Tables},
|
storage::{TableId, TableRow, Tables},
|
||||||
world::unsafe_world_cell::UnsafeWorldCell,
|
world::unsafe_world_cell::UnsafeWorldCell,
|
||||||
};
|
};
|
||||||
use std::{borrow::Borrow, iter::FusedIterator, mem::MaybeUninit};
|
use std::{borrow::Borrow, iter::FusedIterator, mem::MaybeUninit};
|
||||||
|
|
||||||
use super::ReadOnlyWorldQuery;
|
use super::{ReadOnlyWorldQueryData, WorldQueryData, WorldQueryFilter};
|
||||||
|
|
||||||
/// An [`Iterator`] over query results of a [`Query`](crate::system::Query).
|
/// An [`Iterator`] over query results of a [`Query`](crate::system::Query).
|
||||||
///
|
///
|
||||||
/// This struct is created by the [`Query::iter`](crate::system::Query::iter) and
|
/// This struct is created by the [`Query::iter`](crate::system::Query::iter) and
|
||||||
/// [`Query::iter_mut`](crate::system::Query::iter_mut) methods.
|
/// [`Query::iter_mut`](crate::system::Query::iter_mut) methods.
|
||||||
pub struct QueryIter<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> {
|
pub struct QueryIter<'w, 's, Q: WorldQueryData, F: WorldQueryFilter> {
|
||||||
tables: &'w Tables,
|
tables: &'w Tables,
|
||||||
archetypes: &'w Archetypes,
|
archetypes: &'w Archetypes,
|
||||||
query_state: &'s QueryState<Q, F>,
|
query_state: &'s QueryState<Q, F>,
|
||||||
cursor: QueryIterationCursor<'w, 's, Q, F>,
|
cursor: QueryIterationCursor<'w, 's, Q, F>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> QueryIter<'w, 's, Q, F> {
|
impl<'w, 's, Q: WorldQueryData, F: WorldQueryFilter> QueryIter<'w, 's, Q, F> {
|
||||||
/// # Safety
|
/// # Safety
|
||||||
/// - `world` must have permission to access any of the components registered in `query_state`.
|
/// - `world` must have permission to access any of the components registered in `query_state`.
|
||||||
/// - `world` must be the same one used to initialize `query_state`.
|
/// - `world` must be the same one used to initialize `query_state`.
|
||||||
|
@ -41,7 +41,7 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> QueryIter<'w, 's, Q, F> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Iterator for QueryIter<'w, 's, Q, F> {
|
impl<'w, 's, Q: WorldQueryData, F: WorldQueryFilter> Iterator for QueryIter<'w, 's, Q, F> {
|
||||||
type Item = Q::Item<'w>;
|
type Item = Q::Item<'w>;
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -57,14 +57,14 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Iterator for QueryIter<'w, 's
|
||||||
|
|
||||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
let max_size = self.cursor.max_remaining(self.tables, self.archetypes);
|
let max_size = self.cursor.max_remaining(self.tables, self.archetypes);
|
||||||
let archetype_query = Q::IS_ARCHETYPAL && F::IS_ARCHETYPAL;
|
let archetype_query = 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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is correct as [`QueryIter`] always returns `None` once exhausted.
|
// This is correct as [`QueryIter`] always returns `None` once exhausted.
|
||||||
impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> FusedIterator for QueryIter<'w, 's, Q, F> {}
|
impl<'w, 's, Q: WorldQueryData, F: WorldQueryFilter> FusedIterator for QueryIter<'w, 's, Q, F> {}
|
||||||
|
|
||||||
/// An [`Iterator`] over the query items generated from an iterator of [`Entity`]s.
|
/// An [`Iterator`] over the query items generated from an iterator of [`Entity`]s.
|
||||||
///
|
///
|
||||||
|
@ -72,7 +72,7 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> FusedIterator for QueryIter<'
|
||||||
/// Entities that don't match the query are skipped.
|
/// Entities that don't match the query are skipped.
|
||||||
///
|
///
|
||||||
/// This struct is created by the [`Query::iter_many`](crate::system::Query::iter_many) and [`Query::iter_many_mut`](crate::system::Query::iter_many_mut) methods.
|
/// This struct is created by the [`Query::iter_many`](crate::system::Query::iter_many) and [`Query::iter_many_mut`](crate::system::Query::iter_many_mut) methods.
|
||||||
pub struct QueryManyIter<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery, I: Iterator>
|
pub struct QueryManyIter<'w, 's, Q: WorldQueryData, F: WorldQueryFilter, I: Iterator>
|
||||||
where
|
where
|
||||||
I::Item: Borrow<Entity>,
|
I::Item: Borrow<Entity>,
|
||||||
{
|
{
|
||||||
|
@ -85,7 +85,7 @@ where
|
||||||
query_state: &'s QueryState<Q, F>,
|
query_state: &'s QueryState<Q, F>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery, I: Iterator> QueryManyIter<'w, 's, Q, F, I>
|
impl<'w, 's, Q: WorldQueryData, F: WorldQueryFilter, I: Iterator> QueryManyIter<'w, 's, Q, F, I>
|
||||||
where
|
where
|
||||||
I::Item: Borrow<Entity>,
|
I::Item: Borrow<Entity>,
|
||||||
{
|
{
|
||||||
|
@ -182,7 +182,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'w, 's, Q: ReadOnlyWorldQuery, F: ReadOnlyWorldQuery, I: Iterator> Iterator
|
impl<'w, 's, Q: ReadOnlyWorldQueryData, F: WorldQueryFilter, I: Iterator> Iterator
|
||||||
for QueryManyIter<'w, 's, Q, F, I>
|
for QueryManyIter<'w, 's, Q, F, I>
|
||||||
where
|
where
|
||||||
I::Item: Borrow<Entity>,
|
I::Item: Borrow<Entity>,
|
||||||
|
@ -202,7 +202,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is correct as [`QueryManyIter`] always returns `None` once exhausted.
|
// This is correct as [`QueryManyIter`] always returns `None` once exhausted.
|
||||||
impl<'w, 's, Q: ReadOnlyWorldQuery, F: ReadOnlyWorldQuery, I: Iterator> FusedIterator
|
impl<'w, 's, Q: ReadOnlyWorldQueryData, F: WorldQueryFilter, I: Iterator> FusedIterator
|
||||||
for QueryManyIter<'w, 's, Q, F, I>
|
for QueryManyIter<'w, 's, Q, F, I>
|
||||||
where
|
where
|
||||||
I::Item: Borrow<Entity>,
|
I::Item: Borrow<Entity>,
|
||||||
|
@ -272,14 +272,14 @@ where
|
||||||
/// [`Query`]: crate::system::Query
|
/// [`Query`]: crate::system::Query
|
||||||
/// [`Query::iter_combinations`]: crate::system::Query::iter_combinations
|
/// [`Query::iter_combinations`]: crate::system::Query::iter_combinations
|
||||||
/// [`Query::iter_combinations_mut`]: crate::system::Query::iter_combinations_mut
|
/// [`Query::iter_combinations_mut`]: crate::system::Query::iter_combinations_mut
|
||||||
pub struct QueryCombinationIter<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery, const K: usize> {
|
pub struct QueryCombinationIter<'w, 's, Q: WorldQueryData, F: WorldQueryFilter, const K: usize> {
|
||||||
tables: &'w Tables,
|
tables: &'w Tables,
|
||||||
archetypes: &'w Archetypes,
|
archetypes: &'w Archetypes,
|
||||||
query_state: &'s QueryState<Q, F>,
|
query_state: &'s QueryState<Q, F>,
|
||||||
cursors: [QueryIterationCursor<'w, 's, Q, F>; K],
|
cursors: [QueryIterationCursor<'w, 's, Q, F>; K],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery, const K: usize>
|
impl<'w, 's, Q: WorldQueryData, F: WorldQueryFilter, const K: usize>
|
||||||
QueryCombinationIter<'w, 's, Q, F, K>
|
QueryCombinationIter<'w, 's, Q, F, K>
|
||||||
{
|
{
|
||||||
/// # Safety
|
/// # Safety
|
||||||
|
@ -386,7 +386,7 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery, const K: usize>
|
||||||
// Iterator type is intentionally implemented only for read-only access.
|
// Iterator type is intentionally implemented only for read-only access.
|
||||||
// Doing so for mutable references would be unsound, because calling `next`
|
// Doing so for mutable references would be unsound, because calling `next`
|
||||||
// multiple times would allow multiple owned references to the same data to exist.
|
// multiple times would allow multiple owned references to the same data to exist.
|
||||||
impl<'w, 's, Q: ReadOnlyWorldQuery, F: ReadOnlyWorldQuery, const K: usize> Iterator
|
impl<'w, 's, Q: ReadOnlyWorldQueryData, F: WorldQueryFilter, const K: usize> Iterator
|
||||||
for QueryCombinationIter<'w, 's, Q, F, K>
|
for QueryCombinationIter<'w, 's, Q, F, K>
|
||||||
{
|
{
|
||||||
type Item = [Q::Item<'w>; K];
|
type Item = [Q::Item<'w>; K];
|
||||||
|
@ -422,14 +422,14 @@ impl<'w, 's, Q: ReadOnlyWorldQuery, F: ReadOnlyWorldQuery, const K: usize> Itera
|
||||||
Some(acc + choose(n, K - i)?)
|
Some(acc + choose(n, K - i)?)
|
||||||
});
|
});
|
||||||
|
|
||||||
let archetype_query = F::IS_ARCHETYPAL && Q::IS_ARCHETYPAL;
|
let archetype_query = F::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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> ExactSizeIterator for QueryIter<'w, 's, Q, F>
|
impl<'w, 's, Q: WorldQueryData, F: WorldQueryFilter> ExactSizeIterator for QueryIter<'w, 's, Q, F>
|
||||||
where
|
where
|
||||||
F: ArchetypeFilter,
|
F: ArchetypeFilter,
|
||||||
{
|
{
|
||||||
|
@ -439,12 +439,12 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is correct as [`QueryCombinationIter`] always returns `None` once exhausted.
|
// This is correct as [`QueryCombinationIter`] always returns `None` once exhausted.
|
||||||
impl<'w, 's, Q: ReadOnlyWorldQuery, F: ReadOnlyWorldQuery, const K: usize> FusedIterator
|
impl<'w, 's, Q: ReadOnlyWorldQueryData, F: WorldQueryFilter, const K: usize> FusedIterator
|
||||||
for QueryCombinationIter<'w, 's, Q, F, K>
|
for QueryCombinationIter<'w, 's, Q, F, K>
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
struct QueryIterationCursor<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> {
|
struct QueryIterationCursor<'w, 's, Q: WorldQueryData, F: WorldQueryFilter> {
|
||||||
table_id_iter: std::slice::Iter<'s, TableId>,
|
table_id_iter: std::slice::Iter<'s, TableId>,
|
||||||
archetype_id_iter: std::slice::Iter<'s, ArchetypeId>,
|
archetype_id_iter: std::slice::Iter<'s, ArchetypeId>,
|
||||||
table_entities: &'w [Entity],
|
table_entities: &'w [Entity],
|
||||||
|
@ -457,7 +457,7 @@ struct QueryIterationCursor<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> {
|
||||||
current_row: usize,
|
current_row: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Q: WorldQuery, F: ReadOnlyWorldQuery> Clone for QueryIterationCursor<'_, '_, Q, F> {
|
impl<Q: WorldQueryData, F: WorldQueryFilter> Clone for QueryIterationCursor<'_, '_, Q, F> {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
table_id_iter: self.table_id_iter.clone(),
|
table_id_iter: self.table_id_iter.clone(),
|
||||||
|
@ -472,7 +472,7 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> Clone for QueryIterationCursor<'_, '_
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> QueryIterationCursor<'w, 's, Q, F> {
|
impl<'w, 's, Q: WorldQueryData, F: WorldQueryFilter> QueryIterationCursor<'w, 's, Q, F> {
|
||||||
const IS_DENSE: bool = Q::IS_DENSE && F::IS_DENSE;
|
const IS_DENSE: bool = Q::IS_DENSE && F::IS_DENSE;
|
||||||
|
|
||||||
unsafe fn init_empty(
|
unsafe fn init_empty(
|
||||||
|
|
|
@ -7,14 +7,17 @@ mod filter;
|
||||||
mod iter;
|
mod iter;
|
||||||
mod par_iter;
|
mod par_iter;
|
||||||
mod state;
|
mod state;
|
||||||
|
mod world_query;
|
||||||
|
|
||||||
pub use access::*;
|
pub use access::*;
|
||||||
|
pub use bevy_ecs_macros::{WorldQueryData, WorldQueryFilter};
|
||||||
pub use error::*;
|
pub use error::*;
|
||||||
pub use fetch::*;
|
pub use fetch::*;
|
||||||
pub use filter::*;
|
pub use filter::*;
|
||||||
pub use iter::*;
|
pub use iter::*;
|
||||||
pub use par_iter::*;
|
pub use par_iter::*;
|
||||||
pub use state::*;
|
pub use state::*;
|
||||||
|
pub use world_query::*;
|
||||||
|
|
||||||
/// A debug checked version of [`Option::unwrap_unchecked`]. Will panic in
|
/// A debug checked version of [`Option::unwrap_unchecked`]. Will panic in
|
||||||
/// debug modes if unwrapping a `None` or `Err` value in debug mode, but is
|
/// debug modes if unwrapping a `None` or `Err` value in debug mode, but is
|
||||||
|
@ -64,9 +67,10 @@ impl<T> DebugCheckedUnwrap for Option<T> {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::{ReadOnlyWorldQuery, WorldQuery};
|
use bevy_ecs_macros::{WorldQueryData, WorldQueryFilter};
|
||||||
|
|
||||||
use crate::prelude::{AnyOf, Changed, Entity, Or, QueryState, With, Without};
|
use crate::prelude::{AnyOf, Changed, Entity, Or, QueryState, With, Without};
|
||||||
use crate::query::{ArchetypeFilter, Has, QueryCombinationIter};
|
use crate::query::{ArchetypeFilter, Has, QueryCombinationIter, ReadOnlyWorldQueryData};
|
||||||
use crate::schedule::{IntoSystemConfigs, Schedule};
|
use crate::schedule::{IntoSystemConfigs, Schedule};
|
||||||
use crate::system::{IntoSystem, Query, System, SystemState};
|
use crate::system::{IntoSystem, Query, System, SystemState};
|
||||||
use crate::{self as bevy_ecs, component::Component, world::World};
|
use crate::{self as bevy_ecs, component::Component, world::World};
|
||||||
|
@ -113,9 +117,8 @@ mod tests {
|
||||||
}
|
}
|
||||||
fn assert_combination<Q, F, const K: usize>(world: &mut World, expected_size: usize)
|
fn assert_combination<Q, F, const K: usize>(world: &mut World, expected_size: usize)
|
||||||
where
|
where
|
||||||
Q: ReadOnlyWorldQuery,
|
Q: ReadOnlyWorldQueryData,
|
||||||
F: ReadOnlyWorldQuery,
|
F: ArchetypeFilter,
|
||||||
F::ReadOnly: ArchetypeFilter,
|
|
||||||
{
|
{
|
||||||
let mut query = world.query_filtered::<Q, F>();
|
let mut query = world.query_filtered::<Q, F>();
|
||||||
let query_type = type_name::<QueryCombinationIter<Q, F, K>>();
|
let query_type = type_name::<QueryCombinationIter<Q, F, K>>();
|
||||||
|
@ -128,9 +131,8 @@ mod tests {
|
||||||
}
|
}
|
||||||
fn assert_all_sizes_equal<Q, F>(world: &mut World, expected_size: usize)
|
fn assert_all_sizes_equal<Q, F>(world: &mut World, expected_size: usize)
|
||||||
where
|
where
|
||||||
Q: ReadOnlyWorldQuery,
|
Q: ReadOnlyWorldQueryData,
|
||||||
F: ReadOnlyWorldQuery,
|
F: ArchetypeFilter,
|
||||||
F::ReadOnly: ArchetypeFilter,
|
|
||||||
{
|
{
|
||||||
let mut query = world.query_filtered::<Q, F>();
|
let mut query = world.query_filtered::<Q, F>();
|
||||||
let query_type = type_name::<QueryState<Q, F>>();
|
let query_type = type_name::<QueryState<Q, F>>();
|
||||||
|
@ -499,8 +501,8 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic = "&mut bevy_ecs::query::tests::A conflicts with a previous access in this query."]
|
#[should_panic = "&mut bevy_ecs::query::tests::A conflicts with a previous access in this query."]
|
||||||
fn self_conflicting_worldquery() {
|
fn self_conflicting_worldquery() {
|
||||||
#[derive(WorldQuery)]
|
#[derive(WorldQueryData)]
|
||||||
#[world_query(mutable)]
|
#[world_query_data(mutable)]
|
||||||
struct SelfConflicting {
|
struct SelfConflicting {
|
||||||
a: &'static mut A,
|
a: &'static mut A,
|
||||||
b: &'static mut A,
|
b: &'static mut A,
|
||||||
|
@ -536,7 +538,7 @@ mod tests {
|
||||||
world.spawn_empty();
|
world.spawn_empty();
|
||||||
|
|
||||||
{
|
{
|
||||||
#[derive(WorldQuery)]
|
#[derive(WorldQueryData)]
|
||||||
struct CustomAB {
|
struct CustomAB {
|
||||||
a: &'static A,
|
a: &'static A,
|
||||||
b: &'static B,
|
b: &'static B,
|
||||||
|
@ -556,7 +558,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
#[derive(WorldQuery)]
|
#[derive(WorldQueryData)]
|
||||||
struct FancyParam {
|
struct FancyParam {
|
||||||
e: Entity,
|
e: Entity,
|
||||||
b: &'static B,
|
b: &'static B,
|
||||||
|
@ -577,11 +579,11 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
#[derive(WorldQuery)]
|
#[derive(WorldQueryData)]
|
||||||
struct MaybeBSparse {
|
struct MaybeBSparse {
|
||||||
blah: Option<(&'static B, &'static Sparse)>,
|
blah: Option<(&'static B, &'static Sparse)>,
|
||||||
}
|
}
|
||||||
#[derive(WorldQuery)]
|
#[derive(WorldQueryData)]
|
||||||
struct MatchEverything {
|
struct MatchEverything {
|
||||||
abcs: AnyOf<(&'static A, &'static B, &'static C)>,
|
abcs: AnyOf<(&'static A, &'static B, &'static C)>,
|
||||||
opt_bsparse: MaybeBSparse,
|
opt_bsparse: MaybeBSparse,
|
||||||
|
@ -616,11 +618,11 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
#[derive(WorldQuery)]
|
#[derive(WorldQueryFilter)]
|
||||||
struct AOrBFilter {
|
struct AOrBFilter {
|
||||||
a: Or<(With<A>, With<B>)>,
|
a: Or<(With<A>, With<B>)>,
|
||||||
}
|
}
|
||||||
#[derive(WorldQuery)]
|
#[derive(WorldQueryFilter)]
|
||||||
struct NoSparseThatsSlow {
|
struct NoSparseThatsSlow {
|
||||||
no: Without<Sparse>,
|
no: Without<Sparse>,
|
||||||
}
|
}
|
||||||
|
@ -637,7 +639,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
#[derive(WorldQuery)]
|
#[derive(WorldQueryFilter)]
|
||||||
struct CSparseFilter {
|
struct CSparseFilter {
|
||||||
tuple_structs_pls: With<C>,
|
tuple_structs_pls: With<C>,
|
||||||
ugh: With<Sparse>,
|
ugh: With<Sparse>,
|
||||||
|
@ -655,7 +657,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
#[derive(WorldQuery)]
|
#[derive(WorldQueryFilter)]
|
||||||
struct WithoutComps {
|
struct WithoutComps {
|
||||||
_1: Without<A>,
|
_1: Without<A>,
|
||||||
_2: Without<B>,
|
_2: Without<B>,
|
||||||
|
@ -674,7 +676,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
#[derive(WorldQuery)]
|
#[derive(WorldQueryData)]
|
||||||
struct IterCombAB {
|
struct IterCombAB {
|
||||||
a: &'static A,
|
a: &'static A,
|
||||||
b: &'static B,
|
b: &'static B,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::{component::Tick, world::unsafe_world_cell::UnsafeWorldCell};
|
use crate::{component::Tick, world::unsafe_world_cell::UnsafeWorldCell};
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
||||||
use super::{QueryItem, QueryState, ReadOnlyWorldQuery, WorldQuery};
|
use super::{QueryItem, QueryState, WorldQueryData, WorldQueryFilter};
|
||||||
|
|
||||||
/// Dictates how a parallel query chunks up large tables/archetypes
|
/// Dictates how a parallel query chunks up large tables/archetypes
|
||||||
/// during iteration.
|
/// during iteration.
|
||||||
|
@ -82,7 +82,7 @@ impl BatchingStrategy {
|
||||||
///
|
///
|
||||||
/// This struct is created by the [`Query::par_iter`](crate::system::Query::par_iter) and
|
/// This struct is created by the [`Query::par_iter`](crate::system::Query::par_iter) and
|
||||||
/// [`Query::par_iter_mut`](crate::system::Query::par_iter_mut) methods.
|
/// [`Query::par_iter_mut`](crate::system::Query::par_iter_mut) methods.
|
||||||
pub struct QueryParIter<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> {
|
pub struct QueryParIter<'w, 's, Q: WorldQueryData, F: WorldQueryFilter> {
|
||||||
pub(crate) world: UnsafeWorldCell<'w>,
|
pub(crate) world: UnsafeWorldCell<'w>,
|
||||||
pub(crate) state: &'s QueryState<Q, F>,
|
pub(crate) state: &'s QueryState<Q, F>,
|
||||||
pub(crate) last_run: Tick,
|
pub(crate) last_run: Tick,
|
||||||
|
@ -90,7 +90,7 @@ pub struct QueryParIter<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> {
|
||||||
pub(crate) batching_strategy: BatchingStrategy,
|
pub(crate) batching_strategy: BatchingStrategy,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> QueryParIter<'w, 's, Q, F> {
|
impl<'w, 's, Q: WorldQueryData, F: WorldQueryFilter> QueryParIter<'w, 's, Q, F> {
|
||||||
/// Changes the batching strategy used when iterating.
|
/// Changes the batching strategy used when iterating.
|
||||||
///
|
///
|
||||||
/// For more information on how this affects the resultant iteration, see
|
/// For more information on how this affects the resultant iteration, see
|
||||||
|
|
|
@ -6,7 +6,7 @@ use crate::{
|
||||||
prelude::{Component, FromWorld},
|
prelude::{Component, FromWorld},
|
||||||
query::{
|
query::{
|
||||||
Access, BatchingStrategy, DebugCheckedUnwrap, FilteredAccess, QueryCombinationIter,
|
Access, BatchingStrategy, DebugCheckedUnwrap, FilteredAccess, QueryCombinationIter,
|
||||||
QueryIter, QueryParIter, WorldQuery,
|
QueryIter, QueryParIter,
|
||||||
},
|
},
|
||||||
storage::{TableId, TableRow},
|
storage::{TableId, TableRow},
|
||||||
world::{unsafe_world_cell::UnsafeWorldCell, World, WorldId},
|
world::{unsafe_world_cell::UnsafeWorldCell, World, WorldId},
|
||||||
|
@ -18,15 +18,15 @@ use std::{any::TypeId, borrow::Borrow, fmt, mem::MaybeUninit};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
NopWorldQuery, QueryComponentError, QueryEntityError, QueryManyIter, QuerySingleError,
|
NopWorldQuery, QueryComponentError, QueryEntityError, QueryManyIter, QuerySingleError,
|
||||||
ROQueryItem, ReadOnlyWorldQuery,
|
ROQueryItem, WorldQueryData, WorldQueryFilter,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// 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 [`WorldQueryData`] and [`WorldQueryFilter`].
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
// SAFETY NOTE:
|
// SAFETY NOTE:
|
||||||
// Do not add any new fields that use the `Q` or `F` generic parameters as this may
|
// Do not add any new fields that use the `Q` or `F` generic parameters as this may
|
||||||
// make `QueryState::as_transmuted_state` unsound if not done with care.
|
// make `QueryState::as_transmuted_state` unsound if not done with care.
|
||||||
pub struct QueryState<Q: WorldQuery, F: ReadOnlyWorldQuery = ()> {
|
pub struct QueryState<Q: WorldQueryData, F: WorldQueryFilter = ()> {
|
||||||
world_id: WorldId,
|
world_id: WorldId,
|
||||||
pub(crate) archetype_generation: ArchetypeGeneration,
|
pub(crate) archetype_generation: ArchetypeGeneration,
|
||||||
pub(crate) matched_tables: FixedBitSet,
|
pub(crate) matched_tables: FixedBitSet,
|
||||||
|
@ -43,7 +43,7 @@ pub struct QueryState<Q: WorldQuery, F: ReadOnlyWorldQuery = ()> {
|
||||||
par_iter_span: Span,
|
par_iter_span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Q: WorldQuery, F: ReadOnlyWorldQuery> std::fmt::Debug for QueryState<Q, F> {
|
impl<Q: WorldQueryData, F: WorldQueryFilter> std::fmt::Debug for QueryState<Q, F> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
f.debug_struct("QueryState")
|
f.debug_struct("QueryState")
|
||||||
.field("world_id", &self.world_id)
|
.field("world_id", &self.world_id)
|
||||||
|
@ -53,18 +53,18 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> std::fmt::Debug for QueryState<Q, F>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Q: WorldQuery, F: ReadOnlyWorldQuery> FromWorld for QueryState<Q, F> {
|
impl<Q: WorldQueryData, F: WorldQueryFilter> FromWorld for QueryState<Q, F> {
|
||||||
fn from_world(world: &mut World) -> Self {
|
fn from_world(world: &mut World) -> Self {
|
||||||
world.query_filtered()
|
world.query_filtered()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
impl<Q: WorldQueryData, F: WorldQueryFilter> QueryState<Q, F> {
|
||||||
/// Converts this `QueryState` reference to a `QueryState` that does not access anything mutably.
|
/// Converts this `QueryState` reference to a `QueryState` that does not access anything mutably.
|
||||||
pub fn as_readonly(&self) -> &QueryState<Q::ReadOnly, F::ReadOnly> {
|
pub fn as_readonly(&self) -> &QueryState<Q::ReadOnly, F> {
|
||||||
// SAFETY: invariant on `WorldQuery` trait upholds that `Q::ReadOnly` and `F::ReadOnly`
|
// SAFETY: invariant on `WorldQuery` trait upholds that `Q::ReadOnly` and `F::ReadOnly`
|
||||||
// have a subset of the access, and match the exact same archetypes/tables as `Q`/`F` respectively.
|
// have a subset of the access, and match the exact same archetypes/tables as `Q`/`F` respectively.
|
||||||
unsafe { self.as_transmuted_state::<Q::ReadOnly, F::ReadOnly>() }
|
unsafe { self.as_transmuted_state::<Q::ReadOnly, F>() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts this `QueryState` reference to a `QueryState` that does not return any data
|
/// Converts this `QueryState` reference to a `QueryState` that does not return any data
|
||||||
|
@ -88,8 +88,8 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
||||||
/// `NewQ` must have a subset of the access that `Q` does and match the exact same archetypes/tables
|
/// `NewQ` must have a subset of the access that `Q` does and match the exact same archetypes/tables
|
||||||
/// `NewF` must have a subset of the access that `F` does and match the exact same archetypes/tables
|
/// `NewF` must have a subset of the access that `F` does and match the exact same archetypes/tables
|
||||||
pub(crate) unsafe fn as_transmuted_state<
|
pub(crate) unsafe fn as_transmuted_state<
|
||||||
NewQ: WorldQuery<State = Q::State>,
|
NewQ: WorldQueryData<State = Q::State>,
|
||||||
NewF: ReadOnlyWorldQuery<State = F::State>,
|
NewF: WorldQueryFilter<State = F::State>,
|
||||||
>(
|
>(
|
||||||
&self,
|
&self,
|
||||||
) -> &QueryState<NewQ, NewF> {
|
) -> &QueryState<NewQ, NewF> {
|
||||||
|
@ -97,7 +97,7 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
impl<Q: WorldQueryData, F: WorldQueryFilter> 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::init_state(world);
|
let fetch_state = Q::init_state(world);
|
||||||
|
@ -162,7 +162,7 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// - `world` must have permission to read any components required by this instance's `F` [`WorldQuery`].
|
/// - `world` must have permission to read any components required by this instance's `F` [`WorldQueryFilter`].
|
||||||
/// - `world` must match the one used to create this [`QueryState`].
|
/// - `world` must match the one used to create this [`QueryState`].
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) unsafe fn is_empty_unsafe_world_cell(
|
pub(crate) unsafe fn is_empty_unsafe_world_cell(
|
||||||
|
@ -701,10 +701,7 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
||||||
///
|
///
|
||||||
/// This can only be called for read-only queries, see [`Self::iter_mut`] for write-queries.
|
/// This can only be called for read-only queries, see [`Self::iter_mut`] for write-queries.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn iter<'w, 's>(
|
pub fn iter<'w, 's>(&'s mut self, world: &'w World) -> QueryIter<'w, 's, Q::ReadOnly, F> {
|
||||||
&'s mut self,
|
|
||||||
world: &'w World,
|
|
||||||
) -> QueryIter<'w, 's, Q::ReadOnly, F::ReadOnly> {
|
|
||||||
self.update_archetypes(world);
|
self.update_archetypes(world);
|
||||||
// SAFETY: query is read only
|
// SAFETY: query is read only
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -733,10 +730,7 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
||||||
///
|
///
|
||||||
/// This can only be called for read-only queries.
|
/// This can only be called for read-only queries.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn iter_manual<'w, 's>(
|
pub fn iter_manual<'w, 's>(&'s self, world: &'w World) -> QueryIter<'w, 's, Q::ReadOnly, F> {
|
||||||
&'s self,
|
|
||||||
world: &'w World,
|
|
||||||
) -> QueryIter<'w, 's, Q::ReadOnly, F::ReadOnly> {
|
|
||||||
self.validate_world(world.id());
|
self.validate_world(world.id());
|
||||||
// SAFETY: query is read only and world is validated
|
// SAFETY: query is read only and world is validated
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -773,7 +767,7 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
||||||
pub fn iter_combinations<'w, 's, const K: usize>(
|
pub fn iter_combinations<'w, 's, const K: usize>(
|
||||||
&'s mut self,
|
&'s mut self,
|
||||||
world: &'w World,
|
world: &'w World,
|
||||||
) -> QueryCombinationIter<'w, 's, Q::ReadOnly, F::ReadOnly, K> {
|
) -> QueryCombinationIter<'w, 's, Q::ReadOnly, F, K> {
|
||||||
self.update_archetypes(world);
|
self.update_archetypes(world);
|
||||||
// SAFETY: query is read only
|
// SAFETY: query is read only
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -833,7 +827,7 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
||||||
&'s mut self,
|
&'s mut self,
|
||||||
world: &'w World,
|
world: &'w World,
|
||||||
entities: EntityList,
|
entities: EntityList,
|
||||||
) -> QueryManyIter<'w, 's, Q::ReadOnly, F::ReadOnly, EntityList::IntoIter>
|
) -> QueryManyIter<'w, 's, Q::ReadOnly, F, EntityList::IntoIter>
|
||||||
where
|
where
|
||||||
EntityList::Item: Borrow<Entity>,
|
EntityList::Item: Borrow<Entity>,
|
||||||
{
|
{
|
||||||
|
@ -868,7 +862,7 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
||||||
&'s self,
|
&'s self,
|
||||||
world: &'w World,
|
world: &'w World,
|
||||||
entities: EntityList,
|
entities: EntityList,
|
||||||
) -> QueryManyIter<'w, 's, Q::ReadOnly, F::ReadOnly, EntityList::IntoIter>
|
) -> QueryManyIter<'w, 's, Q::ReadOnly, F, EntityList::IntoIter>
|
||||||
where
|
where
|
||||||
EntityList::Item: Borrow<Entity>,
|
EntityList::Item: Borrow<Entity>,
|
||||||
{
|
{
|
||||||
|
@ -1072,7 +1066,7 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
|
||||||
pub fn par_iter<'w, 's>(
|
pub fn par_iter<'w, 's>(
|
||||||
&'s mut self,
|
&'s mut self,
|
||||||
world: &'w World,
|
world: &'w World,
|
||||||
) -> QueryParIter<'w, 's, Q::ReadOnly, F::ReadOnly> {
|
) -> QueryParIter<'w, 's, Q::ReadOnly, F> {
|
||||||
self.update_archetypes(world);
|
self.update_archetypes(world);
|
||||||
QueryParIter {
|
QueryParIter {
|
||||||
world: world.as_unsafe_world_cell_readonly(),
|
world: world.as_unsafe_world_cell_readonly(),
|
||||||
|
|
230
crates/bevy_ecs/src/query/world_query.rs
Normal file
230
crates/bevy_ecs/src/query/world_query.rs
Normal file
|
@ -0,0 +1,230 @@
|
||||||
|
use crate::{
|
||||||
|
archetype::{Archetype, ArchetypeComponentId},
|
||||||
|
component::{ComponentId, Tick},
|
||||||
|
entity::Entity,
|
||||||
|
query::{Access, FilteredAccess},
|
||||||
|
storage::{Table, TableRow},
|
||||||
|
world::{unsafe_world_cell::UnsafeWorldCell, World},
|
||||||
|
};
|
||||||
|
use bevy_utils::all_tuples;
|
||||||
|
|
||||||
|
/// Types that can be used as parameters in a [`Query`].
|
||||||
|
/// Types that implement this should also implement either [`WorldQueryData`] or [`WorldQueryFilter`]
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// Implementor must ensure that
|
||||||
|
/// [`update_component_access`], [`update_archetype_component_access`], [`matches_component_set`], and [`fetch`]
|
||||||
|
/// obey the following:
|
||||||
|
///
|
||||||
|
/// - For each component mutably accessed by [`fetch`], [`update_component_access`] should add write access unless read or write access has already been added, in which case it should panic.
|
||||||
|
/// - For each component readonly accessed by [`fetch`], [`update_component_access`] should add read access unless write access has already been added, in which case it should panic.
|
||||||
|
/// - For each component mutably accessed by [`fetch`], [`update_archetype_component_access`] should add write access if that component belongs to the archetype.
|
||||||
|
/// - For each component readonly accessed by [`fetch`], [`update_archetype_component_access`] should add read access if that component belongs to the archetype.
|
||||||
|
/// - If `fetch` mutably accesses the same component twice, [`update_component_access`] should panic.
|
||||||
|
/// - [`update_component_access`] may not add a `Without` filter for a component unless [`matches_component_set`] always returns `false` when the component set contains that component.
|
||||||
|
/// - [`update_component_access`] may not add a `With` filter for a component unless [`matches_component_set`] always returns `false` when the component set doesn't contain that component.
|
||||||
|
/// - In cases where the query represents a disjunction (such as an `Or` filter) where each element is a valid [`WorldQuery`], the following rules must be obeyed:
|
||||||
|
/// - [`matches_component_set`] must be a disjunction of the element's implementations
|
||||||
|
/// - [`update_component_access`] must replace the filters with a disjunction of filters
|
||||||
|
/// - Each filter in that disjunction must be a conjunction of the corresponding element's filter with the previous `access`
|
||||||
|
///
|
||||||
|
/// When implementing [`update_component_access`], note that `add_read` and `add_write` both also add a `With` filter, whereas `extend_access` does not change the filters.
|
||||||
|
///
|
||||||
|
/// [`fetch`]: Self::fetch
|
||||||
|
/// [`matches_component_set`]: Self::matches_component_set
|
||||||
|
/// [`Query`]: crate::system::Query
|
||||||
|
/// [`update_archetype_component_access`]: Self::update_archetype_component_access
|
||||||
|
/// [`update_component_access`]: Self::update_component_access
|
||||||
|
/// [`WorldQueryData`]: crate::query::WorldQueryData
|
||||||
|
/// [`WorldQueryFilter`]: crate::query::WorldQueryFilter
|
||||||
|
pub unsafe trait WorldQuery {
|
||||||
|
/// The item returned by this [`WorldQuery`]
|
||||||
|
/// For `WorldQueryData` this will be the item returned by the query.
|
||||||
|
/// For `WorldQueryFilter` this will be either `()`, or a `bool` indicating whether the entity should be included
|
||||||
|
/// or a tuple of such things.
|
||||||
|
type Item<'a>;
|
||||||
|
|
||||||
|
/// Per archetype/table state used by this [`WorldQuery`] to fetch [`Self::Item`](crate::query::WorldQuery::Item)
|
||||||
|
type Fetch<'a>: Clone;
|
||||||
|
|
||||||
|
/// State used to construct a [`Self::Fetch`](crate::query::WorldQuery::Fetch). This will be cached inside [`QueryState`](crate::query::QueryState),
|
||||||
|
/// so it is best to move as much data / computation here as possible to reduce the cost of
|
||||||
|
/// constructing [`Self::Fetch`](crate::query::WorldQuery::Fetch).
|
||||||
|
type State: Send + Sync + Sized;
|
||||||
|
|
||||||
|
/// This function manually implements subtyping for the query items.
|
||||||
|
fn shrink<'wlong: 'wshort, 'wshort>(item: Self::Item<'wlong>) -> Self::Item<'wshort>;
|
||||||
|
|
||||||
|
/// Creates a new instance of this fetch.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// - `world` must have permission to access any of the components specified in `Self::update_archetype_component_access`.
|
||||||
|
/// - `state` must have been initialized (via [`WorldQuery::init_state`]) using the same `world` passed
|
||||||
|
/// in to this function.
|
||||||
|
unsafe fn init_fetch<'w>(
|
||||||
|
world: UnsafeWorldCell<'w>,
|
||||||
|
state: &Self::State,
|
||||||
|
last_run: Tick,
|
||||||
|
this_run: Tick,
|
||||||
|
) -> Self::Fetch<'w>;
|
||||||
|
|
||||||
|
/// Returns true if (and only if) every table of every archetype matched by this fetch contains
|
||||||
|
/// all of the matched components. This is used to select a more efficient "table iterator"
|
||||||
|
/// for "dense" queries. If this returns true, [`WorldQuery::set_table`] must be used before
|
||||||
|
/// [`WorldQuery::fetch`] can be called for iterators. If this returns false,
|
||||||
|
/// [`WorldQuery::set_archetype`] must be used before [`WorldQuery::fetch`] can be called for
|
||||||
|
/// iterators.
|
||||||
|
const IS_DENSE: bool;
|
||||||
|
|
||||||
|
/// Adjusts internal state to account for the next [`Archetype`]. This will always be called on
|
||||||
|
/// archetypes that match this [`WorldQuery`].
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// - `archetype` and `tables` must be from the same [`World`] that [`WorldQuery::init_state`] was called on.
|
||||||
|
/// - [`Self::update_archetype_component_access`] must have been previously called with `archetype`.
|
||||||
|
/// - `table` must correspond to `archetype`.
|
||||||
|
/// - `state` must be the [`State`](Self::State) that `fetch` was initialized with.
|
||||||
|
unsafe fn set_archetype<'w>(
|
||||||
|
fetch: &mut Self::Fetch<'w>,
|
||||||
|
state: &Self::State,
|
||||||
|
archetype: &'w Archetype,
|
||||||
|
table: &'w Table,
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Adjusts internal state to account for the next [`Table`]. This will always be called on tables
|
||||||
|
/// that match this [`WorldQuery`].
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// - `table` must be from the same [`World`] that [`WorldQuery::init_state`] was called on.
|
||||||
|
/// - `table` must belong to an archetype that was previously registered with
|
||||||
|
/// [`Self::update_archetype_component_access`].
|
||||||
|
/// - `state` must be the [`State`](Self::State) that `fetch` was initialized with.
|
||||||
|
unsafe fn set_table<'w>(fetch: &mut Self::Fetch<'w>, state: &Self::State, table: &'w Table);
|
||||||
|
|
||||||
|
/// Fetch [`Self::Item`](`WorldQuery::Item`) for either the given `entity` in the current [`Table`],
|
||||||
|
/// or for the given `entity` in the current [`Archetype`]. This must always be called after
|
||||||
|
/// [`WorldQuery::set_table`] with a `table_row` in the range of the current [`Table`] or after
|
||||||
|
/// [`WorldQuery::set_archetype`] with a `entity` in the current archetype.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// Must always be called _after_ [`WorldQuery::set_table`] or [`WorldQuery::set_archetype`]. `entity` and
|
||||||
|
/// `table_row` must be in the range of the current table and archetype.
|
||||||
|
unsafe fn fetch<'w>(
|
||||||
|
fetch: &mut Self::Fetch<'w>,
|
||||||
|
entity: Entity,
|
||||||
|
table_row: TableRow,
|
||||||
|
) -> Self::Item<'w>;
|
||||||
|
|
||||||
|
/// Adds any component accesses used by this [`WorldQuery`] to `access`.
|
||||||
|
// This does not have a default body of `{}` because 99% of cases need to add accesses
|
||||||
|
// and forgetting to do so would be unsound.
|
||||||
|
fn update_component_access(state: &Self::State, access: &mut FilteredAccess<ComponentId>);
|
||||||
|
|
||||||
|
/// For the given `archetype`, adds any component accessed used by this [`WorldQuery`] to `access`.
|
||||||
|
// This does not have a default body of `{}` because 99% of cases need to add accesses
|
||||||
|
// and forgetting to do so would be unsound.
|
||||||
|
fn update_archetype_component_access(
|
||||||
|
state: &Self::State,
|
||||||
|
archetype: &Archetype,
|
||||||
|
access: &mut Access<ArchetypeComponentId>,
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Creates and initializes a [`State`](WorldQuery::State) for this [`WorldQuery`] type.
|
||||||
|
fn init_state(world: &mut World) -> Self::State;
|
||||||
|
|
||||||
|
/// Returns `true` if this query matches a set of components. Otherwise, returns `false`.
|
||||||
|
fn matches_component_set(
|
||||||
|
state: &Self::State,
|
||||||
|
set_contains_id: &impl Fn(ComponentId) -> bool,
|
||||||
|
) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_tuple_world_query {
|
||||||
|
($(($name: ident, $state: ident)),*) => {
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
#[allow(clippy::unused_unit)]
|
||||||
|
/// SAFETY:
|
||||||
|
/// `fetch` accesses are the conjunction of the subqueries' accesses
|
||||||
|
/// This is sound because `update_component_access` and `update_archetype_component_access` adds accesses according to the implementations of all the subqueries.
|
||||||
|
/// `update_component_access` adds all `With` and `Without` filters from the subqueries.
|
||||||
|
/// This is sound because `matches_component_set` always returns `false` if any the subqueries' implementations return `false`.
|
||||||
|
unsafe impl<$($name: WorldQuery),*> WorldQuery for ($($name,)*) {
|
||||||
|
type Fetch<'w> = ($($name::Fetch<'w>,)*);
|
||||||
|
type Item<'w> = ($($name::Item<'w>,)*);
|
||||||
|
type State = ($($name::State,)*);
|
||||||
|
|
||||||
|
fn shrink<'wlong: 'wshort, 'wshort>(item: Self::Item<'wlong>) -> Self::Item<'wshort> {
|
||||||
|
let ($($name,)*) = item;
|
||||||
|
($(
|
||||||
|
$name::shrink($name),
|
||||||
|
)*)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
#[allow(clippy::unused_unit)]
|
||||||
|
unsafe fn init_fetch<'w>(_world: UnsafeWorldCell<'w>, state: &Self::State, _last_run: Tick, _this_run: Tick) -> Self::Fetch<'w> {
|
||||||
|
let ($($name,)*) = state;
|
||||||
|
($($name::init_fetch(_world, $name, _last_run, _this_run),)*)
|
||||||
|
}
|
||||||
|
|
||||||
|
const IS_DENSE: bool = true $(&& $name::IS_DENSE)*;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn set_archetype<'w>(
|
||||||
|
_fetch: &mut Self::Fetch<'w>,
|
||||||
|
_state: &Self::State,
|
||||||
|
_archetype: &'w Archetype,
|
||||||
|
_table: &'w Table
|
||||||
|
) {
|
||||||
|
let ($($name,)*) = _fetch;
|
||||||
|
let ($($state,)*) = _state;
|
||||||
|
$($name::set_archetype($name, $state, _archetype, _table);)*
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
unsafe fn set_table<'w>(_fetch: &mut Self::Fetch<'w>, _state: &Self::State, _table: &'w Table) {
|
||||||
|
let ($($name,)*) = _fetch;
|
||||||
|
let ($($state,)*) = _state;
|
||||||
|
$($name::set_table($name, $state, _table);)*
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
#[allow(clippy::unused_unit)]
|
||||||
|
unsafe fn fetch<'w>(
|
||||||
|
_fetch: &mut Self::Fetch<'w>,
|
||||||
|
_entity: Entity,
|
||||||
|
_table_row: TableRow
|
||||||
|
) -> Self::Item<'w> {
|
||||||
|
let ($($name,)*) = _fetch;
|
||||||
|
($($name::fetch($name, _entity, _table_row),)*)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_component_access(state: &Self::State, _access: &mut FilteredAccess<ComponentId>) {
|
||||||
|
let ($($name,)*) = state;
|
||||||
|
$($name::update_component_access($name, _access);)*
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_archetype_component_access(state: &Self::State, _archetype: &Archetype, _access: &mut Access<ArchetypeComponentId>) {
|
||||||
|
let ($($name,)*) = state;
|
||||||
|
$($name::update_archetype_component_access($name, _archetype, _access);)*
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init_state(_world: &mut World) -> Self::State {
|
||||||
|
($($name::init_state(_world),)*)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn matches_component_set(state: &Self::State, _set_contains_id: &impl Fn(ComponentId) -> bool) -> bool {
|
||||||
|
let ($($name,)*) = state;
|
||||||
|
true $(&& $name::matches_component_set($name, _set_contains_id))*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
all_tuples!(impl_tuple_world_query, 0, 15, F, S);
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
prelude::{FromWorld, QueryState},
|
prelude::{FromWorld, QueryState},
|
||||||
query::{ReadOnlyWorldQuery, WorldQuery},
|
query::{WorldQueryData, WorldQueryFilter},
|
||||||
system::{Local, SystemMeta, SystemParam, SystemState},
|
system::{Local, SystemMeta, SystemParam, SystemState},
|
||||||
world::World,
|
world::World,
|
||||||
};
|
};
|
||||||
|
@ -29,7 +29,7 @@ pub trait ExclusiveSystemParam: Sized {
|
||||||
/// for a given [`ExclusiveSystemParam`].
|
/// for a given [`ExclusiveSystemParam`].
|
||||||
pub type ExclusiveSystemParamItem<'s, P> = <P as ExclusiveSystemParam>::Item<'s>;
|
pub type ExclusiveSystemParamItem<'s, P> = <P as ExclusiveSystemParam>::Item<'s>;
|
||||||
|
|
||||||
impl<'a, Q: WorldQuery + 'static, F: ReadOnlyWorldQuery + 'static> ExclusiveSystemParam
|
impl<'a, Q: WorldQueryData + 'static, F: WorldQueryFilter + 'static> ExclusiveSystemParam
|
||||||
for &'a mut QueryState<Q, F>
|
for &'a mut QueryState<Q, F>
|
||||||
{
|
{
|
||||||
type State = QueryState<Q, F>;
|
type State = QueryState<Q, F>;
|
||||||
|
|
|
@ -3,8 +3,8 @@ use crate::{
|
||||||
entity::Entity,
|
entity::Entity,
|
||||||
query::{
|
query::{
|
||||||
BatchingStrategy, QueryCombinationIter, QueryComponentError, QueryEntityError, QueryIter,
|
BatchingStrategy, QueryCombinationIter, QueryComponentError, QueryEntityError, QueryIter,
|
||||||
QueryManyIter, QueryParIter, QuerySingleError, QueryState, ROQueryItem, ReadOnlyWorldQuery,
|
QueryManyIter, QueryParIter, QuerySingleError, QueryState, ROQueryItem,
|
||||||
WorldQuery,
|
ReadOnlyWorldQueryData, WorldQueryData, WorldQueryFilter,
|
||||||
},
|
},
|
||||||
world::{unsafe_world_cell::UnsafeWorldCell, Mut},
|
world::{unsafe_world_cell::UnsafeWorldCell, Mut},
|
||||||
};
|
};
|
||||||
|
@ -16,13 +16,15 @@ use std::{any::TypeId, borrow::Borrow};
|
||||||
/// Its iterators and getter methods return *query items*.
|
/// Its iterators and getter methods return *query items*.
|
||||||
/// Each query item is a type containing data relative to an entity.
|
/// Each query item is a type containing data relative to an entity.
|
||||||
///
|
///
|
||||||
/// `Query` is a generic data structure that accepts two type parameters, both of which must implement the [`WorldQuery`] trait:
|
/// `Query` is a generic data structure that accepts two type parameters:
|
||||||
///
|
///
|
||||||
/// - **`Q` (query fetch).**
|
/// - **`Q` (query fetch).**
|
||||||
/// The type of data contained in the query item.
|
/// The type of data contained in the query item.
|
||||||
/// Only entities that match the requested data will generate an item.
|
/// Only entities that match the requested data will generate an item.
|
||||||
|
/// Must implement the [`WorldQueryData`] trait.
|
||||||
/// - **`F` (query filter).**
|
/// - **`F` (query filter).**
|
||||||
/// A set of conditions that determines whether query items should be kept or discarded.
|
/// A set of conditions that determines whether query items should be kept or discarded.
|
||||||
|
/// Must implement the [`WorldQueryFilter`] trait.
|
||||||
/// This type parameter is optional.
|
/// This type parameter is optional.
|
||||||
///
|
///
|
||||||
/// [`World`]: crate::world::World
|
/// [`World`]: crate::world::World
|
||||||
|
@ -30,7 +32,7 @@ use std::{any::TypeId, borrow::Borrow};
|
||||||
/// # System parameter declaration
|
/// # System parameter declaration
|
||||||
///
|
///
|
||||||
/// A query should always be declared as a system parameter.
|
/// A query should always be declared as a system parameter.
|
||||||
/// This section shows the most common idioms involving the declaration of `Query`, emerging by combining [`WorldQuery`] implementors.
|
/// This section shows the most common idioms involving the declaration of `Query`.
|
||||||
///
|
///
|
||||||
/// ## Component access
|
/// ## Component access
|
||||||
///
|
///
|
||||||
|
@ -71,7 +73,7 @@ use std::{any::TypeId, borrow::Borrow};
|
||||||
/// # bevy_ecs::system::assert_is_system(system);
|
/// # bevy_ecs::system::assert_is_system(system);
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// ## `WorldQuery` tuples
|
/// ## `WorldQueryData` or `WorldQueryFilter` tuples
|
||||||
///
|
///
|
||||||
/// Using tuples, each `Query` type parameter can contain multiple elements.
|
/// Using tuples, each `Query` type parameter can contain multiple elements.
|
||||||
///
|
///
|
||||||
|
@ -323,7 +325,7 @@ use std::{any::TypeId, borrow::Borrow};
|
||||||
/// [`Table`]: crate::storage::Table
|
/// [`Table`]: crate::storage::Table
|
||||||
/// [`With`]: crate::query::With
|
/// [`With`]: crate::query::With
|
||||||
/// [`Without`]: crate::query::Without
|
/// [`Without`]: crate::query::Without
|
||||||
pub struct Query<'world, 'state, Q: WorldQuery, F: ReadOnlyWorldQuery = ()> {
|
pub struct Query<'world, 'state, Q: WorldQueryData, F: WorldQueryFilter = ()> {
|
||||||
// SAFETY: Must have access to the components registered in `state`.
|
// SAFETY: Must have access to the components registered in `state`.
|
||||||
world: UnsafeWorldCell<'world>,
|
world: UnsafeWorldCell<'world>,
|
||||||
state: &'state QueryState<Q, F>,
|
state: &'state QueryState<Q, F>,
|
||||||
|
@ -337,7 +339,7 @@ pub struct Query<'world, 'state, Q: WorldQuery, F: ReadOnlyWorldQuery = ()> {
|
||||||
force_read_only_component_access: bool,
|
force_read_only_component_access: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Q: WorldQuery, F: ReadOnlyWorldQuery> std::fmt::Debug for Query<'_, '_, Q, F> {
|
impl<Q: WorldQueryData, F: WorldQueryFilter> std::fmt::Debug for Query<'_, '_, Q, F> {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
f.debug_struct("Query")
|
f.debug_struct("Query")
|
||||||
.field("matched_entities", &self.iter().count())
|
.field("matched_entities", &self.iter().count())
|
||||||
|
@ -349,7 +351,7 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> std::fmt::Debug for Query<'_, '_, Q,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
|
impl<'w, 's, Q: WorldQueryData, F: WorldQueryFilter> Query<'w, 's, Q, F> {
|
||||||
/// Creates a new query.
|
/// Creates a new query.
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
|
@ -384,7 +386,7 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
|
||||||
/// For example, `Query<(&mut A, &B, &mut C), With<D>>` will become `Query<(&A, &B, &C), With<D>>`.
|
/// For example, `Query<(&mut A, &B, &mut C), With<D>>` will become `Query<(&A, &B, &C), With<D>>`.
|
||||||
/// This can be useful when working around the borrow checker,
|
/// This can be useful when working around the borrow checker,
|
||||||
/// or reusing functionality between systems via functions that accept query types.
|
/// or reusing functionality between systems via functions that accept query types.
|
||||||
pub fn to_readonly(&self) -> Query<'_, 's, Q::ReadOnly, F::ReadOnly> {
|
pub fn to_readonly(&self) -> Query<'_, 's, Q::ReadOnly, F> {
|
||||||
let new_state = self.state.as_readonly();
|
let new_state = self.state.as_readonly();
|
||||||
// SAFETY: This is memory safe because it turns the query immutable.
|
// SAFETY: This is memory safe because it turns the query immutable.
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -425,7 +427,7 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
|
||||||
/// - [`iter_mut`](Self::iter_mut) for mutable query items.
|
/// - [`iter_mut`](Self::iter_mut) for mutable query items.
|
||||||
/// - [`for_each`](Self::for_each) for the closure based alternative.
|
/// - [`for_each`](Self::for_each) for the closure based alternative.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn iter(&self) -> QueryIter<'_, 's, Q::ReadOnly, F::ReadOnly> {
|
pub fn iter(&self) -> QueryIter<'_, 's, Q::ReadOnly, F> {
|
||||||
// SAFETY:
|
// SAFETY:
|
||||||
// - `self.world` has permission to access the required components.
|
// - `self.world` has permission to access the required components.
|
||||||
// - The query is read-only, so it can be aliased even if it was originally mutable.
|
// - The query is read-only, so it can be aliased even if it was originally mutable.
|
||||||
|
@ -491,7 +493,7 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn iter_combinations<const K: usize>(
|
pub fn iter_combinations<const K: usize>(
|
||||||
&self,
|
&self,
|
||||||
) -> QueryCombinationIter<'_, 's, Q::ReadOnly, F::ReadOnly, K> {
|
) -> QueryCombinationIter<'_, 's, Q::ReadOnly, F, K> {
|
||||||
// SAFETY:
|
// SAFETY:
|
||||||
// - `self.world` has permission to access the required components.
|
// - `self.world` has permission to access the required components.
|
||||||
// - The query is read-only, so it can be aliased even if it was originally mutable.
|
// - The query is read-only, so it can be aliased even if it was originally mutable.
|
||||||
|
@ -574,7 +576,7 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
|
||||||
pub fn iter_many<EntityList: IntoIterator>(
|
pub fn iter_many<EntityList: IntoIterator>(
|
||||||
&self,
|
&self,
|
||||||
entities: EntityList,
|
entities: EntityList,
|
||||||
) -> QueryManyIter<'_, 's, Q::ReadOnly, F::ReadOnly, EntityList::IntoIter>
|
) -> QueryManyIter<'_, 's, Q::ReadOnly, F, EntityList::IntoIter>
|
||||||
where
|
where
|
||||||
EntityList::Item: Borrow<Entity>,
|
EntityList::Item: Borrow<Entity>,
|
||||||
{
|
{
|
||||||
|
@ -787,7 +789,7 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
|
||||||
/// [`par_iter_mut`]: Self::par_iter_mut
|
/// [`par_iter_mut`]: Self::par_iter_mut
|
||||||
/// [`World`]: crate::world::World
|
/// [`World`]: crate::world::World
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn par_iter(&self) -> QueryParIter<'_, '_, Q::ReadOnly, F::ReadOnly> {
|
pub fn par_iter(&self) -> QueryParIter<'_, '_, Q::ReadOnly, F> {
|
||||||
QueryParIter {
|
QueryParIter {
|
||||||
world: self.world,
|
world: self.world,
|
||||||
state: self.state.as_readonly(),
|
state: self.state.as_readonly(),
|
||||||
|
@ -1420,16 +1422,16 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> IntoIterator for &'w Query<'_, 's, Q, F> {
|
impl<'w, 's, Q: WorldQueryData, F: WorldQueryFilter> IntoIterator for &'w Query<'_, 's, Q, F> {
|
||||||
type Item = ROQueryItem<'w, Q>;
|
type Item = ROQueryItem<'w, Q>;
|
||||||
type IntoIter = QueryIter<'w, 's, Q::ReadOnly, F::ReadOnly>;
|
type IntoIter = QueryIter<'w, 's, Q::ReadOnly, F>;
|
||||||
|
|
||||||
fn into_iter(self) -> Self::IntoIter {
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
self.iter()
|
self.iter()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> IntoIterator for &'w mut Query<'_, 's, Q, F> {
|
impl<'w, 's, Q: WorldQueryData, F: WorldQueryFilter> IntoIterator for &'w mut Query<'_, 's, Q, F> {
|
||||||
type Item = Q::Item<'w>;
|
type Item = Q::Item<'w>;
|
||||||
type IntoIter = QueryIter<'w, 's, Q, F>;
|
type IntoIter = QueryIter<'w, 's, Q, F>;
|
||||||
|
|
||||||
|
@ -1438,7 +1440,7 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> IntoIterator for &'w mut Quer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'w, 's, Q: ReadOnlyWorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
|
impl<'w, 's, Q: ReadOnlyWorldQueryData, F: WorldQueryFilter> Query<'w, 's, Q, F> {
|
||||||
/// Returns the query item for the given [`Entity`], with the actual "inner" world lifetime.
|
/// Returns the query item for the given [`Entity`], with the actual "inner" world lifetime.
|
||||||
///
|
///
|
||||||
/// In case of a nonexisting entity or mismatched component, a [`QueryEntityError`] is
|
/// In case of a nonexisting entity or mismatched component, a [`QueryEntityError`] is
|
||||||
|
@ -1509,7 +1511,7 @@ impl<'w, 's, Q: ReadOnlyWorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
|
||||||
/// # bevy_ecs::system::assert_is_system(report_names_system);
|
/// # bevy_ecs::system::assert_is_system(report_names_system);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn iter_inner(&self) -> QueryIter<'w, 's, Q::ReadOnly, F::ReadOnly> {
|
pub fn iter_inner(&self) -> QueryIter<'w, 's, Q::ReadOnly, F> {
|
||||||
// SAFETY: system runs without conflicts with other systems.
|
// SAFETY: system runs without conflicts with other systems.
|
||||||
// same-system queries have runtime borrow checks when they conflict
|
// same-system queries have runtime borrow checks when they conflict
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|
|
@ -6,7 +6,8 @@ use crate::{
|
||||||
component::{ComponentId, ComponentTicks, Components, Tick},
|
component::{ComponentId, ComponentTicks, Components, Tick},
|
||||||
entity::Entities,
|
entity::Entities,
|
||||||
query::{
|
query::{
|
||||||
Access, FilteredAccess, FilteredAccessSet, QueryState, ReadOnlyWorldQuery, WorldQuery,
|
Access, FilteredAccess, FilteredAccessSet, QueryState, ReadOnlyWorldQueryData,
|
||||||
|
WorldQueryData, WorldQueryFilter,
|
||||||
},
|
},
|
||||||
system::{Query, SystemMeta},
|
system::{Query, SystemMeta},
|
||||||
world::{unsafe_world_cell::UnsafeWorldCell, FromWorld, World},
|
world::{unsafe_world_cell::UnsafeWorldCell, FromWorld, World},
|
||||||
|
@ -152,14 +153,14 @@ pub unsafe trait ReadOnlySystemParam: SystemParam {}
|
||||||
pub type SystemParamItem<'w, 's, P> = <P as SystemParam>::Item<'w, 's>;
|
pub type SystemParamItem<'w, 's, P> = <P as SystemParam>::Item<'w, 's>;
|
||||||
|
|
||||||
// SAFETY: QueryState is constrained to read-only fetches, so it only reads World.
|
// SAFETY: QueryState is constrained to read-only fetches, so it only reads World.
|
||||||
unsafe impl<'w, 's, Q: ReadOnlyWorldQuery + 'static, F: ReadOnlyWorldQuery + 'static>
|
unsafe impl<'w, 's, Q: ReadOnlyWorldQueryData + 'static, F: WorldQueryFilter + 'static>
|
||||||
ReadOnlySystemParam for Query<'w, 's, Q, F>
|
ReadOnlySystemParam for Query<'w, 's, Q, F>
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
// SAFETY: Relevant query ComponentId and ArchetypeComponentId access is applied to SystemMeta. If
|
// SAFETY: Relevant query ComponentId and ArchetypeComponentId access is applied to SystemMeta. If
|
||||||
// this Query conflicts with any prior access, a panic will occur.
|
// this Query conflicts with any prior access, a panic will occur.
|
||||||
unsafe impl<Q: WorldQuery + 'static, F: ReadOnlyWorldQuery + 'static> SystemParam
|
unsafe impl<Q: WorldQueryData + 'static, F: WorldQueryFilter + 'static> SystemParam
|
||||||
for Query<'_, '_, Q, F>
|
for Query<'_, '_, Q, F>
|
||||||
{
|
{
|
||||||
type State = QueryState<Q, F>;
|
type State = QueryState<Q, F>;
|
||||||
|
@ -1557,7 +1558,6 @@ mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
self as bevy_ecs, // Necessary for the `SystemParam` Derive when used inside `bevy_ecs`.
|
self as bevy_ecs, // Necessary for the `SystemParam` Derive when used inside `bevy_ecs`.
|
||||||
query::{ReadOnlyWorldQuery, WorldQuery},
|
|
||||||
system::{assert_is_system, Query},
|
system::{assert_is_system, Query},
|
||||||
};
|
};
|
||||||
use std::{cell::RefCell, marker::PhantomData};
|
use std::{cell::RefCell, marker::PhantomData};
|
||||||
|
@ -1569,8 +1569,8 @@ mod tests {
|
||||||
pub struct SpecialQuery<
|
pub struct SpecialQuery<
|
||||||
'w,
|
'w,
|
||||||
's,
|
's,
|
||||||
Q: WorldQuery + Send + Sync + 'static,
|
Q: WorldQueryData + Send + Sync + 'static,
|
||||||
F: ReadOnlyWorldQuery + Send + Sync + 'static = (),
|
F: WorldQueryFilter + Send + Sync + 'static = (),
|
||||||
> {
|
> {
|
||||||
_query: Query<'w, 's, Q, F>,
|
_query: Query<'w, 's, Q, F>,
|
||||||
}
|
}
|
||||||
|
@ -1691,7 +1691,7 @@ mod tests {
|
||||||
#[derive(SystemParam)]
|
#[derive(SystemParam)]
|
||||||
pub struct WhereParam<'w, 's, Q>
|
pub struct WhereParam<'w, 's, Q>
|
||||||
where
|
where
|
||||||
Q: 'static + WorldQuery,
|
Q: 'static + WorldQueryData,
|
||||||
{
|
{
|
||||||
_q: Query<'w, 's, Q, ()>,
|
_q: Query<'w, 's, Q, ()>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ use crate::{
|
||||||
component::{Component, ComponentDescriptor, ComponentId, ComponentInfo, Components, Tick},
|
component::{Component, ComponentDescriptor, ComponentId, ComponentInfo, Components, Tick},
|
||||||
entity::{AllocAtWithoutReplacement, Entities, Entity, EntityLocation},
|
entity::{AllocAtWithoutReplacement, Entities, Entity, EntityLocation},
|
||||||
event::{Event, EventId, Events, SendBatchIds},
|
event::{Event, EventId, Events, SendBatchIds},
|
||||||
query::{DebugCheckedUnwrap, QueryEntityError, QueryState, ReadOnlyWorldQuery, WorldQuery},
|
query::{DebugCheckedUnwrap, QueryEntityError, QueryState, WorldQueryData, WorldQueryFilter},
|
||||||
removal_detection::RemovedComponentEvents,
|
removal_detection::RemovedComponentEvents,
|
||||||
schedule::{Schedule, ScheduleLabel, Schedules},
|
schedule::{Schedule, ScheduleLabel, Schedules},
|
||||||
storage::{ResourceData, Storages},
|
storage::{ResourceData, Storages},
|
||||||
|
@ -922,7 +922,7 @@ impl World {
|
||||||
self.last_change_tick = self.increment_change_tick();
|
self.last_change_tick = self.increment_change_tick();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns [`QueryState`] for the given [`WorldQuery`], which is used to efficiently
|
/// Returns [`QueryState`] for the given [`WorldQueryData`], which is used to efficiently
|
||||||
/// run queries on the [`World`] by storing and reusing the [`QueryState`].
|
/// run queries on the [`World`] by storing and reusing the [`QueryState`].
|
||||||
/// ```
|
/// ```
|
||||||
/// use bevy_ecs::{component::Component, entity::Entity, world::World};
|
/// use bevy_ecs::{component::Component, entity::Entity, world::World};
|
||||||
|
@ -985,11 +985,11 @@ impl World {
|
||||||
/// ]);
|
/// ]);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn query<Q: WorldQuery>(&mut self) -> QueryState<Q, ()> {
|
pub fn query<Q: WorldQueryData>(&mut self) -> QueryState<Q, ()> {
|
||||||
self.query_filtered::<Q, ()>()
|
self.query_filtered::<Q, ()>()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns [`QueryState`] for the given filtered [`WorldQuery`], which is used to efficiently
|
/// Returns [`QueryState`] for the given filtered [`WorldQueryData`], which is used to efficiently
|
||||||
/// run queries on the [`World`] by storing and reusing the [`QueryState`].
|
/// run queries on the [`World`] by storing and reusing the [`QueryState`].
|
||||||
/// ```
|
/// ```
|
||||||
/// use bevy_ecs::{component::Component, entity::Entity, world::World, query::With};
|
/// use bevy_ecs::{component::Component, entity::Entity, world::World, query::With};
|
||||||
|
@ -1009,7 +1009,7 @@ impl World {
|
||||||
/// assert_eq!(matching_entities, vec![e2]);
|
/// assert_eq!(matching_entities, vec![e2]);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn query_filtered<Q: WorldQuery, F: ReadOnlyWorldQuery>(&mut self) -> QueryState<Q, F> {
|
pub fn query_filtered<Q: WorldQueryData, F: WorldQueryFilter>(&mut self) -> QueryState<Q, F> {
|
||||||
QueryState::new(self)
|
QueryState::new(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
error[E0277]: the trait bound `&mut A: ReadOnlyWorldQuery` is not satisfied
|
error[E0277]: the trait bound `&mut A: ReadOnlyWorldQueryData` is not satisfied
|
||||||
--> tests/ui/query_iter_combinations_mut_iterator_safety.rs:10:17
|
--> tests/ui/query_iter_combinations_mut_iterator_safety.rs:10:17
|
||||||
|
|
|
|
||||||
10 | is_iterator(iter)
|
10 | is_iterator(iter)
|
||||||
| ----------- ^^^^ the trait `ReadOnlyWorldQuery` is not implemented for `&mut A`
|
| ----------- ^^^^ the trait `ReadOnlyWorldQueryData` is not implemented for `&mut A`
|
||||||
| |
|
| |
|
||||||
| required by a bound introduced by this call
|
| required by a bound introduced by this call
|
||||||
|
|
|
|
||||||
= help: the following other types implement trait `ReadOnlyWorldQuery`:
|
= help: the following other types implement trait `ReadOnlyWorldQueryData`:
|
||||||
bevy_ecs::change_detection::Ref<'__w, T>
|
bevy_ecs::change_detection::Ref<'__w, T>
|
||||||
Has<T>
|
Has<T>
|
||||||
AnyOf<()>
|
AnyOf<()>
|
||||||
|
@ -16,7 +16,7 @@ error[E0277]: the trait bound `&mut A: ReadOnlyWorldQuery` is not satisfied
|
||||||
AnyOf<(F0, F1, F2, F3)>
|
AnyOf<(F0, F1, F2, F3)>
|
||||||
AnyOf<(F0, F1, F2, F3, F4)>
|
AnyOf<(F0, F1, F2, F3, F4)>
|
||||||
and $N others
|
and $N others
|
||||||
= note: `ReadOnlyWorldQuery` is implemented for `&A`, but not for `&mut A`
|
= note: `ReadOnlyWorldQueryData` is implemented for `&A`, but not for `&mut A`
|
||||||
= note: required for `QueryCombinationIter<'_, '_, &mut A, (), _>` to implement `Iterator`
|
= note: required for `QueryCombinationIter<'_, '_, &mut A, (), _>` to implement `Iterator`
|
||||||
note: required by a bound in `is_iterator`
|
note: required by a bound in `is_iterator`
|
||||||
--> tests/ui/query_iter_combinations_mut_iterator_safety.rs:13:19
|
--> tests/ui/query_iter_combinations_mut_iterator_safety.rs:13:19
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
error[E0277]: the trait bound `&mut A: ReadOnlyWorldQuery` is not satisfied
|
error[E0277]: the trait bound `&mut A: ReadOnlyWorldQueryData` is not satisfied
|
||||||
--> tests/ui/query_iter_many_mut_iterator_safety.rs:10:17
|
--> tests/ui/query_iter_many_mut_iterator_safety.rs:10:17
|
||||||
|
|
|
|
||||||
10 | is_iterator(iter)
|
10 | is_iterator(iter)
|
||||||
| ----------- ^^^^ the trait `ReadOnlyWorldQuery` is not implemented for `&mut A`
|
| ----------- ^^^^ the trait `ReadOnlyWorldQueryData` is not implemented for `&mut A`
|
||||||
| |
|
| |
|
||||||
| required by a bound introduced by this call
|
| required by a bound introduced by this call
|
||||||
|
|
|
|
||||||
= help: the following other types implement trait `ReadOnlyWorldQuery`:
|
= help: the following other types implement trait `ReadOnlyWorldQueryData`:
|
||||||
bevy_ecs::change_detection::Ref<'__w, T>
|
bevy_ecs::change_detection::Ref<'__w, T>
|
||||||
Has<T>
|
Has<T>
|
||||||
AnyOf<()>
|
AnyOf<()>
|
||||||
|
@ -16,7 +16,7 @@ error[E0277]: the trait bound `&mut A: ReadOnlyWorldQuery` is not satisfied
|
||||||
AnyOf<(F0, F1, F2, F3)>
|
AnyOf<(F0, F1, F2, F3)>
|
||||||
AnyOf<(F0, F1, F2, F3, F4)>
|
AnyOf<(F0, F1, F2, F3, F4)>
|
||||||
and $N others
|
and $N others
|
||||||
= note: `ReadOnlyWorldQuery` is implemented for `&A`, but not for `&mut A`
|
= note: `ReadOnlyWorldQueryData` is implemented for `&A`, but not for `&mut A`
|
||||||
= note: required for `QueryManyIter<'_, '_, &mut A, (), std::array::IntoIter<bevy_ecs::entity::Entity, 1>>` to implement `Iterator`
|
= note: required for `QueryManyIter<'_, '_, &mut A, (), std::array::IntoIter<bevy_ecs::entity::Entity, 1>>` to implement `Iterator`
|
||||||
note: required by a bound in `is_iterator`
|
note: required by a bound in `is_iterator`
|
||||||
--> tests/ui/query_iter_many_mut_iterator_safety.rs:13:19
|
--> tests/ui/query_iter_many_mut_iterator_safety.rs:13:19
|
||||||
|
|
|
@ -6,13 +6,13 @@ warning: unused import: `SystemState`
|
||||||
|
|
|
|
||||||
= note: `#[warn(unused_imports)]` on by default
|
= note: `#[warn(unused_imports)]` on by default
|
||||||
|
|
||||||
error[E0277]: the trait bound `&'static mut Foo: ReadOnlyWorldQuery` is not satisfied
|
error[E0277]: the trait bound `&'static mut Foo: ReadOnlyWorldQueryData` is not satisfied
|
||||||
--> tests/ui/system_param_derive_readonly.rs:18:23
|
--> tests/ui/system_param_derive_readonly.rs:18:23
|
||||||
|
|
|
|
||||||
18 | assert_readonly::<Mutable>();
|
18 | assert_readonly::<Mutable>();
|
||||||
| ^^^^^^^ the trait `ReadOnlyWorldQuery` is not implemented for `&'static mut Foo`
|
| ^^^^^^^ the trait `ReadOnlyWorldQueryData` is not implemented for `&'static mut Foo`
|
||||||
|
|
|
|
||||||
= help: the following other types implement trait `ReadOnlyWorldQuery`:
|
= help: the following other types implement trait `ReadOnlyWorldQueryData`:
|
||||||
bevy_ecs::change_detection::Ref<'__w, T>
|
bevy_ecs::change_detection::Ref<'__w, T>
|
||||||
Has<T>
|
Has<T>
|
||||||
AnyOf<()>
|
AnyOf<()>
|
||||||
|
@ -22,7 +22,7 @@ error[E0277]: the trait bound `&'static mut Foo: ReadOnlyWorldQuery` is not sati
|
||||||
AnyOf<(F0, F1, F2, F3)>
|
AnyOf<(F0, F1, F2, F3)>
|
||||||
AnyOf<(F0, F1, F2, F3, F4)>
|
AnyOf<(F0, F1, F2, F3, F4)>
|
||||||
and $N others
|
and $N others
|
||||||
= note: `ReadOnlyWorldQuery` is implemented for `&'static Foo`, but not for `&'static mut Foo`
|
= note: `ReadOnlyWorldQueryData` is implemented for `&'static Foo`, but not for `&'static mut Foo`
|
||||||
= note: required for `bevy_ecs::system::Query<'_, '_, &'static mut Foo>` to implement `ReadOnlySystemParam`
|
= note: required for `bevy_ecs::system::Query<'_, '_, &'static mut Foo>` to implement `ReadOnlySystemParam`
|
||||||
= note: 1 redundant requirement hidden
|
= note: 1 redundant requirement hidden
|
||||||
= note: required for `Mutable<'_, '_>` to implement `ReadOnlySystemParam`
|
= note: required for `Mutable<'_, '_>` to implement `ReadOnlySystemParam`
|
||||||
|
|
|
@ -1,21 +1,21 @@
|
||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
use bevy_ecs::query::WorldQuery;
|
use bevy_ecs::query::WorldQueryData;
|
||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
struct Foo;
|
struct Foo;
|
||||||
|
|
||||||
#[derive(WorldQuery)]
|
#[derive(WorldQueryData)]
|
||||||
struct MutableUnmarked {
|
struct MutableUnmarked {
|
||||||
a: &'static mut Foo,
|
a: &'static mut Foo,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(WorldQuery)]
|
#[derive(WorldQueryData)]
|
||||||
#[world_query(mutable)]
|
#[world_query_data(mutable)]
|
||||||
struct MutableMarked {
|
struct MutableMarked {
|
||||||
a: &'static mut Foo,
|
a: &'static mut Foo,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(WorldQuery)]
|
#[derive(WorldQueryData)]
|
||||||
struct NestedMutableUnmarked {
|
struct NestedMutableUnmarked {
|
||||||
a: MutableMarked,
|
a: MutableMarked,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
error[E0277]: the trait bound `&'static mut Foo: ReadOnlyWorldQuery` is not satisfied
|
error[E0277]: the trait bound `&'static mut Foo: ReadOnlyWorldQueryData` is not satisfied
|
||||||
--> tests/ui/world_query_derive.rs:9:8
|
--> tests/ui/world_query_derive.rs:9:8
|
||||||
|
|
|
|
||||||
9 | a: &'static mut Foo,
|
9 | a: &'static mut Foo,
|
||||||
| ^^^^^^^^^^^^^^^^ the trait `ReadOnlyWorldQuery` is not implemented for `&'static mut Foo`
|
| ^^^^^^^^^^^^^^^^ the trait `ReadOnlyWorldQueryData` is not implemented for `&'static mut Foo`
|
||||||
|
|
|
|
||||||
= help: the following other types implement trait `ReadOnlyWorldQuery`:
|
= help: the following other types implement trait `ReadOnlyWorldQueryData`:
|
||||||
MutableUnmarked
|
MutableUnmarked
|
||||||
MutableMarkedReadOnly
|
MutableMarkedReadOnly
|
||||||
NestedMutableUnmarked
|
NestedMutableUnmarked
|
||||||
|
@ -17,17 +17,17 @@ error[E0277]: the trait bound `&'static mut Foo: ReadOnlyWorldQuery` is not sati
|
||||||
note: required by a bound in `_::assert_readonly`
|
note: required by a bound in `_::assert_readonly`
|
||||||
--> tests/ui/world_query_derive.rs:7:10
|
--> tests/ui/world_query_derive.rs:7:10
|
||||||
|
|
|
|
||||||
7 | #[derive(WorldQuery)]
|
7 | #[derive(WorldQueryData)]
|
||||||
| ^^^^^^^^^^ required by this bound in `assert_readonly`
|
| ^^^^^^^^^^^^^^ required by this bound in `assert_readonly`
|
||||||
= note: this error originates in the derive macro `WorldQuery` (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in the derive macro `WorldQueryData` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
error[E0277]: the trait bound `MutableMarked: ReadOnlyWorldQuery` is not satisfied
|
error[E0277]: the trait bound `MutableMarked: ReadOnlyWorldQueryData` is not satisfied
|
||||||
--> tests/ui/world_query_derive.rs:20:8
|
--> tests/ui/world_query_derive.rs:20:8
|
||||||
|
|
|
|
||||||
20 | a: MutableMarked,
|
20 | a: MutableMarked,
|
||||||
| ^^^^^^^^^^^^^ the trait `ReadOnlyWorldQuery` is not implemented for `MutableMarked`
|
| ^^^^^^^^^^^^^ the trait `ReadOnlyWorldQueryData` is not implemented for `MutableMarked`
|
||||||
|
|
|
|
||||||
= help: the following other types implement trait `ReadOnlyWorldQuery`:
|
= help: the following other types implement trait `ReadOnlyWorldQueryData`:
|
||||||
MutableUnmarked
|
MutableUnmarked
|
||||||
MutableMarkedReadOnly
|
MutableMarkedReadOnly
|
||||||
NestedMutableUnmarked
|
NestedMutableUnmarked
|
||||||
|
@ -40,6 +40,6 @@ error[E0277]: the trait bound `MutableMarked: ReadOnlyWorldQuery` is not satisfi
|
||||||
note: required by a bound in `_::assert_readonly`
|
note: required by a bound in `_::assert_readonly`
|
||||||
--> tests/ui/world_query_derive.rs:18:10
|
--> tests/ui/world_query_derive.rs:18:10
|
||||||
|
|
|
|
||||||
18 | #[derive(WorldQuery)]
|
18 | #[derive(WorldQueryData)]
|
||||||
| ^^^^^^^^^^ required by this bound in `assert_readonly`
|
| ^^^^^^^^^^^^^^ required by this bound in `assert_readonly`
|
||||||
= note: this error originates in the derive macro `WorldQuery` (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in the derive macro `WorldQueryData` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
|
@ -2,14 +2,14 @@ use std::collections::VecDeque;
|
||||||
|
|
||||||
use bevy_ecs::{
|
use bevy_ecs::{
|
||||||
entity::Entity,
|
entity::Entity,
|
||||||
query::{ReadOnlyWorldQuery, WorldQuery},
|
query::{WorldQuery, WorldQueryData, WorldQueryFilter},
|
||||||
system::Query,
|
system::Query,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{Children, Parent};
|
use crate::{Children, Parent};
|
||||||
|
|
||||||
/// An extension trait for [`Query`] that adds hierarchy related methods.
|
/// An extension trait for [`Query`] that adds hierarchy related methods.
|
||||||
pub trait HierarchyQueryExt<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> {
|
pub trait HierarchyQueryExt<'w, 's, Q: WorldQueryData, F: WorldQueryFilter> {
|
||||||
/// Returns an [`Iterator`] of [`Entity`]s over all of `entity`s descendants.
|
/// Returns an [`Iterator`] of [`Entity`]s over all of `entity`s descendants.
|
||||||
///
|
///
|
||||||
/// Can only be called on a [`Query`] of [`Children`] (i.e. `Query<&Children>`).
|
/// Can only be called on a [`Query`] of [`Children`] (i.e. `Query<&Children>`).
|
||||||
|
@ -57,7 +57,7 @@ pub trait HierarchyQueryExt<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> {
|
||||||
Q::ReadOnly: WorldQuery<Item<'w> = &'w Parent>;
|
Q::ReadOnly: WorldQuery<Item<'w> = &'w Parent>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> HierarchyQueryExt<'w, 's, Q, F>
|
impl<'w, 's, Q: WorldQueryData, F: WorldQueryFilter> HierarchyQueryExt<'w, 's, Q, F>
|
||||||
for Query<'w, 's, Q, F>
|
for Query<'w, 's, Q, F>
|
||||||
{
|
{
|
||||||
fn iter_descendants(&'w self, entity: Entity) -> DescendantIter<'w, 's, Q, F>
|
fn iter_descendants(&'w self, entity: Entity) -> DescendantIter<'w, 's, Q, F>
|
||||||
|
@ -78,7 +78,7 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> HierarchyQueryExt<'w, 's, Q,
|
||||||
/// An [`Iterator`] of [`Entity`]s over the descendants of an [`Entity`].
|
/// An [`Iterator`] of [`Entity`]s over the descendants of an [`Entity`].
|
||||||
///
|
///
|
||||||
/// Traverses the hierarchy breadth-first.
|
/// Traverses the hierarchy breadth-first.
|
||||||
pub struct DescendantIter<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery>
|
pub struct DescendantIter<'w, 's, Q: WorldQueryData, F: WorldQueryFilter>
|
||||||
where
|
where
|
||||||
Q::ReadOnly: WorldQuery<Item<'w> = &'w Children>,
|
Q::ReadOnly: WorldQuery<Item<'w> = &'w Children>,
|
||||||
{
|
{
|
||||||
|
@ -86,7 +86,7 @@ where
|
||||||
vecdeque: VecDeque<Entity>,
|
vecdeque: VecDeque<Entity>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> DescendantIter<'w, 's, Q, F>
|
impl<'w, 's, Q: WorldQueryData, F: WorldQueryFilter> DescendantIter<'w, 's, Q, F>
|
||||||
where
|
where
|
||||||
Q::ReadOnly: WorldQuery<Item<'w> = &'w Children>,
|
Q::ReadOnly: WorldQuery<Item<'w> = &'w Children>,
|
||||||
{
|
{
|
||||||
|
@ -104,7 +104,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Iterator for DescendantIter<'w, 's, Q, F>
|
impl<'w, 's, Q: WorldQueryData, F: WorldQueryFilter> Iterator for DescendantIter<'w, 's, Q, F>
|
||||||
where
|
where
|
||||||
Q::ReadOnly: WorldQuery<Item<'w> = &'w Children>,
|
Q::ReadOnly: WorldQuery<Item<'w> = &'w Children>,
|
||||||
{
|
{
|
||||||
|
@ -122,7 +122,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An [`Iterator`] of [`Entity`]s over the ancestors of an [`Entity`].
|
/// An [`Iterator`] of [`Entity`]s over the ancestors of an [`Entity`].
|
||||||
pub struct AncestorIter<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery>
|
pub struct AncestorIter<'w, 's, Q: WorldQueryData, F: WorldQueryFilter>
|
||||||
where
|
where
|
||||||
Q::ReadOnly: WorldQuery<Item<'w> = &'w Parent>,
|
Q::ReadOnly: WorldQuery<Item<'w> = &'w Parent>,
|
||||||
{
|
{
|
||||||
|
@ -130,7 +130,7 @@ where
|
||||||
next: Option<Entity>,
|
next: Option<Entity>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> AncestorIter<'w, 's, Q, F>
|
impl<'w, 's, Q: WorldQueryData, F: WorldQueryFilter> AncestorIter<'w, 's, Q, F>
|
||||||
where
|
where
|
||||||
Q::ReadOnly: WorldQuery<Item<'w> = &'w Parent>,
|
Q::ReadOnly: WorldQuery<Item<'w> = &'w Parent>,
|
||||||
{
|
{
|
||||||
|
@ -143,7 +143,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Iterator for AncestorIter<'w, 's, Q, F>
|
impl<'w, 's, Q: WorldQueryData, F: WorldQueryFilter> Iterator for AncestorIter<'w, 's, Q, F>
|
||||||
where
|
where
|
||||||
Q::ReadOnly: WorldQuery<Item<'w> = &'w Parent>,
|
Q::ReadOnly: WorldQuery<Item<'w> = &'w Parent>,
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use bevy_ecs::{
|
use bevy_ecs::{
|
||||||
component::Component,
|
component::Component,
|
||||||
prelude::Res,
|
prelude::Res,
|
||||||
query::{QueryItem, ReadOnlyWorldQuery},
|
query::{QueryItem, ReadOnlyWorldQueryData, WorldQueryFilter},
|
||||||
system::{Query, ResMut, StaticSystemParam, SystemParam, SystemParamItem},
|
system::{Query, ResMut, StaticSystemParam, SystemParam, SystemParamItem},
|
||||||
};
|
};
|
||||||
use bevy_utils::nonmax::NonMaxU32;
|
use bevy_utils::nonmax::NonMaxU32;
|
||||||
|
@ -57,8 +57,8 @@ impl<T: PartialEq> BatchMeta<T> {
|
||||||
/// items.
|
/// items.
|
||||||
pub trait GetBatchData {
|
pub trait GetBatchData {
|
||||||
type Param: SystemParam + 'static;
|
type Param: SystemParam + 'static;
|
||||||
type Query: ReadOnlyWorldQuery;
|
type Query: ReadOnlyWorldQueryData;
|
||||||
type QueryFilter: ReadOnlyWorldQuery;
|
type QueryFilter: WorldQueryFilter;
|
||||||
/// Data used for comparison between phase items. If the pipeline id, draw
|
/// Data used for comparison between phase items. If the pipeline id, draw
|
||||||
/// function id, per-instance data buffer dynamic offset and this data
|
/// function id, per-instance data buffer dynamic offset and this data
|
||||||
/// matches, the draws can be batched.
|
/// matches, the draws can be batched.
|
||||||
|
|
|
@ -9,7 +9,7 @@ use bevy_asset::{Asset, Handle};
|
||||||
use bevy_ecs::{
|
use bevy_ecs::{
|
||||||
component::Component,
|
component::Component,
|
||||||
prelude::*,
|
prelude::*,
|
||||||
query::{QueryItem, ReadOnlyWorldQuery, WorldQuery},
|
query::{QueryItem, ReadOnlyWorldQueryData, WorldQueryFilter},
|
||||||
system::lifetimeless::Read,
|
system::lifetimeless::Read,
|
||||||
};
|
};
|
||||||
use std::{marker::PhantomData, ops::Deref};
|
use std::{marker::PhantomData, ops::Deref};
|
||||||
|
@ -35,10 +35,10 @@ impl<C: Component> DynamicUniformIndex<C> {
|
||||||
/// Therefore the component is transferred from the "app world" into the "render world"
|
/// Therefore the component is transferred from the "app world" into the "render world"
|
||||||
/// in the [`ExtractSchedule`] step.
|
/// in the [`ExtractSchedule`] step.
|
||||||
pub trait ExtractComponent: Component {
|
pub trait ExtractComponent: Component {
|
||||||
/// ECS [`WorldQuery`] to fetch the components to extract.
|
/// ECS [`ReadOnlyWorldQueryData`] to fetch the components to extract.
|
||||||
type Query: WorldQuery + ReadOnlyWorldQuery;
|
type Query: ReadOnlyWorldQueryData;
|
||||||
/// Filters the entities with additional constraints.
|
/// Filters the entities with additional constraints.
|
||||||
type Filter: WorldQuery + ReadOnlyWorldQuery;
|
type Filter: WorldQueryFilter;
|
||||||
|
|
||||||
/// The output from extraction.
|
/// The output from extraction.
|
||||||
///
|
///
|
||||||
|
|
|
@ -11,7 +11,7 @@ use bevy_asset::{Asset, AssetId, Handle};
|
||||||
use bevy_derive::{Deref, DerefMut};
|
use bevy_derive::{Deref, DerefMut};
|
||||||
use bevy_ecs::{
|
use bevy_ecs::{
|
||||||
prelude::Entity,
|
prelude::Entity,
|
||||||
query::{QueryItem, ReadOnlyWorldQuery, WorldQuery},
|
query::{QueryItem, ReadOnlyWorldQueryData, WorldQueryFilter},
|
||||||
system::{lifetimeless::Read, Query, ResMut, Resource},
|
system::{lifetimeless::Read, Query, ResMut, Resource},
|
||||||
};
|
};
|
||||||
use bevy_utils::EntityHashMap;
|
use bevy_utils::EntityHashMap;
|
||||||
|
@ -28,10 +28,10 @@ use crate::{prelude::ViewVisibility, Extract, ExtractSchedule, RenderApp};
|
||||||
/// [`ExtractComponent`](crate::extract_component::ExtractComponent), but
|
/// [`ExtractComponent`](crate::extract_component::ExtractComponent), but
|
||||||
/// higher-performance because it avoids the ECS overhead.
|
/// higher-performance because it avoids the ECS overhead.
|
||||||
pub trait ExtractInstance: Send + Sync + Sized + 'static {
|
pub trait ExtractInstance: Send + Sync + Sized + 'static {
|
||||||
/// ECS [`WorldQuery`] to fetch the components to extract.
|
/// ECS [`ReadOnlyWorldQueryData`] to fetch the components to extract.
|
||||||
type Query: WorldQuery + ReadOnlyWorldQuery;
|
type Query: ReadOnlyWorldQueryData;
|
||||||
/// Filters the entities with additional constraints.
|
/// Filters the entities with additional constraints.
|
||||||
type Filter: WorldQuery + ReadOnlyWorldQuery;
|
type Filter: WorldQueryFilter;
|
||||||
|
|
||||||
/// Defines how the component is transferred into the "render world".
|
/// Defines how the component is transferred into the "render world".
|
||||||
fn extract(item: QueryItem<'_, Self::Query>) -> Option<Self>;
|
fn extract(item: QueryItem<'_, Self::Query>) -> Option<Self>;
|
||||||
|
|
|
@ -7,7 +7,7 @@ use crate::{
|
||||||
renderer::RenderContext,
|
renderer::RenderContext,
|
||||||
};
|
};
|
||||||
use bevy_ecs::{
|
use bevy_ecs::{
|
||||||
query::{QueryItem, QueryState, ReadOnlyWorldQuery},
|
query::{QueryItem, QueryState, ReadOnlyWorldQueryData},
|
||||||
world::{FromWorld, World},
|
world::{FromWorld, World},
|
||||||
};
|
};
|
||||||
use downcast_rs::{impl_downcast, Downcast};
|
use downcast_rs::{impl_downcast, Downcast};
|
||||||
|
@ -342,7 +342,7 @@ impl Node for RunGraphOnViewNode {
|
||||||
pub trait ViewNode {
|
pub trait ViewNode {
|
||||||
/// The query that will be used on the view entity.
|
/// The query that will be used on the view entity.
|
||||||
/// It is guaranteed to run on the view entity, so there's no need for a filter
|
/// It is guaranteed to run on the view entity, so there's no need for a filter
|
||||||
type ViewQuery: ReadOnlyWorldQuery;
|
type ViewQuery: ReadOnlyWorldQueryData;
|
||||||
|
|
||||||
/// Updates internal node state using the current render [`World`] prior to the run method.
|
/// Updates internal node state using the current render [`World`] prior to the run method.
|
||||||
fn update(&mut self, _world: &mut World) {}
|
fn update(&mut self, _world: &mut World) {}
|
||||||
|
|
|
@ -2,7 +2,7 @@ use crate::render_phase::{PhaseItem, TrackedRenderPass};
|
||||||
use bevy_app::App;
|
use bevy_app::App;
|
||||||
use bevy_ecs::{
|
use bevy_ecs::{
|
||||||
entity::Entity,
|
entity::Entity,
|
||||||
query::{QueryState, ROQueryItem, ReadOnlyWorldQuery},
|
query::{QueryState, ROQueryItem, ReadOnlyWorldQueryData},
|
||||||
system::{ReadOnlySystemParam, Resource, SystemParam, SystemParamItem, SystemState},
|
system::{ReadOnlySystemParam, Resource, SystemParam, SystemParamItem, SystemState},
|
||||||
world::World,
|
world::World,
|
||||||
};
|
};
|
||||||
|
@ -179,12 +179,12 @@ pub trait RenderCommand<P: PhaseItem> {
|
||||||
/// The view entity refers to the camera, or shadow-casting light, etc. from which the phase
|
/// The view entity refers to the camera, or shadow-casting light, etc. from which the phase
|
||||||
/// item will be rendered from.
|
/// item will be rendered from.
|
||||||
/// All components have to be accessed read only.
|
/// All components have to be accessed read only.
|
||||||
type ViewWorldQuery: ReadOnlyWorldQuery;
|
type ViewWorldQuery: ReadOnlyWorldQueryData;
|
||||||
/// Specifies the ECS data of the item entity required by [`RenderCommand::render`].
|
/// Specifies the ECS data of the item entity required by [`RenderCommand::render`].
|
||||||
///
|
///
|
||||||
/// The item is the entity that will be rendered for the corresponding view.
|
/// The item is the entity that will be rendered for the corresponding view.
|
||||||
/// All components have to be accessed read only.
|
/// All components have to be accessed read only.
|
||||||
type ItemWorldQuery: ReadOnlyWorldQuery;
|
type ItemWorldQuery: ReadOnlyWorldQueryData;
|
||||||
|
|
||||||
/// Renders a [`PhaseItem`] by recording commands (e.g. setting pipelines, binding bind groups,
|
/// Renders a [`PhaseItem`] by recording commands (e.g. setting pipelines, binding bind groups,
|
||||||
/// issuing draw calls, etc.) via the [`TrackedRenderPass`].
|
/// issuing draw calls, etc.) via the [`TrackedRenderPass`].
|
||||||
|
|
|
@ -3,7 +3,7 @@ use bevy_ecs::{
|
||||||
change_detection::DetectChangesMut,
|
change_detection::DetectChangesMut,
|
||||||
entity::Entity,
|
entity::Entity,
|
||||||
prelude::{Component, With},
|
prelude::{Component, With},
|
||||||
query::WorldQuery,
|
query::WorldQueryData,
|
||||||
reflect::ReflectComponent,
|
reflect::ReflectComponent,
|
||||||
system::{Local, Query, Res},
|
system::{Local, Query, Res},
|
||||||
};
|
};
|
||||||
|
@ -105,8 +105,8 @@ pub struct State {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Main query for [`ui_focus_system`]
|
/// Main query for [`ui_focus_system`]
|
||||||
#[derive(WorldQuery)]
|
#[derive(WorldQueryData)]
|
||||||
#[world_query(mutable)]
|
#[world_query_data(mutable)]
|
||||||
pub struct NodeQuery {
|
pub struct NodeQuery {
|
||||||
entity: Entity,
|
entity: Entity,
|
||||||
node: &'static Node,
|
node: &'static Node,
|
||||||
|
|
|
@ -12,7 +12,10 @@
|
||||||
//!
|
//!
|
||||||
//! For more details on the `WorldQuery` derive macro, see the trait documentation.
|
//! For more details on the `WorldQuery` derive macro, see the trait documentation.
|
||||||
|
|
||||||
use bevy::{ecs::query::WorldQuery, prelude::*};
|
use bevy::{
|
||||||
|
ecs::query::{WorldQueryData, WorldQueryFilter},
|
||||||
|
prelude::*,
|
||||||
|
};
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -42,8 +45,8 @@ struct ComponentD;
|
||||||
#[derive(Component, Debug)]
|
#[derive(Component, Debug)]
|
||||||
struct ComponentZ;
|
struct ComponentZ;
|
||||||
|
|
||||||
#[derive(WorldQuery)]
|
#[derive(WorldQueryData)]
|
||||||
#[world_query(derive(Debug))]
|
#[world_query_data(derive(Debug))]
|
||||||
struct ReadOnlyCustomQuery<T: Component + Debug, P: Component + Debug> {
|
struct ReadOnlyCustomQuery<T: Component + Debug, P: Component + Debug> {
|
||||||
entity: Entity,
|
entity: Entity,
|
||||||
a: &'static ComponentA,
|
a: &'static ComponentA,
|
||||||
|
@ -76,8 +79,8 @@ fn print_components_read_only(
|
||||||
// suffix.
|
// suffix.
|
||||||
// Note: if you want to use derive macros with read-only query variants, you need to pass them with
|
// Note: if you want to use derive macros with read-only query variants, you need to pass them with
|
||||||
// using the `derive` attribute.
|
// using the `derive` attribute.
|
||||||
#[derive(WorldQuery)]
|
#[derive(WorldQueryData)]
|
||||||
#[world_query(mutable, derive(Debug))]
|
#[world_query_data(mutable, derive(Debug))]
|
||||||
struct CustomQuery<T: Component + Debug, P: Component + Debug> {
|
struct CustomQuery<T: Component + Debug, P: Component + Debug> {
|
||||||
entity: Entity,
|
entity: Entity,
|
||||||
a: &'static mut ComponentA,
|
a: &'static mut ComponentA,
|
||||||
|
@ -90,26 +93,26 @@ struct CustomQuery<T: Component + Debug, P: Component + Debug> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is a valid query as well, which would iterate over every entity.
|
// This is a valid query as well, which would iterate over every entity.
|
||||||
#[derive(WorldQuery)]
|
#[derive(WorldQueryData)]
|
||||||
#[world_query(derive(Debug))]
|
#[world_query_data(derive(Debug))]
|
||||||
struct EmptyQuery {
|
struct EmptyQuery {
|
||||||
empty: (),
|
empty: (),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(WorldQuery)]
|
#[derive(WorldQueryData)]
|
||||||
#[world_query(derive(Debug))]
|
#[world_query_data(derive(Debug))]
|
||||||
struct NestedQuery {
|
struct NestedQuery {
|
||||||
c: &'static ComponentC,
|
c: &'static ComponentC,
|
||||||
d: Option<&'static ComponentD>,
|
d: Option<&'static ComponentD>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(WorldQuery)]
|
#[derive(WorldQueryData)]
|
||||||
#[world_query(derive(Debug))]
|
#[world_query_data(derive(Debug))]
|
||||||
struct GenericQuery<T: Component, P: Component> {
|
struct GenericQuery<T: Component, P: Component> {
|
||||||
generic: (&'static T, &'static P),
|
generic: (&'static T, &'static P),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(WorldQuery)]
|
#[derive(WorldQueryFilter)]
|
||||||
struct QueryFilter<T: Component, P: Component> {
|
struct QueryFilter<T: Component, P: Component> {
|
||||||
_c: With<ComponentC>,
|
_c: With<ComponentC>,
|
||||||
_d: With<ComponentD>,
|
_d: With<ComponentD>,
|
||||||
|
|
Loading…
Reference in a new issue