Trait bevy::ecs::query::WorldQuery

pub unsafe trait WorldQuery {
    type Item<'a>;
    type Fetch<'a>;
    type ReadOnly: ReadOnlyWorldQuery<State = Self::State>;
    type State: Send + Sync + Sized;

    const IS_DENSE: bool;
    const IS_ARCHETYPAL: bool;

    fn shrink<'wlong, 'wshort>(item: Self::Item<'wlong>) -> Self::Item<'wshort>
    where
        'wlong: 'wshort
; unsafe fn init_fetch<'w>(
        world: &'w World,
        state: &Self::State,
        last_change_tick: u32,
        change_tick: u32
    ) -> Self::Fetch<'w>; unsafe fn clone_fetch<'w>(fetch: &Self::Fetch<'w>) -> Self::Fetch<'w>; unsafe fn set_archetype<'w>(
        fetch: &mut Self::Fetch<'w>,
        state: &Self::State,
        archetype: &'w Archetype,
        table: &'w Table
    ); unsafe fn set_table<'w>(
        fetch: &mut Self::Fetch<'w>,
        state: &Self::State,
        table: &'w Table
    ); unsafe fn fetch<'w>(
        fetch: &mut Self::Fetch<'w>,
        entity: Entity,
        table_row: usize
    ) -> Self::Item<'w>; fn update_component_access(
        state: &Self::State,
        access: &mut FilteredAccess<ComponentId>
    ); fn update_archetype_component_access(
        state: &Self::State,
        archetype: &Archetype,
        access: &mut Access<ArchetypeComponentId>
    ); fn init_state(world: &mut World) -> Self::State; fn matches_component_set(
        state: &Self::State,
        set_contains_id: &impl Fn(ComponentId) -> bool
    ) -> bool; unsafe fn filter_fetch(
        fetch: &mut Self::Fetch<'_>,
        entity: Entity,
        table_row: usize
    ) -> bool { ... } }
Expand description

Types that can be fetched from a World using a Query.

There are many types that natively implement this trait:

  • 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. 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 WorldQuerys.
  • 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. By default, a world query only tests entities that have the matching component types. Wrapping it into an Option will increase the query search space, and it will return None if an entity doesn’t satisfy the WorldQuery.
  • AnyOf. Equivalent to wrapping each world query inside it into an Option.
  • ChangeTrackers. 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.

Implementing the trait manually can allow for a fundamentally new type of behaviour.

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. The most relevant improvements are:

  • Reusability across multiple systems.
  • There is no need to destructure a tuple since all fields are named.
  • Subqueries can be composed together to create a more complex query.
  • Methods can be implemented for the query items.
  • There is no hardcoded limit on the number of elements.

This trait can only be derived if each field either

  • also implements WorldQuery, or
  • is marked with #[world_query(ignore)]. Fields decorated with this attribute must implement Default and will be initialized to the default value as defined by the trait.

The derive macro only supports regular structs (structs with named fields).

use bevy_ecs::query::WorldQuery;

#[derive(WorldQuery)]
struct MyQuery {
    entity: Entity,
    // It is required that all reference lifetimes are explicitly annotated, just like in any
    // struct. Each lifetime should be 'static.
    component_a: &'static ComponentA,
    component_b: &'static ComponentB,
}

fn my_system(query: Query<MyQuery>) {
    for q in &query {
        q.component_a;
    }
}

Macro expansion

Expanding the macro will declare three or six additional structs, depending on whether or not the struct is marked as mutable. For a struct named X, the additional structs will be:

Struct namemutable onlyDescription
XStateUsed as the State type for X and XReadOnly
XItemThe type of the query item for X
XFetchUsed as the Fetch type for X
XReadOnlyItemThe type of the query item for XReadOnly
XReadOnlyFetchUsed as the Fetch type for XReadOnly
XReadOnlyReadOnly variant of X

Adding mutable references

Simply adding mutable references to a derived WorldQuery will result in a compilation error:

#[derive(WorldQuery)]
struct CustomQuery {
    component_a: &'static mut ComponentA,
}

To grant mutable access to components, the struct must be marked with the #[world_query(mutable)] attribute. This will also create three more structs that will be used for accessing the query immutably (see table above).

#[derive(WorldQuery)]
#[world_query(mutable)]
struct CustomQuery {
    component_a: &'static mut ComponentA,
}

Adding methods to query items

It is possible to add methods to query items in order to write reusable logic about related components. This will often make systems more readable because low level logic is moved out from them. It is done by adding impl blocks with methods for the -Item or -ReadOnlyItem generated structs.

#[derive(Component)]
struct Health(f32);

#[derive(Component)]
struct Buff(f32);

#[derive(WorldQuery)]
#[world_query(mutable)]
struct HealthQuery {
    health: &'static mut Health,
    buff: Option<&'static mut Buff>,
}

// `HealthQueryItem` is only available when accessing the query with mutable methods.
impl<'w> HealthQueryItem<'w> {
    fn damage(&mut self, value: f32) {
        self.health.0 -= value;
    }

    fn total(&self) -> f32 {
        self.health.0 + self.buff.as_deref().map_or(0.0, |Buff(buff)| *buff)
    }
}

// `HealthQueryReadOnlyItem` is only available when accessing the query with immutable methods.
impl<'w> HealthQueryReadOnlyItem<'w> {
    fn total(&self) -> f32 {
        self.health.0 + self.buff.map_or(0.0, |Buff(buff)| *buff)
    }
}

fn my_system(mut health_query: Query<HealthQuery>) {
    // The item returned by the iterator is of type `HealthQueryReadOnlyItem`.
    for health in health_query.iter() {
        println!("Total: {}", health.total());
    }
    // The item returned by the iterator is of type `HealthQueryItem`.
    for mut health in &mut health_query {
        health.damage(1.0);
        println!("Total (mut): {}", health.total());
    }
}

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. This will apply the listed derivable traits to the query item structs.

#[derive(WorldQuery)]
#[world_query(mutable, derive(Debug))]
struct CustomQuery {
    component_a: &'static ComponentA,
}

// This function statically checks that `T` implements `Debug`.
fn assert_debug<T: std::fmt::Debug>() {}

assert_debug::<CustomQueryItem>();
assert_debug::<CustomQueryReadOnlyItem>();

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.

#[derive(WorldQuery)]
struct SubQuery {
    component_a: &'static ComponentA,
    component_b: &'static ComponentB,
}

#[derive(WorldQuery)]
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.

#[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>>) {
    // ...
}

Safety

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:

Required Associated Types

The item returned by this WorldQuery

Per archetype/table state used by this WorldQuery to fetch Self::Item

The read-only variant of this WorldQuery, which satisfies the ReadOnlyWorldQuery trait.

State used to construct a Self::Fetch. This will be cached inside QueryState, so it is best to move as much data / computation here as possible to reduce the cost of constructing Self::Fetch.

Required Associated Constants

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.

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()).

Required Methods

This function manually implements subtyping for the query items.

Creates a new instance of this fetch.

Safety

state must have been initialized (via WorldQuery::init_state) using the same world passed in to this function.

While this function can be called for any query, it is always safe to call if Self: ReadOnlyWorldQuery holds.

Safety

While calling this method on its own cannot cause UB it is marked unsafe as the caller must ensure that the returned value is not used in any way that would cause two QueryItem<Self> for the same archetype_index or table_row to be alive at the same time.

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 World WorldQuery::init_state was called on. state must be the Self::State this was initialized with.

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 World WorldQuery::init_state was called on. state must be the Self::State this was initialized with.

Fetch Self::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.

Provided Methods

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.

Implementations on Foreign Types

SAFETY: Self is the same as Self::ReadOnly

SAFETY: access of &T is a subset of &mut T

Implementors

SAFETY: no component or archetype access

SAFETY: Self::ReadOnly is Self