edict/query/mod.rs
1//! Queries are used to fetch data from the [`World`].
2//!
3//! Basic query types are `&T`, `&mut T`, and `Entities`.
4//! `&T` fetches component `T` for reading. It yields `&T`, so it also
5//! filters out entities that don't have component `T`.
6//! `&mut T` fetches component `T` for writing. And filters same way as `&T`.
7//! `Entities` fetches [`EntityId`]s. All entities have an ID,
8//! so it doesn't filter anything.
9//!
10//! Queries are divided into two categories: stateful and stateless.
11//!
12//! Stateful queries implement `Query` trait and are passed into methods by value.
13//! Some of them have `DefaultQuery` implementation, and can be used in methods
14//! that do not accept query as an argument and only as a type parameter.
15//!
16//! Stateless queries implement `PhantomQuery` trait, and `PhantomData<Q>`
17//! is stateful counterpart for stateless query `Q`.
18//!
19//! All basic queries are stateless.
20//! Advanced queries like `Modified` - that filter entities based on
21//! component modification - and `RelatedTo` - that filter entities based on
22//! entity relation - are stateful.
23//!
24//! Queries can be combined into tuples producing a new query that yields
25//! a tuple of items from the original queries and filtering out entities
26//! that don't satisfy all queries.
27//!
28//! TODO: Derive impl for structures with named fields.
29//!
30//!
31//! Queries can be used with [`World`] to produce a [`View`].
32//! A [`View`] can be iterated to visit all matching entities and fetch
33//! data from them.
34//! [`View`] can also be indexed with [`Entity`] to fetch data from
35//! a specific entity.
36//!
37//! [`World`]: crate::world::World
38//! [`View`]: crate::view::View
39//! [`Entity`]: crate::entity::Entity
40//!
41
42use core::any::TypeId;
43
44use crate::{
45 archetype::Archetype, component::ComponentInfo, entity::EntityId, epoch::EpochId, Access,
46};
47
48pub use self::{
49 alt::{Alt, FetchAlt},
50 // any_of::AnyOf,
51 boolean::{
52 And, And2, And3, And4, And5, And6, And7, And8, BooleanFetch, BooleanFetchOp, BooleanQuery,
53 Or, Or2, Or3, Or4, Or5, Or6, Or7, Or8, Xor, Xor2, Xor3, Xor4, Xor5, Xor6, Xor7, Xor8,
54 },
55 borrow::{
56 FetchBorrowAllRead, FetchBorrowAnyRead, FetchBorrowAnyWrite, FetchBorrowOneRead,
57 FetchBorrowOneWrite, QueryBorrowAll, QueryBorrowAny, QueryBorrowOne,
58 },
59 copied::{Cpy, FetchCopied},
60 entities::{Entities, EntitiesFetch},
61 fetch::{Fetch, UnitFetch, VerifyFetch},
62 filter::{FilteredFetch, Not, With, Without},
63 modified::{
64 Modified, ModifiedFetchAlt, ModifiedFetchCopied, ModifiedFetchRead, ModifiedFetchWith,
65 ModifiedFetchWrite,
66 },
67 read::{FetchRead, Read},
68 with_epoch::{EpochOf, FetchEpoch},
69 write::{FetchWrite, Write},
70};
71
72mod alt;
73// mod any_of;
74mod boolean;
75mod borrow;
76mod copied;
77mod entities;
78mod fetch;
79mod filter;
80mod modified;
81mod option;
82// mod phantom;
83mod read;
84mod tuple;
85mod with_epoch;
86mod write;
87
88/// Types associated with a query type.
89pub trait AsQuery {
90 /// Associated query type.
91 type Query: Query;
92}
93
94/// Types convertible into query type.
95pub trait IntoQuery: AsQuery {
96 /// Converts into query.
97 fn into_query(self) -> Self::Query;
98}
99
100/// Types convertible into query type.
101pub unsafe trait IntoSendQuery: IntoQuery + AsSendQuery {}
102unsafe impl<Q> IntoSendQuery for Q where Q: IntoQuery + AsSendQuery {}
103
104/// Types associated with default-constructible query type.
105pub trait DefaultQuery: AsQuery {
106 /// Returns default query instance.
107 fn default_query() -> Self::Query;
108}
109
110/// Types associated with default-constructible query type.
111pub unsafe trait DefaultSendQuery: DefaultQuery + AsSendQuery {}
112unsafe impl<Q> DefaultSendQuery for Q where Q: DefaultQuery + AsSendQuery {}
113
114/// Detected write aliasing.
115/// Should be either resolved at runtime or reported with panic.
116pub struct WriteAlias;
117
118/// Trait to query components from entities in the world.
119/// Queries implement efficient iteration over entities while yielding
120/// references to the components and optionally [`EntityId`] to address same components later.
121///
122/// [`EntityId`]: edict::entity::EntityId
123pub unsafe trait Query: IntoQuery<Query = Self> + Copy + Send + Sync + 'static {
124 /// Item type this query type yields.
125 type Item<'a>: 'a;
126
127 /// Fetch value type for this query type.
128 /// Contains data from one archetype.
129 type Fetch<'a>: Fetch<'a, Item = Self::Item<'a>> + 'a;
130
131 /// Set to `true` if query fetches at least one mutable component.
132 const MUTABLE: bool;
133
134 /// Set to `true` if query filters individual entities.
135 const FILTERS_ENTITIES: bool = false;
136
137 /// Returns what kind of access the query performs on the component type.
138 /// This method may return stronger access type if it is impossible to know
139 /// exact access with only type-id.
140 #[must_use]
141 fn component_access(&self, comp: &ComponentInfo) -> Result<Option<Access>, WriteAlias>;
142
143 /// Checks if archetype must be visited or skipped.
144 /// If returns `false`, `access_archetype` and `fetch` must not be called,
145 /// meaning that complex query should either skip archetype entirely or
146 /// for this query specifically.
147 ///
148 /// If this method returns `true`, `access_archetype` and `fetch` must be safe to call.
149 #[must_use]
150 fn visit_archetype(&self, archetype: &Archetype) -> bool;
151
152 /// Asks query to provide types and access for the specific archetype.
153 /// Must call provided closure with type id and access pairs.
154 /// Only types from archetype must be used to call closure.
155 ///
156 /// # Safety
157 ///
158 /// Must not be called if `visit_archetype` returned `false`.
159 /// Implementation are allowed to assume conditions that make `visit_archetype` return `true`.
160 unsafe fn access_archetype(&self, archetype: &Archetype, f: impl FnMut(TypeId, Access));
161
162 /// Checks if archetype must be visited or skipped a second time after
163 /// required access was granted.
164 ///
165 /// Most queries do not check visiting again so defaults to `true`.
166 #[must_use]
167 #[inline(always)]
168 fn visit_archetype_late(&self, archetype: &Archetype) -> bool {
169 debug_assert!(self.visit_archetype(archetype));
170 let _ = archetype;
171 true
172 }
173
174 /// Fetches data from one archetype.
175 ///
176 /// # Safety
177 ///
178 /// Must not be called if `visit_archetype` returned `false`.
179 #[must_use]
180 unsafe fn fetch<'a>(
181 &self,
182 arch_idx: u32,
183 archetype: &'a Archetype,
184 epoch: EpochId,
185 ) -> Self::Fetch<'a>;
186
187 /// Returns item for reserved entity if reserved entity (no components) satisfies the query.
188 /// Otherwise returns `None`.
189 #[must_use]
190 #[inline(always)]
191 fn reserved_entity_item<'a>(&self, id: EntityId, idx: u32) -> Option<Self::Item<'a>> {
192 let _ = id;
193 let _ = idx;
194 None
195 }
196}
197
198/// Query that does not mutate any components.
199///
200/// # Safety
201///
202/// [`Query`] must not borrow components mutably.
203/// [`Query`] must not modify entities versions.
204pub unsafe trait ImmutableQuery: Query {
205 /// Checks that query is valid in compile time.
206 const CHECK_VALID: () = {
207 if Self::MUTABLE {
208 panic!("Immutable query cannot fetch mutable components");
209 }
210 };
211}
212
213/// Query that can be used from non-main thread.
214pub unsafe trait SendQuery: Query {}
215
216pub unsafe trait SendImmutableQuery: SendQuery + ImmutableQuery {}
217unsafe impl<Q> SendImmutableQuery for Q where Q: SendQuery + ImmutableQuery {}
218
219/// Query that can be used from non-main thread.
220pub unsafe trait AsSendQuery: AsQuery {}
221
222unsafe impl<Q> AsSendQuery for Q
223where
224 Q: AsQuery,
225 Q::Query: SendQuery,
226{
227}
228
229/// Type alias for items returned by the [`Query`] type.
230pub type QueryItem<'a, Q> = <<Q as AsQuery>::Query as Query>::Item<'a>;