diff --git a/crates/bevy_ecs/src/system/query.rs b/crates/bevy_ecs/src/system/query.rs index ad6dcc02f1b45a..a112b31a768a55 100644 --- a/crates/bevy_ecs/src/system/query.rs +++ b/crates/bevy_ecs/src/system/query.rs @@ -9,95 +9,70 @@ use crate::{ }; use std::{any::TypeId, borrow::Borrow, fmt::Debug}; -/// Provides scoped access to components in a [`World`]. +/// [System parameter] that provides selective access to the [`Component`] data stored in a [`World`]. /// -/// Queries enable iteration over entities and their components as well as filtering them -/// on certain conditions. A query matches its parameters against the world to produce a series -/// of results. Each *query result* is a tuple of components (the same components defined -/// in the query) that belong to the same entity. +/// Enables access to [entity identifiers] and [components] from a system, without the need to directly access the world. +/// Its iterators and getter methods return *query items*. +/// Each query item is a type containing data relative to an entity. /// -/// Computational cost of queries is reduced by the fact that they have an internal archetype -/// cache to avoid re-computing archetype matches on each query access. +/// `Query` is a generic data structure that accepts two type parameters, both of which must implement the [`WorldQuery`] trait: /// -/// Query functionality is based on the [`WorldQuery`] trait. Both tuples of components -/// (up to 16 elements) and query filters implement this trait. +/// - **`Q` (query fetch).** +/// The type of data contained in the query item. +/// Only entities that match the requested data will generate an item. +/// - **`F` (query filter).** +/// A set of conditions that determines whether query items should be kept or discarded. +/// This type parameter is optional. /// -/// `Query` accepts two type parameters: +/// # System parameter declaration /// -/// 1. **Component access:** the components that an entity must have at the same time to yield -/// a query result. -/// 2. **Query filters (optional):** a predicate that ignores query results that don't match -/// its conditions. +/// 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. /// -/// # Usage as system parameter +/// ## Component access /// -/// A query is defined by declaring it as a system parameter. This section shows the various -/// use cases of `Query` as a system parameter. -/// -/// ## Immutable component access -/// -/// The following example defines a query that gives an iterator over `(&ComponentA, &ComponentB)` -/// tuples, where `ComponentA` and `ComponentB` belong to the same entity. Accessing components -/// immutably helps system parallelization. +/// A query defined with a reference to a component as the query fetch type parameter can be used to generate items that refer to the data of said component. /// /// ``` -/// # use bevy_ecs::component::Component; -/// # use bevy_ecs::system::IntoSystem; -/// # use bevy_ecs::system::Query; +/// # use bevy_ecs::prelude::*; /// # #[derive(Component)] /// # struct ComponentA; -/// # #[derive(Component)] -/// # struct ComponentB; -/// # fn system( -/// query: Query<(&ComponentA, &ComponentB)> +/// # fn immutable_ref( +/// // A component can be accessed by shared reference... +/// query: Query<&ComponentA> /// # ) {} -/// # bevy_ecs::system::assert_is_system(system); -/// ``` +/// # bevy_ecs::system::assert_is_system(immutable_ref); /// -/// You can use the [`ReadOnlyWorldQuery`] trait to abstract over read only query generics: -/// ``` -/// # use bevy_ecs::system::Query; -/// # use bevy_ecs::query::{QueryItem, ReadOnlyWorldQuery}; -/// fn system( -/// query: Query, -/// ) { -/// let _: Option> = query.iter().next(); -/// } +/// # fn mutable_ref( +/// // ... or by mutable reference. +/// query: Query<&mut ComponentA> +/// # ) {} +/// # bevy_ecs::system::assert_is_system(mutable_ref); /// ``` /// -/// ## Mutable component access +/// ## Query filtering /// -/// The following example is similar to the previous one, with the exception of `ComponentA` -/// being accessed mutably here. Note that both mutable and immutable accesses are allowed -/// in the same query. +/// Setting the query filter type parameter will ensure that each query item satisfies the given condition. /// /// ``` -/// # use bevy_ecs::component::Component; -/// # use bevy_ecs::system::IntoSystem; -/// # use bevy_ecs::system::Query; +/// # use bevy_ecs::prelude::*; /// # #[derive(Component)] /// # struct ComponentA; /// # #[derive(Component)] /// # struct ComponentB; /// # fn system( -/// // `ComponentA` is accessed mutably, while `ComponentB` is accessed immutably. -/// mut query: Query<(&mut ComponentA, &ComponentB)> +/// // Just `ComponentA` data will be accessed, but only for entities that also contain +/// // `ComponentB`. +/// query: Query<&ComponentA, With> /// # ) {} /// # bevy_ecs::system::assert_is_system(system); /// ``` /// -/// Two systems cannot be executed in parallel if both access a certain component and -/// at least one of the accesses is mutable, unless the schedule can verify that no entity -/// could be found in both queries, as otherwise Rusts mutability Rules would be broken. +/// ## `WorldQuery` tuples /// -/// Similarly, a system cannot contain two queries that would break Rust's mutability Rules. -/// If you need such Queries, you can use Filters to make the Queries disjoint or use a -/// [`ParamSet`](super::ParamSet). +/// Using tuples, each `Query` type parameter can contain multiple elements. /// -/// ## Entity ID access -/// -/// Inserting [`Entity`](crate::entity::Entity) at any position in the type parameter tuple -/// will give access to the entity ID. +/// In the following example, two components are accessed simultaneously, and the query items are filtered on two conditions. /// /// ``` /// # use bevy_ecs::prelude::*; @@ -105,33 +80,35 @@ use std::{any::TypeId, borrow::Borrow, fmt::Debug}; /// # struct ComponentA; /// # #[derive(Component)] /// # struct ComponentB; -/// # fn system( -/// query: Query<(Entity, &ComponentA, &ComponentB)> +/// # #[derive(Component)] +/// # struct ComponentC; +/// # #[derive(Component)] +/// # struct ComponentD; +/// # fn immutable_ref( +/// query: Query<(&ComponentA, &ComponentB), (With, Without)> /// # ) {} -/// # bevy_ecs::system::assert_is_system(system); +/// # bevy_ecs::system::assert_is_system(immutable_ref); /// ``` /// -/// ## Query filtering +/// ## Entity identifier access /// -/// The second, optional type parameter of query, is used for filters can be added to filter -/// out the query results that don't satisfy the given condition. +/// The identifier of an entity can be made available inside the query item by including [`Entity`] in the query fetch type parameter. /// /// ``` /// # use bevy_ecs::prelude::*; /// # #[derive(Component)] /// # struct ComponentA; -/// # #[derive(Component)] -/// # struct ComponentB; -/// # #[derive(Component)] -/// # struct ComponentC; /// # fn system( -/// // `ComponentC` data won't be accessed, but only entities that contain it will be queried. -/// query: Query<(&ComponentA, &ComponentB), With> +/// query: Query<(Entity, &ComponentA)> /// # ) {} /// # bevy_ecs::system::assert_is_system(system); /// ``` /// -/// If you need to apply more filters in a single query, group them into a tuple: +/// ## Optional component access +/// +/// A component can be made optional in a query by wrapping it into an [`Option`]. +/// In this way, a query item can still be generated even if the queried entity does not contain the wrapped component. +/// In this case, its corresponding value will be `None`. /// /// ``` /// # use bevy_ecs::prelude::*; @@ -139,116 +116,163 @@ use std::{any::TypeId, borrow::Borrow, fmt::Debug}; /// # struct ComponentA; /// # #[derive(Component)] /// # struct ComponentB; -/// # #[derive(Component)] -/// # struct ComponentC; /// # fn system( -/// // Similar to the previous query, but with the addition of a `Changed` filter. -/// query: Query<(&ComponentA, &ComponentB), (With, Changed)> +/// // Generates items for entities that contain `ComponentA`, and optionally `ComponentB`. +/// query: Query<(&ComponentA, Option<&ComponentB>)> /// # ) {} /// # bevy_ecs::system::assert_is_system(system); /// ``` /// -/// The following list contains all the available query filters: +/// See the documentation for [`AnyOf`] to idiomatically declare many optional components. /// -/// - [`Added`](crate::query::Added) -/// - [`Changed`](crate::query::Changed) -/// - [`With`](crate::query::With) -/// - [`Without`](crate::query::Without) -/// - [`Or`](crate::query::Or) +/// See the [performance] section to learn more about the impact of optional components. /// -/// ## Optional component access +/// ## Disjoint queries /// -/// A component can be made optional in a query by wrapping it into an [`Option`]. In the -/// following example, the query will iterate over components of both entities that contain -/// `ComponentA` and `ComponentB`, and entities that contain `ComponentA` but not `ComponentB`. +/// A system cannot contain two queries that break Rust's mutability rules. +/// In this case, the [`Without`] filter can be used to disjoint them. /// -/// ``` +/// In the following example, two queries mutably access the same component. +/// Executing this system will panic, since an entity could potentially match the two queries at the same time by having both `Player` and `Enemy` components. +/// This would violate mutability rules. +/// +/// ```should_panic /// # use bevy_ecs::prelude::*; /// # #[derive(Component)] -/// # struct ComponentA; +/// # struct Health; /// # #[derive(Component)] -/// # struct ComponentB; -/// # fn system( -/// query: Query<(&ComponentA, Option<&ComponentB>)> -/// # ) {} -/// # bevy_ecs::system::assert_is_system(system); +/// # struct Player; +/// # #[derive(Component)] +/// # struct Enemy; +/// # +/// fn randomize_health( +/// player_query: Query<&mut Health, With>, +/// enemy_query: Query<&mut Health, With>, +/// ) +/// # {} +/// # let mut randomize_health_system = bevy_ecs::system::IntoSystem::into_system(randomize_health); +/// # let mut world = World::new(); +/// # randomize_health_system.initialize(&mut world); +/// # randomize_health_system.run((), &mut world); /// ``` /// -/// If an entity does not contain a component, its corresponding query result value will be -/// `None`. Optional components increase the number of entities a query has to match against, -/// therefore they can hurt iteration performance, especially in the worst case scenario where -/// the query solely consists of only optional components, since all entities will be iterated -/// over. -/// -/// ## Single component access -/// -/// If just a single component needs to be accessed, using a tuple as the first type parameter -/// of `Query` can be omitted. +/// Adding a `Without` filter will disjoint the queries. +/// In this way, any entity that has both `Player` and `Enemy` components is excluded from both queries. /// /// ``` /// # use bevy_ecs::prelude::*; /// # #[derive(Component)] -/// # struct MyComponent; -/// # fn tuple_system( -/// // This is correct, but can be avoided. -/// query: Query<(&MyComponent,)> -/// # ) {} -/// # bevy_ecs::system::assert_is_system(tuple_system); -/// -/// # fn non_tuple_system( -/// // This is the preferred method. -/// query: Query<&MyComponent> -/// # ) {} -/// # bevy_ecs::system::assert_is_system(non_tuple_system); +/// # struct Health; +/// # #[derive(Component)] +/// # struct Player; +/// # #[derive(Component)] +/// # struct Enemy; +/// # +/// fn randomize_health( +/// player_query: Query<&mut Health, (With, Without)>, +/// enemy_query: Query<&mut Health, (With, Without)>, +/// ) +/// # {} +/// # let mut randomize_health_system = bevy_ecs::system::IntoSystem::into_system(randomize_health); +/// # let mut world = World::new(); +/// # randomize_health_system.initialize(&mut world); +/// # randomize_health_system.run((), &mut world); /// ``` /// -/// # Usage of query results +/// An alternative to this idiom is to wrap the conflicting queries into a [`ParamSet`](super::ParamSet). /// -/// Inside the body of the system function, the `Query` is available as a function parameter. -/// This section shows various methods to access query results. +/// # Accessing query items /// -/// ## Iteration over every query result +/// The following table summarizes the behavior of the safe methods that can be used to get query items. /// -/// The [`iter`](Self::iter) and [`iter_mut`](Self::iter_mut) methods are used to iterate -/// over every query result. Refer to the -/// [`Iterator` API docs](https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html) -/// for advanced iterator usage. +/// |Query methods|Effect| +/// |:---:|---| +/// |[`iter`]\([`_mut`][`iter_mut`])|Returns an iterator over all query items.| +/// |[`for_each`]\([`_mut`][`for_each_mut`]),
[`par_for_each`]\([`_mut`][`par_for_each_mut`])|Runs a specified function for each query item.| +/// |[`iter_many`]\([`_mut`][`iter_many_mut`])|Iterates or runs a specified function over query items generated by a list of entities.| +/// |[`iter_combinations`]\([`_mut`][`iter_combinations_mut`])|Returns an iterator over all combinations of a specified number of query items.| +/// |[`get`]\([`_mut`][`get_mut`])|Returns the query item for the specified entity.| +/// |[`many`]\([`_mut`][`many_mut`]),
[`get_many`]\([`_mut`][`get_many_mut`])|Returns the query items for the specified entities.| +/// |[`single`]\([`_mut`][`single_mut`]),
[`get_single`]\([`_mut`][`get_single_mut`])|Returns the query item while verifying that there aren't others.| /// -/// ``` -/// # use bevy_ecs::prelude::*; -/// # #[derive(Component)] -/// # struct ComponentA; -/// # #[derive(Component)] -/// # struct ComponentB; -/// fn immutable_query_system(query: Query<(&ComponentA, &ComponentB)>) { -/// for (a, b) in &query { -/// // Here, `a` and `b` are normal references to components, relatively of -/// // `&ComponentA` and `&ComponentB` types. -/// } -/// } -/// # bevy_ecs::system::assert_is_system(immutable_query_system); +/// There are two methods for each type of query operation: immutable and mutable (ending with `_mut`). +/// When using immutable methods, the query items returned are of type [`ROQueryItem`], a read-only version of the query item. +/// In this circumstance, every mutable reference in the query fetch type parameter is substituted by a shared reference. /// -/// fn mutable_query_system(mut query: Query<(&mut ComponentA, &ComponentB)>) { -/// for (mut a, b) in &mut query { -/// // Similar to the above system, but this time `ComponentA` can be accessed mutably. -/// // Note the usage of `mut` in the tuple and the call to `iter_mut` instead of `iter`. -/// } -/// } -/// # bevy_ecs::system::assert_is_system(mutable_query_system); -/// ``` +/// # Performance +/// +/// Creating a `Query` is a low-cost constant operation. +/// Iterating it, on the other hand, fetches data from the world and generates items, which can have a significant computational cost. +/// +/// [`Table`] component storage type is much more optimized for query iteration than [`SparseSet`]. +/// +/// Two systems cannot be executed in parallel if both access the same component type where at least one of the accesses is mutable. +/// This happens unless the executor can verify that no entity could be found in both queries. +/// +/// Optional components increase the number of entities a query has to match against. +/// This can hurt iteration performance, especially if the query solely consists of only optional components, since the query would iterate over each entity in the world. +/// +/// The following table compares the computational complexity of the various methods and operations, where: /// -/// ## Getting the query result for a particular entity +/// - **n** is the number of entities that match the query, +/// - **r** is the number of elements in a combination, +/// - **k** is the number of involved entities in the operation, +/// - **a** is the number of archetypes in the world, +/// - **C** is the [binomial coefficient], used to count combinations. +/// nCr is read as "*n* choose *r*" and is equivalent to the number of distinct unordered subsets of *r* elements that can be taken from a set of *n* elements. /// -/// If you have an [`Entity`] ID, you can use the [`get`](Self::get) or -/// [`get_mut`](Self::get_mut) methods to access the query result for that particular entity. +/// |Query operation|Computational complexity| +/// |:---:|:---:| +/// |[`iter`]\([`_mut`][`iter_mut`])|O(n)| +/// |[`for_each`]\([`_mut`][`for_each_mut`]),
[`par_for_each`]\([`_mut`][`par_for_each_mut`])|O(n)| +/// |[`iter_many`]\([`_mut`][`iter_many_mut`])|O(k)| +/// |[`iter_combinations`]\([`_mut`][`iter_combinations_mut`])|O(nCr)| +/// |[`get`]\([`_mut`][`get_mut`])|O(1)| +/// |([`get_`][`get_many`])[`many`]|O(k)| +/// |([`get_`][`get_many_mut`])[`many_mut`]|O(k2)| +/// |[`single`]\([`_mut`][`single_mut`]),
[`get_single`]\([`_mut`][`get_single_mut`])|O(a)| +/// |Archetype based filtering ([`With`], [`Without`], [`Or`])|O(a)| +/// |Change detection filtering ([`Added`], [`Changed`])|O(a + n)| /// -/// ## Getting a single query result +/// `for_each` methods are seen to be generally faster than their `iter` version on worlds with high archetype fragmentation. +/// As iterators are in general more flexible and better integrated with the rest of the Rust ecosystem, +/// it is advised to use `iter` methods over `for_each`. +/// It is strongly advised to only use `for_each` if it tangibly improves performance: +/// be sure profile or benchmark both before and after the change. /// -/// While it's possible to get a single result from a query by using `iter.next()`, a more -/// idiomatic approach would use the [`single`](Self::single) or [`single_mut`](Self::single_mut) -/// methods instead. Keep in mind though that they will return a [`QuerySingleError`] if the -/// number of query results differ from being exactly one. If that's the case, use `iter.next()` -/// (or `iter_mut.next()`) to only get the first query result. +/// [`Added`]: crate::query::Added +/// [`AnyOf`]: crate::query::AnyOf +/// [binomial coefficient]: https://en.wikipedia.org/wiki/Binomial_coefficient +/// [`Changed`]: crate::query::Changed +/// [components]: crate::component::Component +/// [entity identifiers]: crate::entity::Entity +/// [`for_each`]: Self::for_each +/// [`for_each_mut`]: Self::for_each_mut +/// [`get`]: Self::get +/// [`get_many`]: Self::get_many +/// [`get_many_mut`]: Self::get_many_mut +/// [`get_mut`]: Self::get_mut +/// [`get_single`]: Self::get_single +/// [`get_single_mut`]: Self::get_single_mut +/// [`iter`]: Self::iter +/// [`iter_combinations`]: Self::iter_combinations +/// [`iter_combinations_mut`]: Self::iter_combinations_mut +/// [`iter_many`]: Self::iter_many +/// [`iter_many_mut`]: Self::iter_many_mut +/// [`iter_mut`]: Self::iter_mut +/// [`many`]: Self::many +/// [`many_mut`]: Self::many_mut +/// [`Or`]: crate::query::Or +/// [`par_for_each`]: Self::par_for_each +/// [`par_for_each_mut`]: Self::par_for_each_mut +/// [performance]: #performance +/// [`single`]: Self::single +/// [`single_mut`]: Self::single_mut +/// [`SparseSet`]: crate::storage::SparseSet +/// [System parameter]: crate::system::SystemParam +/// [`Table`]: crate::storage::Table +/// [`With`]: crate::query::With +/// [`Without`]: crate::query::Without pub struct Query<'world, 'state, Q: WorldQuery, F: WorldQuery = ()> { pub(crate) world: &'world World, pub(crate) state: &'state QueryState,