Struct Query

Source
pub struct Query<T>
where T: QueryTuple,
{ /* private fields */ }
Expand description

Queries quickly find entities that match a list of conditions, and are at the core of many Flecs features like systems, observers, tooling and serialization.

Flecs queries can do anything from returning entities that match a simple list of components, to matching complex patterns against entity graphs.

See the Flecs Query Manual for in-depth documentation of queries.

They can be either:

  • cached, which means they are stored in the world and can be retrieved by name or entity. They don’t go out of scope until explicitly destroyed. They are slower to create than uncached queries, but faster to iterate.
  • uncached, which means they are created on the fly and are only valid for the duration of the query, scope. They are faster to create than cached queries, but slower to iterate.

§Safety

Queries are reference counted and won’t cause any lifetime issues or dangling references. You need to ensure that you’re holding no query objects anymore when the world is destroyed. This will otherwise panic.

§See also

Implementations§

Source§

impl<T> Query<T>
where T: QueryTuple,

Source

pub unsafe fn new_from(query: NonNull<ecs_query_t>) -> Self

wraps the query pointer in a new query

§Safety

this is unsafe due to the fact that the type of the query is not checked. the user is responsible for ensuring that the query is of the correct type. if not possible, only use .iter functions that do not pass in the components in the callback

§Arguments
  • query - The query pointer to wrap
§See also
  • C++ API: query::query
Source

pub fn destruct(self)

Destroy a query and its resources.

If the query is used as the parent of subqueries, those subqueries will be orphaned and must be deinitialized as well.

§See also
  • C++ API: query_base::destruct
Examples found in repository?
examples/flecs/queries/query_group_by_callbacks.rs (line 157)
75fn main() {
76    let world = World::new();
77
78    // Register components in order so that id for First is lower than Third
79    world.component::<First>();
80    world.component::<Second>();
81    world.component::<Third>();
82
83    // Grouped query
84    let query = world
85        .query::<(&Position,)>()
86        .group_by::<Group>()
87        // Callback invoked when a new group is created
88        .on_group_create(Some(callback_group_create))
89        // Callback invoked when a group is deleted
90        .on_group_delete(Some(callback_group_delete))
91        .build();
92
93    // Create entities in 6 different tables with 3 group ids
94    world
95        .entity()
96        .add::<(Group, Third)>()
97        .set(Position { x: 1.0, y: 1.0 });
98    world
99        .entity()
100        .add::<(Group, Second)>()
101        .set(Position { x: 2.0, y: 2.0 });
102    world
103        .entity()
104        .add::<(Group, First)>()
105        .set(Position { x: 3.0, y: 3.0 });
106
107    world
108        .entity()
109        .add::<(Group, Third)>()
110        .set(Position { x: 4.0, y: 4.0 })
111        .add::<Tag>();
112    world
113        .entity()
114        .add::<(Group, Second)>()
115        .set(Position { x: 5.0, y: 5.0 })
116        .add::<Tag>();
117    world
118        .entity()
119        .add::<(Group, First)>()
120        .set(Position { x: 6.0, y: 6.0 })
121        .add::<Tag>();
122
123    println!();
124
125    // The query cache now looks like this:
126    //  - group First:
127    //     - table [Position, (Group, First)]
128    //     - table [Position, Tag, (Group, First)]
129    //
130    //  - group Second:
131    //     - table [Position, (Group, Second)]
132    //     - table [Position, Tag, (Group, Second)]
133    //
134    //  - group Third:
135    //     - table [Position, (Group, Third)]
136    //     - table [Position, Tag, (Group, Third)]
137    //
138
139    query.run_iter(|it, (pos,)| {
140        let group = world.entity_from_id(it.group_id());
141        let ctx = unsafe { &*(query.group_context(group) as *mut GroupCtx) };
142        println!(
143            "Group: {:?} - Table: [{:?}] - Counter: {}",
144            group.path().unwrap(),
145            it.archetype(),
146            ctx.counter
147        );
148
149        for i in it.iter() {
150            println!(" [{:?}]", pos[i]);
151        }
152
153        println!();
154    });
155
156    // Deleting the query will call the on_group_deleted callback
157    query.destruct();
158
159    // Output:
160    //  Group created: "Third"
161    //  Group created: "Second"
162    //  Group created: "First"
163    //
164    //  Group: "::First" - Table: [Position, (Group,First)] - Counter: 3
165    //   [Position { x: 3.0, y: 3.0 }]
166    //
167    //  Group: "::First" - Table: [Position, Tag, (Group,First)] - Counter: 3
168    //   [Position { x: 6.0, y: 6.0 }]
169    //
170    //  Group: "::Second" - Table: [Position, (Group,Second)] - Counter: 2
171    //   [Position { x: 2.0, y: 2.0 }]
172    //
173    //  Group: "::Second" - Table: [Position, Tag, (Group,Second)] - Counter: 2
174    //   [Position { x: 5.0, y: 5.0 }]
175    //
176    //  Group: "::Third" - Table: [Position, (Group,Third)] - Counter: 1
177    //   [Position { x: 1.0, y: 1.0 }]
178    //
179    //  Group: "::Third" - Table: [Position, Tag, (Group,Third)] - Counter: 1
180    //   [Position { x: 4.0, y: 4.0 }]
181    //
182    //  Group deleted: "Second"
183    //  Group deleted: "First"
184    //  Group deleted: "Third"
185}
Source

pub fn is_changed(&self) -> bool

Returns whether the query data changed since the last iteration.

This operation must be invoked before obtaining the iterator, as this will reset the changed state.

§Returns

The operation will return true after:

  • new entities have been matched with
  • matched entities were deleted
  • matched components were changed

Otherwise, it will return false.

§See also
Examples found in repository?
examples/flecs/queries/query_change_tracking.rs (line 87)
25fn main() {
26    let world = World::new();
27
28    // Make Dirty inheritable so that queries can match it on prefabs
29    world
30        .component::<Dirty>()
31        .add_trait::<(flecs::OnInstantiate, flecs::Inherit)>();
32    //todo v4 bug flecs core
33
34    // Create a query that just reads a component. We'll use this query for
35    // change tracking. Change tracking for a query is automatically enabled
36    // when query::changed() is called.
37    // Each query has its own private dirty state which is reset only when the
38    // query is iterated.
39
40    let query_read = world.query::<&Position>().set_cached().build();
41
42    // Create a query that writes the component based on a Dirty state.
43    let query_write = world
44        .query::<(&Dirty, &mut Position)>()
45        .term_at(0)
46        .up_type::<flecs::IsA>() // Only match Dirty from prefab
47        .instanced() // Instanced iteration is faster (see example)
48        .build();
49
50    // Create two prefabs with a Dirty component. We can use this to share a
51    // single Dirty value for all entities in a table.
52    let prefab_dirty_false = world
53        .prefab_named("prefab_dirty_false")
54        .set(Dirty { value: false });
55
56    let prefab_dirty_true = world
57        .prefab_named("prefab_dirty_true")
58        .set(Dirty { value: true });
59
60    // Create instances of p1 and p2. Because the entities have different
61    // prefabs, they end up in different tables.
62    world
63        .entity_named("e1_dirty_false")
64        .is_a_id(prefab_dirty_false)
65        .set(Position { x: 10.0, y: 20.0 });
66
67    world
68        .entity_named("e2_dirty_false")
69        .is_a_id(prefab_dirty_false)
70        .set(Position { x: 30.0, y: 40.0 });
71
72    world
73        .entity_named("e3_dirty_true")
74        .is_a_id(prefab_dirty_true)
75        .set(Position { x: 40.0, y: 50.0 });
76
77    world
78        .entity_named("e4_dirty_true")
79        .is_a_id(prefab_dirty_true)
80        .set(Position { x: 50.0, y: 60.0 });
81
82    // We can use the changed() function on the query to check if any of the
83    // tables it is matched with has changed. Since this is the first time that
84    // we check this and the query is matched with the tables we just created,
85    // the function will return true.
86    println!();
87    println!("query_read.is_changed(): {}", query_read.is_changed());
88    println!();
89
90    // The changed state will remain true until we have iterated each table.
91    query_read.run(|mut iter| {
92        while iter.next() {
93            // With the it.changed() function we can check if the table we're
94            // currently iterating has changed since last iteration.
95            // Because this is the first time the query is iterated, all tables
96            // will show up as changed.
97            println!(
98                "iiter.is_changed() for table [{}]: {}",
99                iter.archetype().unwrap(),
100                iter.is_changed()
101            );
102        }
103    });
104
105    // Now that we have iterated all tables, the dirty state is reset.
106    println!();
107    println!("query_read.is_changed(): {:?}", query_read.is_changed());
108    println!();
109
110    // Iterate the write query. Because the Position term is InOut (default)
111    // iterating the query will write to the dirty state of iterated tables.
112    query_write.run_iter(|mut it, (dirty, pos)| {
113        println!("iterate table [{}]", it.archetype().unwrap());
114
115        // Because we enforced that Dirty is a shared component, we can check
116        // a single value for the entire table.
117        if !dirty[0].value {
118            // If the dirty flag is false, skip the table. This way the table's
119            // dirty state is not updated by the query.
120            it.skip();
121            println!("iter.skip() for table [{}]", it.archetype().unwrap());
122            return;
123        }
124
125        // For all other tables the dirty state will be set.
126        for i in it.iter() {
127            pos[i].x += 1.0;
128            pos[i].y += 1.0;
129        }
130    });
131
132    // One of the tables has changed, so q_read.changed() will return true
133    println!();
134    println!("query_read.is_changed(): {}", query_read.is_changed());
135    println!();
136
137    // When we iterate the read query, we'll see that one table has changed.
138    query_read.run(|mut iter| {
139        while iter.next() {
140            println!(
141                "iter.is_changed() for table [{}]: {}",
142                iter.archetype().unwrap(),
143                iter.is_changed()
144            );
145        }
146    });
147    println!();
148
149    // Output:
150    //  query_read.is_changed(): true
151    //
152    //  iiter.is_changed() for table [Position, (Identifier,Name), (IsA,prefab_dirty_false)]: true
153    //  iiter.is_changed() for table [Position, (Identifier,Name), (IsA,prefab_dirty_true)]: true
154    //
155    //  query_read.is_changed(): false
156    //
157    //  iterate table [Position, (Identifier,Name), (IsA,prefab_dirty_false)]
158    //  iter.skip() for table [Position, (Identifier,Name), (IsA,prefab_dirty_false)]
159    //  iterate table [Position, (Identifier,Name), (IsA,prefab_dirty_true)]
160    //
161    //  query_read.is_changed(): true
162    //
163    //  iter.is_changed() for table [Position, (Identifier,Name), (IsA,prefab_dirty_false)]: false
164    //  iter.is_changed() for table [Position, (Identifier,Name), (IsA,prefab_dirty_true)]: true
165}
Source

pub fn group_info( &self, group_id: impl Into<Entity>, ) -> *const ecs_query_group_info_t

Get info for group

§Arguments
  • group_id - The group id to get info for
§Returns

Returns a pointer to the group info

§See also
  • C++ API: query_base::get_group_info
Source

pub fn group_context(&self, group_id: impl Into<Entity>) -> *mut c_void

Get context for group

§Arguments
  • group_id - The group id to get context for
§Returns

Returns a (void) pointer to the group context

§See also
  • C++ API: query_base::group_ctx
Examples found in repository?
examples/flecs/queries/query_group_by_callbacks.rs (line 141)
75fn main() {
76    let world = World::new();
77
78    // Register components in order so that id for First is lower than Third
79    world.component::<First>();
80    world.component::<Second>();
81    world.component::<Third>();
82
83    // Grouped query
84    let query = world
85        .query::<(&Position,)>()
86        .group_by::<Group>()
87        // Callback invoked when a new group is created
88        .on_group_create(Some(callback_group_create))
89        // Callback invoked when a group is deleted
90        .on_group_delete(Some(callback_group_delete))
91        .build();
92
93    // Create entities in 6 different tables with 3 group ids
94    world
95        .entity()
96        .add::<(Group, Third)>()
97        .set(Position { x: 1.0, y: 1.0 });
98    world
99        .entity()
100        .add::<(Group, Second)>()
101        .set(Position { x: 2.0, y: 2.0 });
102    world
103        .entity()
104        .add::<(Group, First)>()
105        .set(Position { x: 3.0, y: 3.0 });
106
107    world
108        .entity()
109        .add::<(Group, Third)>()
110        .set(Position { x: 4.0, y: 4.0 })
111        .add::<Tag>();
112    world
113        .entity()
114        .add::<(Group, Second)>()
115        .set(Position { x: 5.0, y: 5.0 })
116        .add::<Tag>();
117    world
118        .entity()
119        .add::<(Group, First)>()
120        .set(Position { x: 6.0, y: 6.0 })
121        .add::<Tag>();
122
123    println!();
124
125    // The query cache now looks like this:
126    //  - group First:
127    //     - table [Position, (Group, First)]
128    //     - table [Position, Tag, (Group, First)]
129    //
130    //  - group Second:
131    //     - table [Position, (Group, Second)]
132    //     - table [Position, Tag, (Group, Second)]
133    //
134    //  - group Third:
135    //     - table [Position, (Group, Third)]
136    //     - table [Position, Tag, (Group, Third)]
137    //
138
139    query.run_iter(|it, (pos,)| {
140        let group = world.entity_from_id(it.group_id());
141        let ctx = unsafe { &*(query.group_context(group) as *mut GroupCtx) };
142        println!(
143            "Group: {:?} - Table: [{:?}] - Counter: {}",
144            group.path().unwrap(),
145            it.archetype(),
146            ctx.counter
147        );
148
149        for i in it.iter() {
150            println!(" [{:?}]", pos[i]);
151        }
152
153        println!();
154    });
155
156    // Deleting the query will call the on_group_deleted callback
157    query.destruct();
158
159    // Output:
160    //  Group created: "Third"
161    //  Group created: "Second"
162    //  Group created: "First"
163    //
164    //  Group: "::First" - Table: [Position, (Group,First)] - Counter: 3
165    //   [Position { x: 3.0, y: 3.0 }]
166    //
167    //  Group: "::First" - Table: [Position, Tag, (Group,First)] - Counter: 3
168    //   [Position { x: 6.0, y: 6.0 }]
169    //
170    //  Group: "::Second" - Table: [Position, (Group,Second)] - Counter: 2
171    //   [Position { x: 2.0, y: 2.0 }]
172    //
173    //  Group: "::Second" - Table: [Position, Tag, (Group,Second)] - Counter: 2
174    //   [Position { x: 5.0, y: 5.0 }]
175    //
176    //  Group: "::Third" - Table: [Position, (Group,Third)] - Counter: 1
177    //   [Position { x: 1.0, y: 1.0 }]
178    //
179    //  Group: "::Third" - Table: [Position, Tag, (Group,Third)] - Counter: 1
180    //   [Position { x: 4.0, y: 4.0 }]
181    //
182    //  Group deleted: "Second"
183    //  Group deleted: "First"
184    //  Group deleted: "Third"
185}

Trait Implementations§

Source§

impl<T> Clone for Query<T>
where T: QueryTuple,

Source§

fn clone(&self) -> Self

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<T> Drop for Query<T>
where T: QueryTuple,

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

impl<T: QueryTuple> From<&Query<T>> for NonNull<ecs_query_t>

Source§

fn from(q: &Query<T>) -> Self

Converts to this type from the input type.
Source§

impl<T> From<Query<T>> for Entity
where T: QueryTuple,

Source§

fn from(query: Query<T>) -> Self

Converts to this type from the input type.
Source§

impl<'a, T> QueryAPI<'a, (), T> for Query<T>
where T: QueryTuple,

Source§

fn entity(&self) -> EntityView<'_>

Get the entity of the current query Read more
Source§

fn each(&self, func: impl FnMut(T::TupleType<'_>))

Each iterator. The “each” iterator accepts a function that is invoked for each matching entity. The following function signatures is valid: Read more
Source§

fn each_entity(&self, func: impl FnMut(EntityView<'_>, T::TupleType<'_>))

Each iterator. The “each” iterator accepts a function that is invoked for each matching entity. The following function signatures is valid: Read more
Source§

fn each_iter( &self, func: impl FnMut(TableIter<'_, false, P>, usize, T::TupleType<'_>), )
where P: ComponentId,

Each iterator. This variant of each provides access to the TableIter object, which contains more information about the object being iterated. The usize argument contains the index of the entity being iterated, which can be used to obtain entity-specific data from the TableIter object. Read more
Source§

fn find( &self, func: impl FnMut(T::TupleType<'_>) -> bool, ) -> Option<EntityView<'a>>

find iterator to find an entity The “find” iterator accepts a function that is invoked for each matching entity and checks if the condition is true. if it is, it returns that entity. The following function signatures is valid: Read more
Source§

fn find_entity( &self, func: impl FnMut(EntityView<'_>, T::TupleType<'_>) -> bool, ) -> Option<EntityView<'a>>

find iterator to find an entity The “find” iterator accepts a function that is invoked for each matching entity and checks if the condition is true. if it is, it returns that entity. The following function signatures is valid: Read more
Source§

fn find_iter( &self, func: impl FnMut(TableIter<'_, false, P>, usize, T::TupleType<'_>) -> bool, ) -> Option<EntityView<'a>>
where P: ComponentId,

find iterator to find an entity. The “find” iterator accepts a function that is invoked for each matching entity and checks if the condition is true. if it is, it returns that entity. The following function signatures is valid: Read more
Source§

fn run_iter( &self, func: impl FnMut(TableIter<'_, false, P>, T::TupleSliceType<'_>), )
where P: ComponentId,

run iter iterator. loops the iterator automatically compared to run() Read more
Source§

fn run(&self, func: impl FnMut(TableIter<'_, true, P>))
where P: ComponentId,

Run iterator. Read more
Source§

fn run_each<FuncEach>( &self, func: impl FnMut(TableIter<'_, true, P>), func_each: FuncEach, )
where P: ComponentId, FuncEach: FnMut(T::TupleType<'_>),

Run iterator with each forwarding. The “iter” iterator accepts a function that is invoked for each matching table. The following function signature is valid: Read more
Source§

fn run_each_entity<FuncEachEntity>( &self, func: impl FnMut(TableIter<'_, true, P>), func_each: FuncEachEntity, )
where P: ComponentId, FuncEachEntity: FnMut(EntityView<'_>, T::TupleType<'_>),

Run iterator with each entity forwarding. Read more
Source§

fn each_term(&self, func: impl FnMut(&TermRef<'_>))

Each term iterator. The each_term iterator accepts a function that is invoked for each term in the query. The following function signature is valid: Read more
Source§

fn term(&self, index: usize) -> TermRef<'_>

Get a immutable reference of the term of the current query at the given index This is mostly used for debugging purposes. Read more
Source§

fn field_count(&self) -> i8

Get the field count of the current query Read more
Source§

fn term_count(&self) -> u32

Get the count of terms set of the current query
Source§

fn to_string(&self) -> String

Convert query to string expression. Convert query terms to a string expression. The resulting expression can be parsed to create the same query. Read more
Source§

fn find_var(&self, name: &str) -> Option<i32>

Source§

fn plan(&self) -> String

Source§

fn iterable(&self) -> QueryIter<'_, P, T>

Source§

fn iter_stage(&'a self, stage: impl WorldProvider<'a>) -> QueryIter<'a, P, T>

Source§

fn first_entity(&mut self) -> Option<EntityView<'a>>

Return first matching entity. Read more
Source§

fn is_true(&mut self) -> bool

Returns true if iterator yields at least once result.
Source§

fn count(&mut self) -> i32

Return total number of entities in result. Read more
Source§

fn set_group_id(&mut self, group_id: impl Into<Entity>) -> QueryIter<'_, P, T>

Limit results to tables with specified group id (grouped queries only) Read more
Source§

fn set_group<Group: ComponentId>(&mut self) -> QueryIter<'_, P, T>

Limit results to tables with specified group id (grouped queries only) Read more
Source§

fn set_var( &mut self, var_id: i32, value: impl Into<Entity>, ) -> QueryIter<'_, P, T>

set variable of iter Read more
Source§

fn set_var_table( &mut self, var_id: i32, table: impl IntoTableRange, ) -> QueryIter<'_, P, T>

set variable of iter as table Read more
Source§

fn set_var_expr( &mut self, name: &str, value: impl Into<Entity>, ) -> QueryIter<'_, P, T>

set variable for rule iter Read more
Source§

fn set_var_table_expr( &mut self, name: &str, table: impl IntoTableRange, ) -> QueryIter<'_, P, T>

set variable for rule iter as table Read more
Source§

impl<'a, T> WorldProvider<'a> for Query<T>
where T: QueryTuple,

Source§

fn world(&self) -> WorldRef<'a>

Source§

impl<T> IterOperations for Query<T>
where T: QueryTuple,

Auto Trait Implementations§

§

impl<T> Freeze for Query<T>

§

impl<T> RefUnwindSafe for Query<T>
where T: RefUnwindSafe,

§

impl<T> !Send for Query<T>

§

impl<T> !Sync for Query<T>

§

impl<T> Unpin for Query<T>
where T: Unpin,

§

impl<T> UnwindSafe for Query<T>
where T: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<'a, T> Doc<'a> for T
where T: Into<Entity> + WorldProvider<'a> + Clone,

Source§

fn set_doc_name(&self, name: &str) -> &Self

Available on crate feature flecs_doc only.
Add human-readable name to entity. Read more
Source§

fn set_doc_brief(&self, brief: &str) -> &Self

Available on crate feature flecs_doc only.
Add brief description to entity. Read more
Source§

fn set_doc_detail(&self, detail: &str) -> &Self

Available on crate feature flecs_doc only.
Add detailed description to entity. Read more
Available on crate feature flecs_doc only.
Add link to external documentation to entity. Read more
Source§

fn set_doc_color(&self, color: &str) -> &Self

Available on crate feature flecs_doc only.
Add color to entity. Read more
Source§

impl<T> DoesNotImpl for T

Source§

const IMPLS: bool = false

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.