Skip to main content

goud_engine/ecs/query/fetch/
traits.rs

1//! Core traits for the query fetch system.
2//!
3//! Defines [`WorldQuery`], [`ReadOnlyWorldQuery`], and [`QueryState`], which
4//! are the foundational building blocks of the ECS query system.
5
6use std::collections::BTreeSet;
7
8use crate::ecs::archetype::Archetype;
9use crate::ecs::component::ComponentId;
10use crate::ecs::entity::Entity;
11use crate::ecs::World;
12
13// =============================================================================
14// WorldQuery Trait
15// =============================================================================
16
17/// Trait for types that can be queried from a [`World`].
18///
19/// `WorldQuery` is the foundational trait of the ECS query system. It defines:
20///
21/// 1. What type of data the query produces (`Item`)
22/// 2. What state the query caches (`State`)
23/// 3. How to match archetypes (`matches_archetype`)
24/// 4. How to fetch data from the world (`fetch`)
25///
26/// # Generic Associated Type
27///
28/// The `Item<'w>` associated type uses a Generic Associated Type (GAT) to
29/// express that the fetched item has a lifetime tied to the world borrow.
30/// This enables returning references to component data.
31///
32/// # State Caching
33///
34/// The `State` type caches information needed for efficient queries, typically:
35/// - Component IDs (avoids repeated TypeId lookups)
36/// - Cached archetype matches (avoids repeated set operations)
37///
38/// # Safety
39///
40/// Implementors must ensure:
41/// 1. `matches_archetype` accurately reflects what entities can be fetched
42/// 2. `fetch` returns `None` for entities that don't match
43/// 3. Mutable queries conflict with other queries on the same component
44///
45/// # Built-in Implementations
46///
47/// The following types implement `WorldQuery`:
48///
49/// - `&T` where `T: Component` - Fetches immutable component reference
50/// - `&mut T` where `T: Component` - Fetches mutable component reference
51/// - `Entity` - Fetches the entity ID itself
52/// - Tuples `(A, B, ...)` - Combines multiple queries
53/// - `Option<Q>` - Optional query, always matches
54/// - `With<T>` - Filter for entities that have T (no data)
55/// - `Without<T>` - Filter for entities that don't have T (no data)
56///
57/// # Example
58///
59/// ```
60/// use goud_engine::ecs::{Component, Entity, World};
61/// use goud_engine::ecs::query::WorldQuery;
62///
63/// #[derive(Debug)]
64/// struct Health(f32);
65/// impl Component for Health {}
66///
67/// // The trait bounds ensure type safety:
68/// fn query_requires_world_query<Q: WorldQuery>() {}
69///
70/// // Entity always implements WorldQuery
71/// query_requires_world_query::<Entity>();
72/// ```
73pub trait WorldQuery {
74    /// The type of data this query fetches.
75    ///
76    /// This is a Generic Associated Type (GAT) that takes a lifetime parameter
77    /// `'w` representing the world borrow lifetime. This allows the item to
78    /// contain references to data stored in the world.
79    ///
80    /// Examples:
81    /// - For `&T`: `Item<'w> = &'w T`
82    /// - For `&mut T`: `Item<'w> = &'w mut T`
83    /// - For `Entity`: `Item<'w> = Entity` (no reference needed)
84    type Item<'w>;
85
86    /// The cached state for this query.
87    ///
88    /// State is initialized once via `init_state` and reused for subsequent
89    /// queries. This avoids repeated lookups of component IDs and other
90    /// metadata.
91    ///
92    /// Examples:
93    /// - For `&T`: `State = ComponentId`
94    /// - For tuples: `State = (A::State, B::State, ...)`
95    type State: QueryState;
96
97    /// Initializes the query state from the world.
98    ///
99    /// This is called once when a query is first created. The returned state
100    /// is cached and reused for all subsequent operations.
101    ///
102    /// # Arguments
103    ///
104    /// * `world` - Reference to the world (may be used for resource lookups)
105    ///
106    /// # Returns
107    ///
108    /// The initialized state for this query.
109    fn init_state(world: &World) -> Self::State;
110
111    /// Returns the set of component IDs this query reads.
112    ///
113    /// Used for access conflict detection. Two queries conflict if one writes
114    /// a component that the other reads or writes.
115    ///
116    /// # Arguments
117    ///
118    /// * `state` - The query state
119    ///
120    /// # Returns
121    ///
122    /// Set of component IDs accessed for reading (includes mutable access).
123    fn component_access(state: &Self::State) -> BTreeSet<ComponentId>;
124
125    /// Checks whether this query matches the given archetype.
126    ///
127    /// Returns `true` if entities in the archetype can produce a valid `Item`.
128    /// This is used to filter archetypes during query iteration.
129    ///
130    /// # Arguments
131    ///
132    /// * `state` - The cached query state
133    /// * `archetype` - The archetype to check
134    ///
135    /// # Returns
136    ///
137    /// `true` if entities in this archetype match the query.
138    fn matches_archetype(state: &Self::State, archetype: &Archetype) -> bool;
139
140    /// Fetches data for a specific entity from the world.
141    ///
142    /// Returns `Some(Item)` if the entity has all required components,
143    /// `None` otherwise.
144    ///
145    /// # Arguments
146    ///
147    /// * `state` - The cached query state
148    /// * `world` - Reference to the world containing component data
149    /// * `entity` - The entity to fetch data for
150    ///
151    /// # Returns
152    ///
153    /// `Some(Item)` if the entity matches the query, `None` otherwise.
154    ///
155    /// # Safety Note
156    ///
157    /// This method takes an immutable world reference but may return mutable
158    /// component references. The caller must ensure aliasing rules are
159    /// maintained (typically enforced by the query iterator).
160    fn fetch<'w>(state: &Self::State, world: &'w World, entity: Entity) -> Option<Self::Item<'w>>;
161
162    /// Fetches data for a specific entity from a mutable world reference.
163    ///
164    /// This variant is used when mutable component access is needed.
165    /// The default implementation calls `fetch` with an immutable borrow,
166    /// but mutable query implementations override this.
167    ///
168    /// # Arguments
169    ///
170    /// * `state` - The cached query state
171    /// * `world` - Mutable reference to the world
172    /// * `entity` - The entity to fetch data for
173    ///
174    /// # Returns
175    ///
176    /// `Some(Item)` if the entity matches the query, `None` otherwise.
177    fn fetch_mut<'w>(
178        state: &Self::State,
179        world: &'w mut World,
180        entity: Entity,
181    ) -> Option<Self::Item<'w>> {
182        // Default implementation for read-only queries
183        Self::fetch(state, world, entity)
184    }
185}
186
187// =============================================================================
188// ReadOnlyWorldQuery Trait
189// =============================================================================
190
191/// Marker trait for queries that only read data.
192///
193/// `ReadOnlyWorldQuery` is a marker trait that indicates a query does not
194/// mutate any component data. This enables:
195///
196/// 1. **Parallel Execution**: Multiple read-only queries can run concurrently
197/// 2. **Shared Borrows**: Can coexist with other readers of the same component
198/// 3. **Query Combination**: Read-only queries can be combined more freely
199///
200/// # Safety
201///
202/// Implementors must ensure that the query never mutates component data,
203/// even when given a mutable world reference.
204///
205/// # Built-in Implementations
206///
207/// - `&T` where `T: Component`
208/// - `Entity`
209/// - `Option<Q>` where `Q: ReadOnlyWorldQuery`
210/// - Tuples of read-only queries
211/// - `With<T>` and `Without<T>` filters
212///
213/// # Example
214///
215/// ```
216/// use goud_engine::ecs::Entity;
217/// use goud_engine::ecs::query::ReadOnlyWorldQuery;
218///
219/// // Entity is always read-only
220/// fn requires_read_only<Q: ReadOnlyWorldQuery>() {}
221/// requires_read_only::<Entity>();
222/// ```
223pub trait ReadOnlyWorldQuery: WorldQuery {}
224
225// =============================================================================
226// QueryState Trait
227// =============================================================================
228
229/// Trait for query state types.
230///
231/// Query state caches information needed for efficient query execution.
232/// The state is initialized once and reused for all query operations.
233///
234/// # Requirements
235///
236/// State types must be:
237/// - `Send + Sync`: For parallel query execution
238/// - `Clone`: To allow query state to be copied if needed
239///
240/// # Example
241///
242/// ```
243/// use goud_engine::ecs::component::ComponentId;
244/// use goud_engine::ecs::query::QueryState;
245///
246/// // ComponentId implements QueryState
247/// fn requires_query_state<S: QueryState>() {}
248/// requires_query_state::<ComponentId>();
249/// ```
250pub trait QueryState: Send + Sync + Clone + 'static {}
251
252// Blanket implementation for all qualifying types
253impl<T: Send + Sync + Clone + 'static> QueryState for T {}