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:
Mark Wainwright 2023-11-28 03:56:07 +00:00 committed by GitHub
parent 90958104cb
commit f0a8994f55
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
31 changed files with 1898 additions and 1321 deletions

View file

@ -1,6 +1,6 @@
use bevy_ecs::{
component::Component, entity::Entity, query::WorldQuery, reflect::ReflectComponent,
};
use bevy_ecs::query::WorldQueryData;
use bevy_ecs::{component::Component, entity::Entity, reflect::ReflectComponent};
use bevy_reflect::std_traits::ReflectDefault;
use bevy_reflect::Reflect;
use bevy_utils::AHasher;
@ -102,7 +102,7 @@ impl std::fmt::Debug for Name {
/// }
/// # bevy_ecs::system::assert_is_system(increment_score);
/// ```
#[derive(WorldQuery)]
#[derive(WorldQueryData)]
pub struct DebugName {
/// A [`Name`] that the entity might have that is displayed if available.
pub name: Option<&'static Name>,

View file

@ -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 })
}

View file

@ -1,10 +1,15 @@
extern crate proc_macro;
mod component;
mod fetch;
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 proc_macro::TokenStream;
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
#[proc_macro_derive(WorldQuery, attributes(world_query))]
pub fn derive_world_query(input: TokenStream) -> TokenStream {
derive_world_query_impl(input)
/// Implement `WorldQueryData` to use a struct as a data parameter in a query
#[proc_macro_derive(WorldQueryData, attributes(world_query_data))]
pub fn derive_world_query_data(input: TokenStream) -> TokenStream {
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`.

View 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))*
}
}
}
}

View 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 })
}

View 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;)*
}
};
})
}

View file

@ -64,7 +64,7 @@ mod tests {
change_detection::Ref,
component::{Component, ComponentId},
entity::Entity,
query::{Added, Changed, FilteredAccess, ReadOnlyWorldQuery, With, Without},
query::{Added, Changed, FilteredAccess, With, Without, WorldQueryFilter},
system::Resource,
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
.query_filtered::<Entity, F>()
.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
.query_filtered::<Entity, F>()
.iter(world)

View file

@ -3,11 +3,10 @@ use crate::{
change_detection::{Ticks, TicksMut},
component::{Component, ComponentId, ComponentStorage, StorageType, Tick},
entity::Entity,
query::{Access, DebugCheckedUnwrap, FilteredAccess},
query::{Access, DebugCheckedUnwrap, FilteredAccess, WorldQuery},
storage::{ComponentSparseSet, Table, TableRow},
world::{unsafe_world_cell::UnsafeWorldCell, EntityMut, EntityRef, Mut, Ref, World},
};
pub use bevy_ecs_macros::WorldQuery;
use bevy_ptr::{ThinSlicePtr, UnsafeCellDeref};
use bevy_utils::all_tuples;
use std::{cell::UnsafeCell, marker::PhantomData};
@ -18,18 +17,11 @@ use std::{cell::UnsafeCell, marker::PhantomData};
///
/// - **Component references.**
/// Fetches a component by reference (immutably or mutably).
/// - **`WorldQuery` tuples.**
/// If every element of a tuple implements `WorldQuery`, then the tuple itself also implements the same trait.
/// This enables a single `Query` to access multiple components and filter over multiple conditions.
/// - **`WorldQueryData` tuples.**
/// 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.
/// 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.
/// - **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`].**
/// Gets the identifier of the queried entity.
/// - **[`Option`].**
@ -40,13 +32,15 @@ use std::{cell::UnsafeCell, marker::PhantomData};
/// - **[`Ref`].**
/// 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.
/// - **[`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.
///
/// # Trait derivation
///
/// Query design can be easily structured by deriving `WorldQuery` for custom types.
/// Despite the added complexity, this approach has several advantages over using `WorldQuery` tuples.
/// Query design can be easily structured by deriving `WorldQueryData` for custom types.
/// Despite the added complexity, this approach has several advantages over using `WorldQueryData` tuples.
/// The most relevant improvements are:
///
/// - Reusability across multiple systems.
@ -55,18 +49,18 @@ use std::{cell::UnsafeCell, marker::PhantomData};
/// - Methods can be implemented for the query items.
/// - 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::query::WorldQuery;
/// use bevy_ecs::query::WorldQueryData;
/// #
/// # #[derive(Component)]
/// # struct ComponentA;
/// # #[derive(Component)]
/// # struct ComponentB;
///
/// #[derive(WorldQuery)]
/// #[derive(WorldQueryData)]
/// struct MyQuery {
/// entity: Entity,
/// // 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
///
/// 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
/// # use bevy_ecs::prelude::*;
/// # use bevy_ecs::query::WorldQuery;
/// # use bevy_ecs::query::WorldQueryData;
/// #
/// # #[derive(Component)]
/// # struct ComponentA;
/// #
/// #[derive(WorldQuery)]
/// #[derive(WorldQueryData)]
/// struct CustomQuery {
/// 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).
///
/// ```
/// # use bevy_ecs::prelude::*;
/// # use bevy_ecs::query::WorldQuery;
/// # use bevy_ecs::query::WorldQueryData;
/// #
/// # #[derive(Component)]
/// # struct ComponentA;
/// #
/// #[derive(WorldQuery)]
/// #[world_query(mutable)]
/// #[derive(WorldQueryData)]
/// #[world_query_data(mutable)]
/// struct CustomQuery {
/// component_a: &'static mut ComponentA,
/// }
@ -136,7 +130,7 @@ use std::{cell::UnsafeCell, marker::PhantomData};
///
/// ```
/// # use bevy_ecs::prelude::*;
/// # use bevy_ecs::query::WorldQuery;
/// # use bevy_ecs::query::WorldQueryData;
/// #
/// #[derive(Component)]
/// struct Health(f32);
@ -144,8 +138,8 @@ use std::{cell::UnsafeCell, marker::PhantomData};
/// #[derive(Component)]
/// struct Buff(f32);
///
/// #[derive(WorldQuery)]
/// #[world_query(mutable)]
/// #[derive(WorldQueryData)]
/// #[world_query_data(mutable)]
/// struct HealthQuery {
/// health: &'static mut Health,
/// buff: Option<&'static mut Buff>,
@ -185,19 +179,19 @@ use std::{cell::UnsafeCell, marker::PhantomData};
///
/// ## Deriving traits for query items
///
/// The `WorldQuery` 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.
/// 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_data(derive(...))]` attribute.
/// This will apply the listed derivable traits to the query item structs.
///
/// ```
/// # use bevy_ecs::prelude::*;
/// # use bevy_ecs::query::WorldQuery;
/// # use bevy_ecs::query::WorldQueryData;
/// #
/// # #[derive(Component, Debug)]
/// # struct ComponentA;
/// #
/// #[derive(WorldQuery)]
/// #[world_query(mutable, derive(Debug))]
/// #[derive(WorldQueryData)]
/// #[world_query_data(mutable, derive(Debug))]
/// struct CustomQuery {
/// component_a: &'static ComponentA,
/// }
@ -211,12 +205,12 @@ use std::{cell::UnsafeCell, marker::PhantomData};
///
/// ## Query composition
///
/// It is possible to use any `WorldQuery` as a field of another one.
/// This means that a `WorldQuery` can also be used as a subquery, potentially in multiple places.
/// It is possible to use any `WorldQueryData` as a field of another one.
/// This means that a `WorldQueryData` can also be used as a subquery, potentially in multiple places.
///
/// ```
/// # use bevy_ecs::prelude::*;
/// # use bevy_ecs::query::WorldQuery;
/// # use bevy_ecs::query::WorldQueryData;
/// #
/// # #[derive(Component)]
/// # struct ComponentA;
@ -225,62 +219,29 @@ use std::{cell::UnsafeCell, marker::PhantomData};
/// # #[derive(Component)]
/// # struct ComponentC;
/// #
/// #[derive(WorldQuery)]
/// #[derive(WorldQueryData)]
/// struct SubQuery {
/// component_a: &'static ComponentA,
/// component_b: &'static ComponentB,
/// }
///
/// #[derive(WorldQuery)]
/// #[derive(WorldQueryData)]
/// struct MyQuery {
/// subquery: SubQuery,
/// 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
///
/// 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.
///
/// ```
/// # use bevy_ecs::{prelude::*, query::WorldQuery};
/// # use bevy_ecs::{prelude::*, query::WorldQueryData};
/// # use std::marker::PhantomData;
/// #[derive(WorldQuery)]
/// #[derive(WorldQueryData)]
/// pub struct GenericQuery<T> {
/// id: Entity,
/// marker: PhantomData<T>,
@ -294,176 +255,31 @@ use std::{cell::UnsafeCell, marker::PhantomData};
/// Component access of `Self::ReadOnly` must be a subset of `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
/// [`ReadOnly`]: Self::ReadOnly
/// [`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 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;
pub unsafe trait WorldQueryData: WorldQuery {
/// The read-only variant of this [`WorldQueryData`], which satisfies the [`ReadOnlyWorldQueryData`] trait.
type ReadOnly: ReadOnlyWorldQueryData<State = <Self as WorldQuery>::State>;
}
/// A world query that is read only.
/// A [`WorldQueryData`] that is read only.
///
/// # Safety
///
/// This must only be implemented for read-only [`WorldQuery`]'s.
pub unsafe trait ReadOnlyWorldQuery: WorldQuery<ReadOnly = Self> {}
/// This must only be implemented for read-only [`WorldQueryData`]'s.
pub unsafe trait ReadOnlyWorldQueryData: WorldQueryData<ReadOnly = Self> {}
/// The item type returned when a [`WorldQuery`] is iterated over
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
pub type ROQueryItem<'w, Q> = QueryItem<'w, <Q as WorldQuery>::ReadOnly>;
/// 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 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 {
type Fetch<'w> = ();
type Item<'w> = Entity;
type ReadOnly = Self;
type State = ();
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_ARCHETYPAL: bool = true;
unsafe fn init_fetch<'w>(
_world: UnsafeWorldCell<'w>,
_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`
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 Item<'w> = EntityRef<'w>;
type ReadOnly = Self;
type State = ();
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_ARCHETYPAL: bool = true;
unsafe fn init_fetch<'w>(
world: UnsafeWorldCell<'w>,
_state: &Self::State,
@ -603,14 +422,18 @@ unsafe impl WorldQuery for EntityRef<'_> {
}
}
/// SAFETY: Access is read-only.
unsafe impl ReadOnlyWorldQuery for EntityRef<'_> {}
/// SAFETY: `Self` is the same as `Self::ReadOnly`
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`
unsafe impl<'a> WorldQuery for EntityMut<'a> {
type Fetch<'w> = UnsafeWorldCell<'w>;
type Item<'w> = EntityMut<'w>;
type ReadOnly = EntityRef<'a>;
type State = ();
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_ARCHETYPAL: bool = true;
unsafe fn init_fetch<'w>(
world: UnsafeWorldCell<'w>,
_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)]
pub struct ReadFetch<'w, T> {
// T::Storage = TableStorage
@ -698,11 +524,14 @@ impl<T> Clone 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 {
type Fetch<'w> = ReadFetch<'w, T>;
type Item<'w> = &'w T;
type ReadOnly = Self;
type State = ComponentId;
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]
unsafe fn init_fetch<'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
unsafe impl<T: Component> ReadOnlyWorldQuery for &T {}
unsafe impl<T: Component> ReadOnlyWorldQueryData for &T {}
#[doc(hidden)]
pub struct RefFetch<'w, T> {
@ -848,11 +680,14 @@ impl<T> Clone 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> {
type Fetch<'w> = RefFetch<'w, T>;
type Item<'w> = Ref<'w, T>;
type ReadOnly = Self;
type State = ComponentId;
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]
unsafe fn init_fetch<'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
unsafe impl<'__w, T: Component> ReadOnlyWorldQuery for Ref<'__w, T> {}
unsafe impl<'__w, T: Component> ReadOnlyWorldQueryData for Ref<'__w, T> {}
#[doc(hidden)]
pub struct WriteFetch<'w, T> {
@ -1009,11 +847,14 @@ impl<T> Clone 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 {
type Fetch<'w> = WriteFetch<'w, T>;
type Item<'w> = Mut<'w, T>;
type ReadOnly = &'__w T;
type State = ComponentId;
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]
unsafe fn init_fetch<'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)]
pub struct OptionFetch<'w, T: WorldQuery> {
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> {
type Fetch<'w> = OptionFetch<'w, T>;
type Item<'w> = Option<T::Item<'w>>;
type ReadOnly = Option<T::ReadOnly>;
type State = T::State;
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_ARCHETYPAL: bool = T::IS_ARCHETYPAL;
#[inline]
unsafe fn init_fetch<'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
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`.
///
@ -1315,11 +1164,12 @@ unsafe impl<T: ReadOnlyWorldQuery> ReadOnlyWorldQuery for Option<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> {
type Fetch<'w> = bool;
type Item<'w> = bool;
type ReadOnly = Self;
type State = ComponentId;
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]
unsafe fn init_fetch<'w>(
_world: UnsafeWorldCell<'w>,
@ -1393,105 +1241,14 @@ unsafe impl<T: Component> WorldQuery for Has<T> {
}
}
/// SAFETY: [`Has`] is read only
unsafe impl<T: Component> ReadOnlyWorldQuery for Has<T> {}
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: `Self` is the same as `Self::ReadOnly`
unsafe impl<T: Component> WorldQueryData for Has<T> {
type ReadOnly = Self;
}
/// 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.
///
/// `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`.
pub struct AnyOf<T>(PhantomData<T>);
macro_rules! impl_anytuple_fetch {
macro_rules! impl_tuple_world_query_data {
($(($name: ident, $state: ident)),*) => {
#[allow(non_snake_case)]
#[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,)*)> {
type Fetch<'w> = ($(($name::Fetch<'w>, bool),)*);
type Item<'w> = ($(Option<$name::Item<'w>>,)*);
type ReadOnly = AnyOf<($($name::ReadOnly,)*)>;
type State = ($($name::State,)*);
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_ARCHETYPAL: bool = true $(&& $name::IS_ARCHETYPAL)*;
#[inline]
unsafe fn set_archetype<'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
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);
/// [`WorldQuery`] used to nullify queries by turning `Query<Q>` into `Query<NopWorldQuery<Q>>`
///
/// 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`
unsafe impl<Q: WorldQuery> WorldQuery 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<Q: WorldQueryData> WorldQuery for NopWorldQuery<Q> {
type Fetch<'w> = ();
type Item<'w> = ();
type ReadOnly = Self;
type State = Q::State;
fn shrink<'wlong: 'wshort, 'wshort>(_: ()) {}
const IS_DENSE: bool = Q::IS_DENSE;
const IS_ARCHETYPAL: bool = true;
#[inline(always)]
unsafe fn init_fetch(
_world: UnsafeWorldCell,
@ -1685,14 +1466,21 @@ unsafe impl<Q: WorldQuery> WorldQuery for NopWorldQuery<Q> {
}
}
/// SAFETY: `NopFetch` never accesses any data
unsafe impl<Q: WorldQuery> ReadOnlyWorldQuery for NopWorldQuery<Q> {}
/// SAFETY: `Self::ReadOnly` is `Self`
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> {
type Item<'a> = ();
type Fetch<'a> = ();
type ReadOnly = Self;
type State = ();
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
// are stored in a Table (vacuous truth).
const IS_DENSE: bool = true;
// `PhantomData` matches every entity in each archetype.
const IS_ARCHETYPAL: bool = true;
unsafe fn set_archetype<'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.
unsafe impl<T: ?Sized> ReadOnlyWorldQuery for PhantomData<T> {}
unsafe impl<T: ?Sized> ReadOnlyWorldQueryData for PhantomData<T> {}
#[cfg(test)]
mod tests {
use bevy_ecs_macros::WorldQueryData;
use super::*;
use crate::{
self as bevy_ecs,
@ -1768,16 +1561,16 @@ mod tests {
// Tests that each variant of struct can be used as a `WorldQuery`.
#[test]
fn world_query_struct_variants() {
#[derive(WorldQuery)]
#[derive(WorldQueryData)]
pub struct NamedQuery {
id: Entity,
a: &'static A,
}
#[derive(WorldQuery)]
#[derive(WorldQueryData)]
pub struct TupleQuery(&'static A, &'static B);
#[derive(WorldQuery)]
#[derive(WorldQueryData)]
pub struct UnitQuery;
fn my_system(_: Query<(NamedQuery, TupleQuery, UnitQuery)>) {}
@ -1788,7 +1581,7 @@ mod tests {
// Compile test for https://github.com/bevyengine/bevy/pull/8030.
#[test]
fn world_query_phantom_data() {
#[derive(WorldQuery)]
#[derive(WorldQueryData)]
pub struct IgnoredQuery<Marker> {
id: Entity,
_marker: PhantomData<Marker>,
@ -1806,8 +1599,8 @@ mod tests {
mod private {
use super::*;
#[derive(WorldQuery)]
#[world_query(mutable)]
#[derive(WorldQueryData)]
#[world_query_data(mutable)]
pub struct Q {
pub a: &'static mut A,
}
@ -1831,7 +1624,7 @@ mod tests {
fn world_query_metadata_collision() {
// The metadata types generated would be named `ClientState` and `ClientFetch`,
// but they should rename themselves to avoid conflicts.
#[derive(WorldQuery)]
#[derive(WorldQueryData)]
pub struct Client<S: ClientState> {
pub state: &'static S,
pub fetch: &'static ClientFetch,

View file

@ -10,7 +10,92 @@ use bevy_ptr::{ThinSlicePtr, UnsafeCellDeref};
use bevy_utils::all_tuples;
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`.
///
@ -41,11 +126,14 @@ use super::ReadOnlyWorldQuery;
/// ```
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> {
type Fetch<'w> = ();
type Item<'w> = ();
type ReadOnly = Self;
type State = ComponentId;
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]
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
unsafe impl<T: Component> ReadOnlyWorldQuery for With<T> {}
impl<T: Component> WorldQueryFilter 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`.
///
@ -142,11 +238,14 @@ unsafe impl<T: Component> ReadOnlyWorldQuery for With<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> {
type Fetch<'w> = ();
type Item<'w> = ();
type ReadOnly = Self;
type State = ComponentId;
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]
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
unsafe impl<T: Component> ReadOnlyWorldQuery for Without<T> {}
impl<T: Component> WorldQueryFilter 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.
///
@ -269,11 +376,14 @@ macro_rules! impl_query_filter_tuple {
#[allow(unused_variables)]
#[allow(non_snake_case)]
#[allow(clippy::unused_unit)]
// SAFETY: defers to soundness of `$filter: WorldQuery` impl
unsafe impl<$($filter: WorldQuery),*> WorldQuery for Or<($($filter,)*)> {
/// 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` 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 Item<'w> = bool;
type ReadOnly = Or<($($filter::ReadOnly,)*)>;
type State = ($($filter::State,)*);
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_ARCHETYPAL: bool = true $(&& $filter::IS_ARCHETYPAL)*;
#[inline]
unsafe fn init_fetch<'w>(world: UnsafeWorldCell<'w>, state: &Self::State, last_run: Tick, this_run: Tick) -> Self::Fetch<'w> {
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)))*
}
#[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>) {
let ($($filter,)*) = state;
@ -376,129 +475,8 @@ macro_rules! impl_query_filter_tuple {
}
}
// SAFETY: filters are read only
unsafe impl<$($filter: ReadOnlyWorldQuery),*> ReadOnlyWorldQuery for Or<($($filter,)*)> {}
};
}
all_tuples!(impl_query_filter_tuple, 0, 15, F, S);
macro_rules! impl_tick_filter {
(
$(#[$meta:meta])*
$name: ident,
$(#[$fetch_meta:meta])*
$fetch_name: ident,
$get_slice: expr,
$get_sparse_set: expr
) => {
$(#[$meta])*
pub struct $name<T>(PhantomData<T>);
#[doc(hidden)]
#[derive(Clone)]
$(#[$fetch_meta])*
pub struct $fetch_name<'w> {
table_ticks: Option<ThinSlicePtr<'w, UnsafeCell<Tick>>>,
sparse_set: Option<&'w ComponentSparseSet>,
last_run: Tick,
this_run: Tick,
}
// SAFETY: `Self::ReadOnly` is the same as `Self`
unsafe impl<T: Component> WorldQuery for $name<T> {
type Fetch<'w> = $fetch_name<'w>;
type Item<'w> = bool;
type ReadOnly = Self;
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,
}
};
const IS_ARCHETYPAL: bool = false;
#[inline]
unsafe fn set_table<'w>(
fetch: &mut Self::Fetch<'w>,
&component_id: &ComponentId,
table: &'w Table
) {
fetch.table_ticks = Some(
$get_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();
$get_sparse_set(sparse_set, entity)
.debug_checked_unwrap()
.deref()
.is_newer_than(fetch.last_run, fetch.this_run)
}
}
}
impl<$($filter: WorldQueryFilter),*> WorldQueryFilter for Or<($($filter,)*)> {
const IS_ARCHETYPAL: bool = true $(&& $filter::IS_ARCHETYPAL)*;
#[inline(always)]
unsafe fn filter_fetch(
@ -508,141 +486,399 @@ macro_rules! impl_tick_filter {
) -> bool {
Self::fetch(fetch, entity, table_row)
}
#[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)
}
}
/// SAFETY: read-only access
unsafe impl<T: Component> ReadOnlyWorldQuery for $name<T> {}
};
}
impl_tick_filter!(
/// A filter on a component that only retains results added after the system last ran.
///
/// A common use for this filter is one-time initialization.
///
/// To retain all results without filtering but still check whether they were added after the
/// system last ran, use [`Ref<T>`](crate::change_detection::Ref).
///
/// # Deferred
///
/// 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
);
macro_rules! impl_tuple_world_query_filter {
($($name: ident),*) => {
#[allow(unused_variables)]
#[allow(non_snake_case)]
#[allow(clippy::unused_unit)]
impl_tick_filter!(
/// 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.
///
/// **Note** that simply *mutably dereferencing* a component is considered a change ([`DerefMut`](std::ops::DerefMut)).
/// Bevy does not compare components to their previous values.
///
/// 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).
///
/// # Deferred
///
/// Note, that entity modifications issued with [`Commands`](crate::system::Commands)
/// (like entity creation or entity component addition or removal)
/// 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::Changed;
/// # use bevy_ecs::system::IntoSystem;
/// # use bevy_ecs::system::Query;
/// #
/// # #[derive(Component, Debug)]
/// # struct Name {};
/// # #[derive(Component)]
/// # struct Transform {};
///
/// fn print_moving_objects_system(query: Query<&Name, Changed<Transform>>) {
/// for name in &query {
/// println!("Entity Moved: {:?}", name);
/// }
/// }
///
/// # bevy_ecs::system::assert_is_system(print_moving_objects_system);
/// ```
Changed,
ChangedFetch,
Column::get_changed_ticks_slice,
ComponentSparseSet::get_changed_tick
);
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);
/// A filter on a component that only retains results added after the system last ran.
///
/// A common use for this filter is one-time initialization.
///
/// To retain all results without filtering but still check whether they were added after the
/// system last ran, use [`Ref<T>`](crate::change_detection::Ref).
///
/// # Deferred
///
/// 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);
/// ```
pub struct Added<T>(PhantomData<T>);
#[doc(hidden)]
#[derive(Clone)]
pub struct AddedFetch<'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 Added<T> {
type Fetch<'w> = AddedFetch<'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_added_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_added_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 Added<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 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.
///
/// **Note** that simply *mutably dereferencing* a component is considered a change ([`DerefMut`](std::ops::DerefMut)).
/// Bevy does not compare components to their previous values.
///
/// 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).
///
/// # Deferred
///
/// Note, that entity modifications issued with [`Commands`](crate::system::Commands)
/// (like entity creation or entity component addition or removal)
/// 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::Changed;
/// # use bevy_ecs::system::IntoSystem;
/// # use bevy_ecs::system::Query;
/// #
/// # #[derive(Component, Debug)]
/// # struct Name {};
/// # #[derive(Component)]
/// # struct Transform {};
///
/// fn print_moving_objects_system(query: Query<&Name, Changed<Transform>>) {
/// for name in &query {
/// println!("Entity Moved: {:?}", name);
/// }
/// }
///
/// # bevy_ecs::system::assert_is_system(print_moving_objects_system);
/// ```
pub struct Changed<T>(PhantomData<T>);
#[doc(hidden)]
#[derive(Clone)]
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.
///
/// This is needed to implement [`ExactSizeIterator`] for
/// [`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.
/// [Tuples](prim@tuple) and [`Or`] filters are automatically implemented with the trait only if its containing types
/// also implement the same trait.
///
/// [`Added`] and [`Changed`] works with entities, and therefore are not archetypal. As such
/// they do not implement [`ArchetypeFilter`].
pub trait ArchetypeFilter {}
pub trait ArchetypeFilter: WorldQueryFilter {}
impl<T> ArchetypeFilter for With<T> {}
impl<T> ArchetypeFilter for Without<T> {}
impl<T: Component> ArchetypeFilter for With<T> {}
impl<T: Component> ArchetypeFilter for Without<T> {}
macro_rules! impl_archetype_filter_tuple {
($($filter: ident),*) => {

View file

@ -2,26 +2,26 @@ use crate::{
archetype::{ArchetypeEntity, ArchetypeId, Archetypes},
component::Tick,
entity::{Entities, Entity},
query::{ArchetypeFilter, DebugCheckedUnwrap, QueryState, WorldQuery},
query::{ArchetypeFilter, DebugCheckedUnwrap, QueryState},
storage::{TableId, TableRow, Tables},
world::unsafe_world_cell::UnsafeWorldCell,
};
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).
///
/// This struct is created by the [`Query::iter`](crate::system::Query::iter) and
/// [`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,
archetypes: &'w Archetypes,
query_state: &'s QueryState<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
/// - `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`.
@ -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>;
#[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>) {
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 };
(min_size, Some(max_size))
}
}
// 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.
///
@ -72,7 +72,7 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> FusedIterator for QueryIter<'
/// 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.
pub struct QueryManyIter<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery, I: Iterator>
pub struct QueryManyIter<'w, 's, Q: WorldQueryData, F: WorldQueryFilter, I: Iterator>
where
I::Item: Borrow<Entity>,
{
@ -85,7 +85,7 @@ where
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
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>
where
I::Item: Borrow<Entity>,
@ -202,7 +202,7 @@ where
}
// 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>
where
I::Item: Borrow<Entity>,
@ -272,14 +272,14 @@ where
/// [`Query`]: crate::system::Query
/// [`Query::iter_combinations`]: crate::system::Query::iter_combinations
/// [`Query::iter_combinations_mut`]: crate::system::Query::iter_combinations_mut
pub struct QueryCombinationIter<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery, const K: usize> {
pub struct QueryCombinationIter<'w, 's, Q: WorldQueryData, F: WorldQueryFilter, const K: usize> {
tables: &'w Tables,
archetypes: &'w Archetypes,
query_state: &'s QueryState<Q, F>,
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>
{
/// # 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.
// Doing so for mutable references would be unsound, because calling `next`
// 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>
{
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)?)
});
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 min_combinations = if archetype_query { known_max } else { 0 };
(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
F: ArchetypeFilter,
{
@ -439,12 +439,12 @@ where
}
// 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>
{
}
struct QueryIterationCursor<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> {
struct QueryIterationCursor<'w, 's, Q: WorldQueryData, F: WorldQueryFilter> {
table_id_iter: std::slice::Iter<'s, TableId>,
archetype_id_iter: std::slice::Iter<'s, ArchetypeId>,
table_entities: &'w [Entity],
@ -457,7 +457,7 @@ struct QueryIterationCursor<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> {
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 {
Self {
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;
unsafe fn init_empty(

View file

@ -7,14 +7,17 @@ mod filter;
mod iter;
mod par_iter;
mod state;
mod world_query;
pub use access::*;
pub use bevy_ecs_macros::{WorldQueryData, WorldQueryFilter};
pub use error::*;
pub use fetch::*;
pub use filter::*;
pub use iter::*;
pub use par_iter::*;
pub use state::*;
pub use world_query::*;
/// 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
@ -64,9 +67,10 @@ impl<T> DebugCheckedUnwrap for Option<T> {
#[cfg(test)]
mod tests {
use super::{ReadOnlyWorldQuery, WorldQuery};
use bevy_ecs_macros::{WorldQueryData, WorldQueryFilter};
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::system::{IntoSystem, Query, System, SystemState};
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)
where
Q: ReadOnlyWorldQuery,
F: ReadOnlyWorldQuery,
F::ReadOnly: ArchetypeFilter,
Q: ReadOnlyWorldQueryData,
F: ArchetypeFilter,
{
let mut query = world.query_filtered::<Q, F>();
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)
where
Q: ReadOnlyWorldQuery,
F: ReadOnlyWorldQuery,
F::ReadOnly: ArchetypeFilter,
Q: ReadOnlyWorldQueryData,
F: ArchetypeFilter,
{
let mut query = world.query_filtered::<Q, F>();
let query_type = type_name::<QueryState<Q, F>>();
@ -499,8 +501,8 @@ mod tests {
#[test]
#[should_panic = "&mut bevy_ecs::query::tests::A conflicts with a previous access in this query."]
fn self_conflicting_worldquery() {
#[derive(WorldQuery)]
#[world_query(mutable)]
#[derive(WorldQueryData)]
#[world_query_data(mutable)]
struct SelfConflicting {
a: &'static mut A,
b: &'static mut A,
@ -536,7 +538,7 @@ mod tests {
world.spawn_empty();
{
#[derive(WorldQuery)]
#[derive(WorldQueryData)]
struct CustomAB {
a: &'static A,
b: &'static B,
@ -556,7 +558,7 @@ mod tests {
}
{
#[derive(WorldQuery)]
#[derive(WorldQueryData)]
struct FancyParam {
e: Entity,
b: &'static B,
@ -577,11 +579,11 @@ mod tests {
}
{
#[derive(WorldQuery)]
#[derive(WorldQueryData)]
struct MaybeBSparse {
blah: Option<(&'static B, &'static Sparse)>,
}
#[derive(WorldQuery)]
#[derive(WorldQueryData)]
struct MatchEverything {
abcs: AnyOf<(&'static A, &'static B, &'static C)>,
opt_bsparse: MaybeBSparse,
@ -616,11 +618,11 @@ mod tests {
}
{
#[derive(WorldQuery)]
#[derive(WorldQueryFilter)]
struct AOrBFilter {
a: Or<(With<A>, With<B>)>,
}
#[derive(WorldQuery)]
#[derive(WorldQueryFilter)]
struct NoSparseThatsSlow {
no: Without<Sparse>,
}
@ -637,7 +639,7 @@ mod tests {
}
{
#[derive(WorldQuery)]
#[derive(WorldQueryFilter)]
struct CSparseFilter {
tuple_structs_pls: With<C>,
ugh: With<Sparse>,
@ -655,7 +657,7 @@ mod tests {
}
{
#[derive(WorldQuery)]
#[derive(WorldQueryFilter)]
struct WithoutComps {
_1: Without<A>,
_2: Without<B>,
@ -674,7 +676,7 @@ mod tests {
}
{
#[derive(WorldQuery)]
#[derive(WorldQueryData)]
struct IterCombAB {
a: &'static A,
b: &'static B,

View file

@ -1,7 +1,7 @@
use crate::{component::Tick, world::unsafe_world_cell::UnsafeWorldCell};
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
/// during iteration.
@ -82,7 +82,7 @@ impl BatchingStrategy {
///
/// 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.
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) state: &'s QueryState<Q, F>,
pub(crate) last_run: Tick,
@ -90,7 +90,7 @@ pub struct QueryParIter<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> {
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.
///
/// For more information on how this affects the resultant iteration, see

View file

@ -6,7 +6,7 @@ use crate::{
prelude::{Component, FromWorld},
query::{
Access, BatchingStrategy, DebugCheckedUnwrap, FilteredAccess, QueryCombinationIter,
QueryIter, QueryParIter, WorldQuery,
QueryIter, QueryParIter,
},
storage::{TableId, TableRow},
world::{unsafe_world_cell::UnsafeWorldCell, World, WorldId},
@ -18,15 +18,15 @@ use std::{any::TypeId, borrow::Borrow, fmt, mem::MaybeUninit};
use super::{
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)]
// SAFETY NOTE:
// 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.
pub struct QueryState<Q: WorldQuery, F: ReadOnlyWorldQuery = ()> {
pub struct QueryState<Q: WorldQueryData, F: WorldQueryFilter = ()> {
world_id: WorldId,
pub(crate) archetype_generation: ArchetypeGeneration,
pub(crate) matched_tables: FixedBitSet,
@ -43,7 +43,7 @@ pub struct QueryState<Q: WorldQuery, F: ReadOnlyWorldQuery = ()> {
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 {
f.debug_struct("QueryState")
.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 {
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.
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`
// 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
@ -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
/// `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<
NewQ: WorldQuery<State = Q::State>,
NewF: ReadOnlyWorldQuery<State = F::State>,
NewQ: WorldQueryData<State = Q::State>,
NewF: WorldQueryFilter<State = F::State>,
>(
&self,
) -> &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()`.
pub fn new(world: &mut World) -> Self {
let fetch_state = Q::init_state(world);
@ -162,7 +162,7 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
///
/// # 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`].
#[inline]
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.
#[inline]
pub fn iter<'w, 's>(
&'s mut self,
world: &'w World,
) -> QueryIter<'w, 's, Q::ReadOnly, F::ReadOnly> {
pub fn iter<'w, 's>(&'s mut self, world: &'w World) -> QueryIter<'w, 's, Q::ReadOnly, F> {
self.update_archetypes(world);
// SAFETY: query is read only
unsafe {
@ -733,10 +730,7 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
///
/// This can only be called for read-only queries.
#[inline]
pub fn iter_manual<'w, 's>(
&'s self,
world: &'w World,
) -> QueryIter<'w, 's, Q::ReadOnly, F::ReadOnly> {
pub fn iter_manual<'w, 's>(&'s self, world: &'w World) -> QueryIter<'w, 's, Q::ReadOnly, F> {
self.validate_world(world.id());
// SAFETY: query is read only and world is validated
unsafe {
@ -773,7 +767,7 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
pub fn iter_combinations<'w, 's, const K: usize>(
&'s mut self,
world: &'w World,
) -> QueryCombinationIter<'w, 's, Q::ReadOnly, F::ReadOnly, K> {
) -> QueryCombinationIter<'w, 's, Q::ReadOnly, F, K> {
self.update_archetypes(world);
// SAFETY: query is read only
unsafe {
@ -833,7 +827,7 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
&'s mut self,
world: &'w World,
entities: EntityList,
) -> QueryManyIter<'w, 's, Q::ReadOnly, F::ReadOnly, EntityList::IntoIter>
) -> QueryManyIter<'w, 's, Q::ReadOnly, F, EntityList::IntoIter>
where
EntityList::Item: Borrow<Entity>,
{
@ -868,7 +862,7 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
&'s self,
world: &'w World,
entities: EntityList,
) -> QueryManyIter<'w, 's, Q::ReadOnly, F::ReadOnly, EntityList::IntoIter>
) -> QueryManyIter<'w, 's, Q::ReadOnly, F, EntityList::IntoIter>
where
EntityList::Item: Borrow<Entity>,
{
@ -1072,7 +1066,7 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
pub fn par_iter<'w, 's>(
&'s mut self,
world: &'w World,
) -> QueryParIter<'w, 's, Q::ReadOnly, F::ReadOnly> {
) -> QueryParIter<'w, 's, Q::ReadOnly, F> {
self.update_archetypes(world);
QueryParIter {
world: world.as_unsafe_world_cell_readonly(),

View 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);

View file

@ -1,6 +1,6 @@
use crate::{
prelude::{FromWorld, QueryState},
query::{ReadOnlyWorldQuery, WorldQuery},
query::{WorldQueryData, WorldQueryFilter},
system::{Local, SystemMeta, SystemParam, SystemState},
world::World,
};
@ -29,7 +29,7 @@ pub trait ExclusiveSystemParam: Sized {
/// for a given [`ExclusiveSystemParam`].
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>
{
type State = QueryState<Q, F>;

View file

@ -3,8 +3,8 @@ use crate::{
entity::Entity,
query::{
BatchingStrategy, QueryCombinationIter, QueryComponentError, QueryEntityError, QueryIter,
QueryManyIter, QueryParIter, QuerySingleError, QueryState, ROQueryItem, ReadOnlyWorldQuery,
WorldQuery,
QueryManyIter, QueryParIter, QuerySingleError, QueryState, ROQueryItem,
ReadOnlyWorldQueryData, WorldQueryData, WorldQueryFilter,
},
world::{unsafe_world_cell::UnsafeWorldCell, Mut},
};
@ -16,13 +16,15 @@ use std::{any::TypeId, borrow::Borrow};
/// Its iterators and getter methods return *query items*.
/// 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).**
/// The type of data contained in the query item.
/// Only entities that match the requested data will generate an item.
/// Must implement the [`WorldQueryData`] trait.
/// - **`F` (query filter).**
/// A set of conditions that determines whether query items should be kept or discarded.
/// Must implement the [`WorldQueryFilter`] trait.
/// This type parameter is optional.
///
/// [`World`]: crate::world::World
@ -30,7 +32,7 @@ use std::{any::TypeId, borrow::Borrow};
/// # System parameter declaration
///
/// 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
///
@ -71,7 +73,7 @@ use std::{any::TypeId, borrow::Borrow};
/// # bevy_ecs::system::assert_is_system(system);
/// ```
///
/// ## `WorldQuery` tuples
/// ## `WorldQueryData` or `WorldQueryFilter` tuples
///
/// Using tuples, each `Query` type parameter can contain multiple elements.
///
@ -323,7 +325,7 @@ use std::{any::TypeId, borrow::Borrow};
/// [`Table`]: crate::storage::Table
/// [`With`]: crate::query::With
/// [`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`.
world: UnsafeWorldCell<'world>,
state: &'state QueryState<Q, F>,
@ -337,7 +339,7 @@ pub struct Query<'world, 'state, Q: WorldQuery, F: ReadOnlyWorldQuery = ()> {
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 {
f.debug_struct("Query")
.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.
///
/// # 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>>`.
/// This can be useful when working around the borrow checker,
/// 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();
// SAFETY: This is memory safe because it turns the query immutable.
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.
/// - [`for_each`](Self::for_each) for the closure based alternative.
#[inline]
pub fn iter(&self) -> QueryIter<'_, 's, Q::ReadOnly, F::ReadOnly> {
pub fn iter(&self) -> QueryIter<'_, 's, Q::ReadOnly, F> {
// SAFETY:
// - `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.
@ -491,7 +493,7 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
#[inline]
pub fn iter_combinations<const K: usize>(
&self,
) -> QueryCombinationIter<'_, 's, Q::ReadOnly, F::ReadOnly, K> {
) -> QueryCombinationIter<'_, 's, Q::ReadOnly, F, K> {
// SAFETY:
// - `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.
@ -574,7 +576,7 @@ impl<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery> Query<'w, 's, Q, F> {
pub fn iter_many<EntityList: IntoIterator>(
&self,
entities: EntityList,
) -> QueryManyIter<'_, 's, Q::ReadOnly, F::ReadOnly, EntityList::IntoIter>
) -> QueryManyIter<'_, 's, Q::ReadOnly, F, EntityList::IntoIter>
where
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
/// [`World`]: crate::world::World
#[inline]
pub fn par_iter(&self) -> QueryParIter<'_, '_, Q::ReadOnly, F::ReadOnly> {
pub fn par_iter(&self) -> QueryParIter<'_, '_, Q::ReadOnly, F> {
QueryParIter {
world: self.world,
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 IntoIter = QueryIter<'w, 's, Q::ReadOnly, F::ReadOnly>;
type IntoIter = QueryIter<'w, 's, Q::ReadOnly, F>;
fn into_iter(self) -> Self::IntoIter {
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 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.
///
/// 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);
/// ```
#[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.
// same-system queries have runtime borrow checks when they conflict
unsafe {

View file

@ -6,7 +6,8 @@ use crate::{
component::{ComponentId, ComponentTicks, Components, Tick},
entity::Entities,
query::{
Access, FilteredAccess, FilteredAccessSet, QueryState, ReadOnlyWorldQuery, WorldQuery,
Access, FilteredAccess, FilteredAccessSet, QueryState, ReadOnlyWorldQueryData,
WorldQueryData, WorldQueryFilter,
},
system::{Query, SystemMeta},
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>;
// 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>
{
}
// SAFETY: Relevant query ComponentId and ArchetypeComponentId access is applied to SystemMeta. If
// 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>
{
type State = QueryState<Q, F>;
@ -1557,7 +1558,6 @@ mod tests {
use super::*;
use crate::{
self as bevy_ecs, // Necessary for the `SystemParam` Derive when used inside `bevy_ecs`.
query::{ReadOnlyWorldQuery, WorldQuery},
system::{assert_is_system, Query},
};
use std::{cell::RefCell, marker::PhantomData};
@ -1569,8 +1569,8 @@ mod tests {
pub struct SpecialQuery<
'w,
's,
Q: WorldQuery + Send + Sync + 'static,
F: ReadOnlyWorldQuery + Send + Sync + 'static = (),
Q: WorldQueryData + Send + Sync + 'static,
F: WorldQueryFilter + Send + Sync + 'static = (),
> {
_query: Query<'w, 's, Q, F>,
}
@ -1691,7 +1691,7 @@ mod tests {
#[derive(SystemParam)]
pub struct WhereParam<'w, 's, Q>
where
Q: 'static + WorldQuery,
Q: 'static + WorldQueryData,
{
_q: Query<'w, 's, Q, ()>,
}

View file

@ -18,7 +18,7 @@ use crate::{
component::{Component, ComponentDescriptor, ComponentId, ComponentInfo, Components, Tick},
entity::{AllocAtWithoutReplacement, Entities, Entity, EntityLocation},
event::{Event, EventId, Events, SendBatchIds},
query::{DebugCheckedUnwrap, QueryEntityError, QueryState, ReadOnlyWorldQuery, WorldQuery},
query::{DebugCheckedUnwrap, QueryEntityError, QueryState, WorldQueryData, WorldQueryFilter},
removal_detection::RemovedComponentEvents,
schedule::{Schedule, ScheduleLabel, Schedules},
storage::{ResourceData, Storages},
@ -922,7 +922,7 @@ impl World {
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`].
/// ```
/// use bevy_ecs::{component::Component, entity::Entity, world::World};
@ -985,11 +985,11 @@ impl World {
/// ]);
/// ```
#[inline]
pub fn query<Q: WorldQuery>(&mut self) -> QueryState<Q, ()> {
pub fn query<Q: WorldQueryData>(&mut self) -> QueryState<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`].
/// ```
/// use bevy_ecs::{component::Component, entity::Entity, world::World, query::With};
@ -1009,7 +1009,7 @@ impl World {
/// assert_eq!(matching_entities, vec![e2]);
/// ```
#[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)
}

View file

@ -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
|
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
|
= help: the following other types implement trait `ReadOnlyWorldQuery`:
= help: the following other types implement trait `ReadOnlyWorldQueryData`:
bevy_ecs::change_detection::Ref<'__w, T>
Has<T>
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, F4)>
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 by a bound in `is_iterator`
--> tests/ui/query_iter_combinations_mut_iterator_safety.rs:13:19

View file

@ -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
|
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
|
= help: the following other types implement trait `ReadOnlyWorldQuery`:
= help: the following other types implement trait `ReadOnlyWorldQueryData`:
bevy_ecs::change_detection::Ref<'__w, T>
Has<T>
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, F4)>
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 by a bound in `is_iterator`
--> tests/ui/query_iter_many_mut_iterator_safety.rs:13:19

View file

@ -6,13 +6,13 @@ warning: unused import: `SystemState`
|
= 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
|
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>
Has<T>
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, F4)>
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: 1 redundant requirement hidden
= note: required for `Mutable<'_, '_>` to implement `ReadOnlySystemParam`

View file

@ -1,21 +1,21 @@
use bevy_ecs::prelude::*;
use bevy_ecs::query::WorldQuery;
use bevy_ecs::query::WorldQueryData;
#[derive(Component)]
struct Foo;
#[derive(WorldQuery)]
#[derive(WorldQueryData)]
struct MutableUnmarked {
a: &'static mut Foo,
}
#[derive(WorldQuery)]
#[world_query(mutable)]
#[derive(WorldQueryData)]
#[world_query_data(mutable)]
struct MutableMarked {
a: &'static mut Foo,
}
#[derive(WorldQuery)]
#[derive(WorldQueryData)]
struct NestedMutableUnmarked {
a: MutableMarked,
}

View file

@ -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
|
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
MutableMarkedReadOnly
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`
--> tests/ui/world_query_derive.rs:7:10
|
7 | #[derive(WorldQuery)]
| ^^^^^^^^^^ 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)
7 | #[derive(WorldQueryData)]
| ^^^^^^^^^^^^^^ required by this bound in `assert_readonly`
= 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
|
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
MutableMarkedReadOnly
NestedMutableUnmarked
@ -40,6 +40,6 @@ error[E0277]: the trait bound `MutableMarked: ReadOnlyWorldQuery` is not satisfi
note: required by a bound in `_::assert_readonly`
--> tests/ui/world_query_derive.rs:18:10
|
18 | #[derive(WorldQuery)]
| ^^^^^^^^^^ 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)
18 | #[derive(WorldQueryData)]
| ^^^^^^^^^^^^^^ required by this bound in `assert_readonly`
= note: this error originates in the derive macro `WorldQueryData` (in Nightly builds, run with -Z macro-backtrace for more info)

View file

@ -2,14 +2,14 @@ use std::collections::VecDeque;
use bevy_ecs::{
entity::Entity,
query::{ReadOnlyWorldQuery, WorldQuery},
query::{WorldQuery, WorldQueryData, WorldQueryFilter},
system::Query,
};
use crate::{Children, Parent};
/// 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.
///
/// 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>;
}
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>
{
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`].
///
/// Traverses the hierarchy breadth-first.
pub struct DescendantIter<'w, 's, Q: WorldQuery, F: ReadOnlyWorldQuery>
pub struct DescendantIter<'w, 's, Q: WorldQueryData, F: WorldQueryFilter>
where
Q::ReadOnly: WorldQuery<Item<'w> = &'w Children>,
{
@ -86,7 +86,7 @@ where
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
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
Q::ReadOnly: WorldQuery<Item<'w> = &'w Children>,
{
@ -122,7 +122,7 @@ where
}
/// 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
Q::ReadOnly: WorldQuery<Item<'w> = &'w Parent>,
{
@ -130,7 +130,7 @@ where
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
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
Q::ReadOnly: WorldQuery<Item<'w> = &'w Parent>,
{

View file

@ -1,7 +1,7 @@
use bevy_ecs::{
component::Component,
prelude::Res,
query::{QueryItem, ReadOnlyWorldQuery},
query::{QueryItem, ReadOnlyWorldQueryData, WorldQueryFilter},
system::{Query, ResMut, StaticSystemParam, SystemParam, SystemParamItem},
};
use bevy_utils::nonmax::NonMaxU32;
@ -57,8 +57,8 @@ impl<T: PartialEq> BatchMeta<T> {
/// items.
pub trait GetBatchData {
type Param: SystemParam + 'static;
type Query: ReadOnlyWorldQuery;
type QueryFilter: ReadOnlyWorldQuery;
type Query: ReadOnlyWorldQueryData;
type QueryFilter: WorldQueryFilter;
/// Data used for comparison between phase items. If the pipeline id, draw
/// function id, per-instance data buffer dynamic offset and this data
/// matches, the draws can be batched.

View file

@ -9,7 +9,7 @@ use bevy_asset::{Asset, Handle};
use bevy_ecs::{
component::Component,
prelude::*,
query::{QueryItem, ReadOnlyWorldQuery, WorldQuery},
query::{QueryItem, ReadOnlyWorldQueryData, WorldQueryFilter},
system::lifetimeless::Read,
};
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"
/// in the [`ExtractSchedule`] step.
pub trait ExtractComponent: Component {
/// ECS [`WorldQuery`] to fetch the components to extract.
type Query: WorldQuery + ReadOnlyWorldQuery;
/// ECS [`ReadOnlyWorldQueryData`] to fetch the components to extract.
type Query: ReadOnlyWorldQueryData;
/// Filters the entities with additional constraints.
type Filter: WorldQuery + ReadOnlyWorldQuery;
type Filter: WorldQueryFilter;
/// The output from extraction.
///

View file

@ -11,7 +11,7 @@ use bevy_asset::{Asset, AssetId, Handle};
use bevy_derive::{Deref, DerefMut};
use bevy_ecs::{
prelude::Entity,
query::{QueryItem, ReadOnlyWorldQuery, WorldQuery},
query::{QueryItem, ReadOnlyWorldQueryData, WorldQueryFilter},
system::{lifetimeless::Read, Query, ResMut, Resource},
};
use bevy_utils::EntityHashMap;
@ -28,10 +28,10 @@ use crate::{prelude::ViewVisibility, Extract, ExtractSchedule, RenderApp};
/// [`ExtractComponent`](crate::extract_component::ExtractComponent), but
/// higher-performance because it avoids the ECS overhead.
pub trait ExtractInstance: Send + Sync + Sized + 'static {
/// ECS [`WorldQuery`] to fetch the components to extract.
type Query: WorldQuery + ReadOnlyWorldQuery;
/// ECS [`ReadOnlyWorldQueryData`] to fetch the components to extract.
type Query: ReadOnlyWorldQueryData;
/// Filters the entities with additional constraints.
type Filter: WorldQuery + ReadOnlyWorldQuery;
type Filter: WorldQueryFilter;
/// Defines how the component is transferred into the "render world".
fn extract(item: QueryItem<'_, Self::Query>) -> Option<Self>;

View file

@ -7,7 +7,7 @@ use crate::{
renderer::RenderContext,
};
use bevy_ecs::{
query::{QueryItem, QueryState, ReadOnlyWorldQuery},
query::{QueryItem, QueryState, ReadOnlyWorldQueryData},
world::{FromWorld, World},
};
use downcast_rs::{impl_downcast, Downcast};
@ -342,7 +342,7 @@ impl Node for RunGraphOnViewNode {
pub trait ViewNode {
/// 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
type ViewQuery: ReadOnlyWorldQuery;
type ViewQuery: ReadOnlyWorldQueryData;
/// Updates internal node state using the current render [`World`] prior to the run method.
fn update(&mut self, _world: &mut World) {}

View file

@ -2,7 +2,7 @@ use crate::render_phase::{PhaseItem, TrackedRenderPass};
use bevy_app::App;
use bevy_ecs::{
entity::Entity,
query::{QueryState, ROQueryItem, ReadOnlyWorldQuery},
query::{QueryState, ROQueryItem, ReadOnlyWorldQueryData},
system::{ReadOnlySystemParam, Resource, SystemParam, SystemParamItem, SystemState},
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
/// item will be rendered from.
/// 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`].
///
/// The item is the entity that will be rendered for the corresponding view.
/// 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,
/// issuing draw calls, etc.) via the [`TrackedRenderPass`].

View file

@ -3,7 +3,7 @@ use bevy_ecs::{
change_detection::DetectChangesMut,
entity::Entity,
prelude::{Component, With},
query::WorldQuery,
query::WorldQueryData,
reflect::ReflectComponent,
system::{Local, Query, Res},
};
@ -105,8 +105,8 @@ pub struct State {
}
/// Main query for [`ui_focus_system`]
#[derive(WorldQuery)]
#[world_query(mutable)]
#[derive(WorldQueryData)]
#[world_query_data(mutable)]
pub struct NodeQuery {
entity: Entity,
node: &'static Node,

View file

@ -12,7 +12,10 @@
//!
//! 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;
fn main() {
@ -42,8 +45,8 @@ struct ComponentD;
#[derive(Component, Debug)]
struct ComponentZ;
#[derive(WorldQuery)]
#[world_query(derive(Debug))]
#[derive(WorldQueryData)]
#[world_query_data(derive(Debug))]
struct ReadOnlyCustomQuery<T: Component + Debug, P: Component + Debug> {
entity: Entity,
a: &'static ComponentA,
@ -76,8 +79,8 @@ fn print_components_read_only(
// suffix.
// Note: if you want to use derive macros with read-only query variants, you need to pass them with
// using the `derive` attribute.
#[derive(WorldQuery)]
#[world_query(mutable, derive(Debug))]
#[derive(WorldQueryData)]
#[world_query_data(mutable, derive(Debug))]
struct CustomQuery<T: Component + Debug, P: Component + Debug> {
entity: Entity,
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.
#[derive(WorldQuery)]
#[world_query(derive(Debug))]
#[derive(WorldQueryData)]
#[world_query_data(derive(Debug))]
struct EmptyQuery {
empty: (),
}
#[derive(WorldQuery)]
#[world_query(derive(Debug))]
#[derive(WorldQueryData)]
#[world_query_data(derive(Debug))]
struct NestedQuery {
c: &'static ComponentC,
d: Option<&'static ComponentD>,
}
#[derive(WorldQuery)]
#[world_query(derive(Debug))]
#[derive(WorldQueryData)]
#[world_query_data(derive(Debug))]
struct GenericQuery<T: Component, P: Component> {
generic: (&'static T, &'static P),
}
#[derive(WorldQuery)]
#[derive(WorldQueryFilter)]
struct QueryFilter<T: Component, P: Component> {
_c: With<ComponentC>,
_d: With<ComponentD>,