Skip to main content

Module query

Module query 

Source
Expand description

Queries: picking entities by the components they carry.

A query is a type, not a value. The components to hand out are written in the turbofish, so the compiler checks them, and the iterator resolves them once per archetype instead of once per row.

ItemYields
&Tthe component, shared; only archetypes carrying it match
&mut Tthe component, exclusive; only archetypes carrying it match
Option<&T>Some when the archetype carries the component
Option<&mut T>Some when it carries it, exclusive
Entitythe entity itself
Has<T>whether the archetype carries T, narrowing nothing

A tuple of items asks for all of them at once and yields a tuple of their items, and tuples nest: (&a, (&b, &c)) asks for the same three components as (&a, &b, &c) and yields (&A, (&B, &C)). An item written &(a, b) is one component whose type is that tuple, not two, and an item outside the forms above fails to compile.

A query is held rather than borrowed one row at a time: crate::QueryBorrow is what a scope hands out, it claims the components it will reach when it is built, and the claims are released when it is dropped. Iterating it is crate::QueryBorrow::iter.

let mut world = World::new();
world.root_scope_mut().spawn(bundle![1u32, 10.0f32]);
world.root_scope_mut().spawn(bundle![2u32, true]);

let mut query = world.root_scope().query::<&u32>();
let sum: u32 = query.iter().map(|value| *value).sum();
assert_eq!(sum, 3);

// The entity, its component, and whether it also carries a `bool`. The
// `Has<bool>` reports the answer without narrowing anything, so both spawns
// above are visited and the one without a `bool` prints `false`.
for (entity, value, has_bool) in world.root_scope().query::<(Entity, &u32, Has<bool>)>().iter() {
    println!("{entity:?} has {value}, and a bool: {has_bool}");
}

// Tuples nest, so this asks for the same components and yields
// `(&u32, (&f32,))` instead of `(&u32, &f32)`.
for (value, (height,)) in world.root_scope().query::<(&u32, (&f32,))>().iter() {
    let _ = (value, height);
}

A query visits archetypes in creation order and rows in storage order, so iteration is deterministic. It skips the rows the scope cannot see and the tree’s two scaffolding entities.

Narrowing which archetypes a query visits, including by a component set only known at run time, is crate::QueryBorrow::by.

Β§Queries of your own

A row that carries more than a tuple impl covers, or one whose components are worth naming, is declared with the crate::query! macro:

pub struct Health(pub i32);
pub struct Armor(pub i32);
pub struct Mana(pub i32);

query! {
    /// Everything one combatant is made of.
    pub struct Combatant<'a> {
        pub entity: Entity,
        pub health: &'a mut Health,
        pub armor: &'a Armor,
        /// `None` for a row that carries no mana.
        pub mana: Option<&'a Mana>,
        pub has_armor: Has<Armor>,
    }
}

let mut world = World::new();
world.root_scope_mut().spawn(bundle![Health(10), Armor(2)]);

for row in world.root_scope().query::<Combatant>().iter() {
    row.health.0 -= row.armor.0;
    assert!(row.has_armor);
    assert!(row.mana.is_none());
}

The declaration is one row: the macro derives the item struct and the Query impl from it. No unsafe is involved on the caller’s side, and the claims the query makes are exactly the fields it declares: a component is claimed by asking the PlanBuilder for it, so there is no second list that could disagree with what the query actually reaches.

Re-exportsΒ§

use core::any::TypeId; πŸ”’
use core::cell::UnsafeCell; πŸ”’
use core::marker::PhantomData; πŸ”’
use crate::archetype::Archetype; πŸ”’
use crate::borrow::Claims; πŸ”’
use crate::entity::Entity; πŸ”’
use crate::world::World; πŸ”’
pub use iter::QueryIter;

ModulesΒ§

iter πŸ”’
The iterator a query hands out.
macros πŸ”’
The declarative front end for a query.

MacrosΒ§

impl_tuple πŸ”’

StructsΒ§

Col
A claimed column, shared.
ColMut
A claimed column, exclusive.
Has
Yields whether the archetype carries T.
PlanBuilder
What one archetype offers, and what a query asks of it while resolving its plan.
QueryBorrow
What a scope hands out for a query: the claims, and the way to iterate them.
QueryOne
What a scope hands out for a query over one entity.

EnumsΒ§

Mode
Whether a component is reached shared or exclusive.

TraitsΒ§

ArchetypeFilter
Narrows the archetypes a query visits.
Query
What to fetch from every entity a query matches.

Type AliasesΒ§

Ask πŸ”’
One component a query reaches, and how.