goud_engine/ecs/system/system_param/resource_params.rs
1//! [`SystemParam`] implementations for resource access types.
2//!
3//! Covers [`Res`], [`ResMut`], [`NonSend`], and [`NonSendMut`].
4
5use crate::ecs::query::Access;
6use crate::ecs::resource::{NonSend, NonSendMut, NonSendResource, NonSendResourceId};
7use crate::ecs::resource::{Res, ResMut, Resource, ResourceId};
8use crate::ecs::World;
9
10use super::traits::{ReadOnlySystemParam, SystemParam, SystemParamState};
11
12// =============================================================================
13// Res<T> - Immutable Resource SystemParam
14// =============================================================================
15
16/// State for `Res<T>` system parameter.
17///
18/// Caches the resource ID for efficient access and conflict detection.
19#[derive(Debug, Clone)]
20pub struct ResState<T: Resource> {
21 _marker: std::marker::PhantomData<T>,
22}
23
24impl<T: Resource> SystemParamState for ResState<T> {
25 fn init(_world: &mut World) -> Self {
26 Self {
27 _marker: std::marker::PhantomData,
28 }
29 }
30}
31
32/// `Res<T>` as a system parameter for immutable resource access.
33///
34/// # Example
35///
36/// ```ignore
37/// fn print_time(time: Res<Time>) {
38/// println!("Delta: {}", time.delta);
39/// }
40/// ```
41///
42/// # Panics
43///
44/// When used as a system parameter, `Res<T>` will panic if the resource
45/// does not exist in the world. Use `Option<Res<T>>` for optional access.
46impl<T: Resource> SystemParam for Res<'_, T> {
47 type State = ResState<T>;
48 type Item<'w, 's> = Res<'w, T>;
49
50 fn update_access(_state: &Self::State, access: &mut Access) {
51 // Register read access to the resource
52 access.add_resource_read(ResourceId::of::<T>());
53 }
54
55 fn get_param<'w, 's>(_state: &'s mut Self::State, world: &'w World) -> Self::Item<'w, 's> {
56 world
57 .resource::<T>()
58 .expect("Resource does not exist. Use Option<Res<T>> for optional access.")
59 }
60
61 fn get_param_mut<'w, 's>(
62 state: &'s mut Self::State,
63 world: &'w mut World,
64 ) -> Self::Item<'w, 's> {
65 // Immutable resource access, so we just use get_param
66 Self::get_param(state, world)
67 }
68}
69
70/// `Res<T>` is read-only.
71impl<T: Resource> ReadOnlySystemParam for Res<'_, T> {}
72
73// =============================================================================
74// ResMut<T> - Mutable Resource SystemParam
75// =============================================================================
76
77/// State for `ResMut<T>` system parameter.
78///
79/// Caches the resource ID for efficient access and conflict detection.
80#[derive(Debug, Clone)]
81pub struct ResMutState<T: Resource> {
82 _marker: std::marker::PhantomData<T>,
83}
84
85impl<T: Resource> SystemParamState for ResMutState<T> {
86 fn init(_world: &mut World) -> Self {
87 Self {
88 _marker: std::marker::PhantomData,
89 }
90 }
91}
92
93/// `ResMut<T>` as a system parameter for mutable resource access.
94///
95/// # Example
96///
97/// ```ignore
98/// fn update_time(mut time: ResMut<Time>) {
99/// time.total += time.delta;
100/// }
101/// ```
102///
103/// # Panics
104///
105/// When used as a system parameter, `ResMut<T>` will panic if the resource
106/// does not exist in the world. Use `Option<ResMut<T>>` for optional access.
107impl<T: Resource> SystemParam for ResMut<'_, T> {
108 type State = ResMutState<T>;
109 type Item<'w, 's> = ResMut<'w, T>;
110
111 fn update_access(_state: &Self::State, access: &mut Access) {
112 // Register write access to the resource
113 access.add_resource_write(ResourceId::of::<T>());
114 }
115
116 fn get_param<'w, 's>(_state: &'s mut Self::State, _world: &'w World) -> Self::Item<'w, 's> {
117 // ResMut requires mutable world access, so this panics
118 panic!("ResMut<T> requires mutable world access. Use get_param_mut instead.")
119 }
120
121 fn get_param_mut<'w, 's>(
122 _state: &'s mut Self::State,
123 world: &'w mut World,
124 ) -> Self::Item<'w, 's> {
125 world
126 .resource_mut::<T>()
127 .expect("Resource does not exist. Use Option<ResMut<T>> for optional access.")
128 }
129}
130
131// ResMut is NOT ReadOnlySystemParam - intentionally omitted
132
133// =============================================================================
134// NonSend<T> - Immutable Non-Send Resource SystemParam
135// =============================================================================
136
137/// State for `NonSend<T>` system parameter.
138///
139/// Caches the non-send resource ID for efficient access and conflict detection.
140///
141/// Note: Uses `PhantomData<fn() -> T>` to be Send+Sync regardless of T's bounds.
142/// This is safe because the state only stores type information for conflict detection,
143/// not the actual resource data.
144#[derive(Debug, Clone)]
145pub struct NonSendState<T: NonSendResource> {
146 // Use fn() -> T to be Send + Sync regardless of T's bounds
147 _marker: std::marker::PhantomData<fn() -> T>,
148}
149
150impl<T: NonSendResource> SystemParamState for NonSendState<T> {
151 fn init(_world: &mut World) -> Self {
152 Self {
153 _marker: std::marker::PhantomData,
154 }
155 }
156}
157
158/// `NonSend<T>` as a system parameter for immutable non-send resource access.
159///
160/// # Thread Safety
161///
162/// Systems using `NonSend<T>` are constrained to run on the main thread.
163/// This is enforced by the scheduler.
164///
165/// # Example
166///
167/// ```ignore
168/// fn print_window(window: NonSend<WindowHandle>) {
169/// println!("Window ID: {}", window.id);
170/// }
171/// ```
172///
173/// # Panics
174///
175/// When used as a system parameter, `NonSend<T>` will panic if the non-send
176/// resource does not exist in the world.
177impl<T: NonSendResource> SystemParam for NonSend<'_, T> {
178 type State = NonSendState<T>;
179 type Item<'w, 's> = NonSend<'w, T>;
180
181 fn update_access(_state: &Self::State, access: &mut Access) {
182 // Register read access to the non-send resource
183 access.add_non_send_read(NonSendResourceId::of::<T>());
184 }
185
186 fn get_param<'w, 's>(_state: &'s mut Self::State, world: &'w World) -> Self::Item<'w, 's> {
187 world
188 .non_send_resource::<T>()
189 .expect("Non-send resource does not exist. Use Option<NonSend<T>> for optional access.")
190 }
191
192 fn get_param_mut<'w, 's>(
193 state: &'s mut Self::State,
194 world: &'w mut World,
195 ) -> Self::Item<'w, 's> {
196 // Immutable non-send resource access, so we just use get_param
197 Self::get_param(state, world)
198 }
199}
200
201/// `NonSend<T>` is read-only.
202impl<T: NonSendResource> ReadOnlySystemParam for NonSend<'_, T> {}
203
204// =============================================================================
205// NonSendMut<T> - Mutable Non-Send Resource SystemParam
206// =============================================================================
207
208/// State for `NonSendMut<T>` system parameter.
209///
210/// Caches the non-send resource ID for efficient access and conflict detection.
211///
212/// Note: Uses `PhantomData<fn() -> T>` to be Send+Sync regardless of T's bounds.
213/// This is safe because the state only stores type information for conflict detection,
214/// not the actual resource data.
215#[derive(Debug, Clone)]
216pub struct NonSendMutState<T: NonSendResource> {
217 // Use fn() -> T to be Send + Sync regardless of T's bounds
218 _marker: std::marker::PhantomData<fn() -> T>,
219}
220
221impl<T: NonSendResource> SystemParamState for NonSendMutState<T> {
222 fn init(_world: &mut World) -> Self {
223 Self {
224 _marker: std::marker::PhantomData,
225 }
226 }
227}
228
229/// `NonSendMut<T>` as a system parameter for mutable non-send resource access.
230///
231/// # Thread Safety
232///
233/// Systems using `NonSendMut<T>` are constrained to run on the main thread.
234/// This is enforced by the scheduler.
235///
236/// # Example
237///
238/// ```ignore
239/// fn update_window(mut window: NonSendMut<WindowHandle>) {
240/// window.update_title("New Title");
241/// }
242/// ```
243///
244/// # Panics
245///
246/// When used as a system parameter, `NonSendMut<T>` will panic if the non-send
247/// resource does not exist in the world.
248impl<T: NonSendResource> SystemParam for NonSendMut<'_, T> {
249 type State = NonSendMutState<T>;
250 type Item<'w, 's> = NonSendMut<'w, T>;
251
252 fn update_access(_state: &Self::State, access: &mut Access) {
253 // Register write access to the non-send resource
254 access.add_non_send_write(NonSendResourceId::of::<T>());
255 }
256
257 fn get_param<'w, 's>(_state: &'s mut Self::State, _world: &'w World) -> Self::Item<'w, 's> {
258 // NonSendMut requires mutable world access, so this panics
259 panic!("NonSendMut<T> requires mutable world access. Use get_param_mut instead.")
260 }
261
262 fn get_param_mut<'w, 's>(
263 _state: &'s mut Self::State,
264 world: &'w mut World,
265 ) -> Self::Item<'w, 's> {
266 world.non_send_resource_mut::<T>().expect(
267 "Non-send resource does not exist. Use Option<NonSendMut<T>> for optional access.",
268 )
269 }
270}
271
272// NonSendMut is NOT ReadOnlySystemParam - intentionally omitted