1use std::cell::RefMut;
2use std::ops::{Deref, DerefMut};
3
4use crate::ecs::resources::Resources;
5
6pub struct Res<'a, T: hecs::Component> {
10 pub(crate) data: hecs::Ref<'a, T>,
11}
12
13impl<'a, T: hecs::Component> Deref for Res<'a, T> {
14 type Target = T;
15 fn deref(&self) -> &Self::Target {
16 &self.data
17 }
18}
19
20pub struct ResMut<'a, T: hecs::Component> {
24 data: hecs::RefMut<'a, T>,
25}
26
27impl<'a, T: hecs::Component> Deref for ResMut<'a, T> {
28 type Target = T;
29 fn deref(&self) -> &Self::Target {
30 &self.data
31 }
32}
33
34impl<'a, T: hecs::Component> DerefMut for ResMut<'a, T> {
35 fn deref_mut(&mut self) -> &mut Self::Target {
36 &mut self.data
37 }
38}
39
40pub struct Query<'a, Q: hecs::Query> {
65 world: &'a hecs::World,
66 borrow: hecs::QueryBorrow<'a, Q>,
67}
68
69impl<'a, Q: hecs::Query> Deref for Query<'a, Q> {
70 type Target = hecs::QueryBorrow<'a, Q>;
71 fn deref(&self) -> &Self::Target {
72 &self.borrow
73 }
74}
75
76impl<'a, Q: hecs::Query> DerefMut for Query<'a, Q> {
77 fn deref_mut(&mut self) -> &mut Self::Target {
78 &mut self.borrow
79 }
80}
81
82impl<'q, Q: hecs::Query> IntoIterator for &'q mut Query<'_, Q> {
83 type Item = Q::Item<'q>;
84 type IntoIter = hecs::QueryIter<'q, Q>;
85
86 fn into_iter(self) -> Self::IntoIter {
87 (&mut self.borrow).into_iter()
88 }
89}
90
91impl<'a, Q: hecs::Query> Query<'a, Q> {
92 pub fn get(&self, entity: hecs::Entity) -> hecs::QueryOne<'_, Q> {
95 self.world.query_one::<Q>(entity)
96 }
97
98 pub fn with<R: hecs::Query>(self) -> hecs::QueryBorrow<'a, hecs::With<Q, R>> {
102 self.borrow.with::<R>()
103 }
104
105 pub fn without<R: hecs::Query>(self) -> hecs::QueryBorrow<'a, hecs::Without<Q, R>> {
108 self.borrow.without::<R>()
109 }
110
111 pub fn single(&mut self) -> Q::Item<'_> {
119 self.get_single()
120 .expect("Query::single: expected exactly one matching entity")
121 }
122
123 pub fn get_single(&mut self) -> Option<Q::Item<'_>> {
126 let mut iter = self.borrow.iter();
127 let first = iter.next()?;
128 if iter.next().is_some() {
129 return None;
130 }
131 Some(first)
132 }
133}
134
135pub struct Commands<'a> {
144 buffer: RefMut<'a, hecs::CommandBuffer>,
145 resource_entity: hecs::Entity,
146 resources: &'a Resources,
148}
149
150impl<'a> Commands<'a> {
151 pub fn insert_resource<T: hecs::Component>(&mut self, res: T) {
157 self.buffer.insert_one(self.resource_entity, res);
158 self.resources.bump_generation();
159 }
160
161 pub fn remove_resource<T: hecs::Component>(&mut self) {
163 self.buffer.remove_one::<T>(self.resource_entity);
164 }
165}
166
167impl<'a> Deref for Commands<'a> {
168 type Target = hecs::CommandBuffer;
169 fn deref(&self) -> &Self::Target {
170 &self.buffer
171 }
172}
173
174impl<'a> DerefMut for Commands<'a> {
175 fn deref_mut(&mut self) -> &mut Self::Target {
176 &mut self.buffer
177 }
178}
179
180pub struct Local<'a, T: Default + Send + Sync + 'static> {
190 data: &'a mut T,
191}
192
193impl<'a, T: Default + Send + Sync + 'static> Deref for Local<'a, T> {
194 type Target = T;
195 fn deref(&self) -> &Self::Target {
196 self.data
197 }
198}
199
200impl<'a, T: Default + Send + Sync + 'static> DerefMut for Local<'a, T> {
201 fn deref_mut(&mut self) -> &mut Self::Target {
202 self.data
203 }
204}
205
206pub trait SystemParam {
214 type Item<'a>;
215 type State: Default + 'static;
216 fn fetch<'a>(
217 state: &'a mut Self::State,
218 world: &'a hecs::World,
219 resources: &'a Resources,
220 ) -> Self::Item<'a>;
221}
222
223impl<T> SystemParam for Res<'static, T>
224where
225 T: 'static + Sync + Send,
226{
227 type Item<'a> = Res<'a, T>;
228 type State = ();
229
230 fn fetch<'a>(
231 _state: &'a mut Self::State,
232 world: &'a hecs::World,
233 resource: &'a Resources,
234 ) -> Self::Item<'a> {
235 Res {
236 data: resource.get_resource(world),
237 }
238 }
239}
240
241impl<T> SystemParam for Option<Res<'static, T>>
242where
243 T: 'static + Sync + Send,
244{
245 type Item<'a> = Option<Res<'a, T>>;
246 type State = ();
247
248 fn fetch<'a>(
249 _state: &'a mut Self::State,
250 world: &'a hecs::World,
251 resource: &'a Resources,
252 ) -> Self::Item<'a> {
253 if resource.has_resource::<T>(world) {
254 return Some(Res {
255 data: resource.get_resource(world),
256 });
257 }
258
259 None
260 }
261}
262
263impl<T> SystemParam for ResMut<'static, T>
264where
265 T: 'static + Sync + Send,
266{
267 type Item<'a> = ResMut<'a, T>;
268 type State = ();
269
270 fn fetch<'a>(
271 _state: &'a mut Self::State,
272 world: &'a hecs::World,
273 resource: &'a Resources,
274 ) -> Self::Item<'a> {
275 ResMut {
276 data: resource.get_resource_mut(world),
277 }
278 }
279}
280
281impl<T> SystemParam for Option<ResMut<'static, T>>
282where
283 T: 'static + Sync + Send,
284{
285 type Item<'a> = Option<ResMut<'a, T>>;
286 type State = ();
287
288 fn fetch<'a>(
289 _state: &'a mut Self::State,
290 world: &'a hecs::World,
291 resource: &'a Resources,
292 ) -> Self::Item<'a> {
293 if resource.has_resource::<T>(world) {
294 return Some(ResMut {
295 data: resource.get_resource_mut(world),
296 });
297 }
298
299 None
300 }
301}
302
303impl<Q> SystemParam for Query<'static, Q>
304where
305 Q: hecs::Query + 'static,
306{
307 type Item<'a> = Query<'a, Q>;
308 type State = ();
309
310 fn fetch<'a>(
311 _state: &'a mut Self::State,
312 world: &'a hecs::World,
313 _resources: &'a Resources,
314 ) -> Self::Item<'a> {
315 Query {
316 world: world,
317 borrow: world.query::<Q>(),
318 }
319 }
320}
321
322impl SystemParam for Commands<'static> {
323 type Item<'a> = Commands<'a>;
324 type State = ();
325
326 fn fetch<'a>(
327 _state: &'a mut Self::State,
328 _world: &'a hecs::World,
329 resources: &'a Resources,
330 ) -> Self::Item<'a> {
331 Commands {
332 buffer: resources.get_command_buffer(),
333 resource_entity: resources.resource_entity,
334 resources,
335 }
336 }
337}
338
339impl SystemParam for &'static hecs::World {
340 type Item<'a> = &'a hecs::World;
341 type State = ();
342
343 fn fetch<'a>(
344 _state: &'a mut Self::State,
345 world: &'a hecs::World,
346 _resources: &'a Resources,
347 ) -> Self::Item<'a> {
348 world
349 }
350}
351
352impl SystemParam for &'static Resources {
353 type Item<'a> = &'a Resources;
354 type State = ();
355
356 fn fetch<'a>(
357 _state: &'a mut Self::State,
358 _world: &'a hecs::World,
359 resources: &'a Resources,
360 ) -> Self::Item<'a> {
361 resources
362 }
363}
364
365impl<T> SystemParam for Local<'static, T>
366where
367 T: Default + Send + Sync + 'static,
368{
369 type Item<'a> = Local<'a, T>;
370 type State = T;
371
372 fn fetch<'a>(
373 state: &'a mut Self::State,
374 _world: &'a hecs::World,
375 _resources: &'a Resources,
376 ) -> Self::Item<'a> {
377 Local { data: state }
378 }
379}
380
381pub trait System: 'static {
383 fn run(&mut self, world: &hecs::World, resources: &Resources);
384}
385
386pub struct FunctionSystem<F, Marker, State = ()> {
391 pub func: F,
392 state: State,
393 _marker: std::marker::PhantomData<Marker>,
394}
395
396pub trait IntoSystem<Marker> {
401 type System: System;
402
403 fn into_system(self) -> Self::System;
404}
405
406macro_rules! impl_system {
407 ($($param:ident),*) => {
408 impl<T, $($param),*> IntoSystem<($($param,)*)> for T
409 where
410 T: for<'a> FnMut($($param::Item<'a>),*) + 'static,
411 for<'a> &'a mut T: FnMut($($param),*),
412 $($param: SystemParam + 'static),*
413 {
414 type System = FunctionSystem<T, ($($param,)*), ($($param::State,)*)>;
415
416 fn into_system(self) -> Self::System {
417 FunctionSystem {
418 func: self,
419 state: Default::default(),
420 _marker: std::marker::PhantomData,
421 }
422 }
423 }
424
425 impl<T, $($param),*> System for FunctionSystem<T, ($($param,)*), ($($param::State,)*)>
426 where
427 T: for<'a> FnMut($($param::Item<'a>),*) + 'static,
428 $($param: SystemParam + 'static),*
429 {
430 fn run(&mut self, _world: &hecs::World, _resources: &Resources) {
431 #[allow(non_snake_case)]
432 let ($($param,)*) = &mut self.state;
433 (self.func)($($param::fetch($param, _world, _resources)),*);
434 }
435 }
436 };
437}
438
439impl_system!();
440impl_system!(A);
441impl_system!(A, B);
442impl_system!(A, B, C);
443impl_system!(A, B, C, D);
444impl_system!(A, B, C, D, E);
445impl_system!(A, B, C, D, E, F);
446impl_system!(A, B, C, D, E, F, G);
447impl_system!(A, B, C, D, E, F, G, H);