Skip to main content

goud_engine/ecs/query/
param.rs

1//! [`SystemParam`] implementation for [`Query`].
2
3use crate::ecs::system::{ReadOnlySystemParam, SystemParam, SystemParamState};
4use crate::ecs::World;
5
6use super::fetch::{Access, ReadOnlyWorldQuery, WorldQuery};
7use super::query_type::Query;
8
9// =============================================================================
10// Query SystemParam Implementation
11// =============================================================================
12
13/// Cached state for Query as a system parameter.
14///
15/// This stores the initialized query and filter states, allowing efficient
16/// reuse across multiple system runs.
17#[derive(Clone)]
18pub struct QuerySystemParamState<Q: WorldQuery, F: WorldQuery> {
19    /// Cached query state.
20    pub(crate) query_state: Q::State,
21    /// Cached filter state.
22    pub(crate) filter_state: F::State,
23}
24
25impl<Q: WorldQuery, F: WorldQuery> std::fmt::Debug for QuerySystemParamState<Q, F>
26where
27    Q::State: std::fmt::Debug,
28    F::State: std::fmt::Debug,
29{
30    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
31        f.debug_struct("QuerySystemParamState")
32            .field("query_state", &self.query_state)
33            .field("filter_state", &self.filter_state)
34            .finish()
35    }
36}
37
38// SAFETY: QuerySystemParamState is Send + Sync if the underlying states are
39unsafe impl<Q: WorldQuery, F: WorldQuery> Send for QuerySystemParamState<Q, F>
40where
41    Q::State: Send,
42    F::State: Send,
43{
44}
45
46unsafe impl<Q: WorldQuery, F: WorldQuery> Sync for QuerySystemParamState<Q, F>
47where
48    Q::State: Sync,
49    F::State: Sync,
50{
51}
52
53impl<Q: WorldQuery + 'static, F: WorldQuery + 'static> SystemParamState
54    for QuerySystemParamState<Q, F>
55where
56    Q::State: Clone + Send + Sync,
57    F::State: Clone + Send + Sync,
58{
59    fn init(world: &mut World) -> Self {
60        Self {
61            query_state: Q::init_state(world),
62            filter_state: F::init_state(world),
63        }
64    }
65}
66
67/// `Query<Q, F>` as a system parameter.
68///
69/// This allows functions to declare queries as parameters:
70///
71/// ```ignore
72/// fn my_system(query: Query<&Position, With<Player>>) {
73///     for pos in query.iter() {
74///         println!("Player position: {:?}", pos);
75///     }
76/// }
77/// ```
78impl<Q: WorldQuery + 'static, F: WorldQuery + 'static> SystemParam for Query<Q, F>
79where
80    Q::State: Clone + Send + Sync + 'static,
81    F::State: Clone + Send + Sync + 'static,
82{
83    type State = QuerySystemParamState<Q, F>;
84    type Item<'w, 's> = Query<Q, F>;
85
86    fn update_access(state: &Self::State, access: &mut Access) {
87        // Add component access from the query
88        for id in Q::component_access(&state.query_state) {
89            // For now, we add as read. Mutable queries need special handling.
90            // The WorldQuery implementation determines read vs write.
91            access.add_read(id);
92        }
93        // Filters don't count as access (they only check archetype)
94    }
95
96    fn get_param<'w, 's>(state: &'s mut Self::State, _world: &'w World) -> Self::Item<'w, 's> {
97        Query::from_state(state.query_state.clone(), state.filter_state.clone())
98    }
99
100    fn get_param_mut<'w, 's>(
101        state: &'s mut Self::State,
102        _world: &'w mut World,
103    ) -> Self::Item<'w, 's> {
104        // For mutable access, we still return a Query that can iterate mutably
105        Query::from_state(state.query_state.clone(), state.filter_state.clone())
106    }
107}
108
109/// Query with read-only data query is a read-only system parameter.
110impl<Q: ReadOnlyWorldQuery + 'static, F: ReadOnlyWorldQuery + 'static> ReadOnlySystemParam
111    for Query<Q, F>
112where
113    Q::State: Clone + Send + Sync + 'static,
114    F::State: Clone + Send + Sync + 'static,
115{
116}