1use std::cell::RefMut;
2use std::ops::{Deref, DerefMut};
3
4use crate::ecs::resources::Resources;
5use crate::threading::SpawnableFuture;
9
10#[derive(Clone, Copy)]
20pub struct RequiredResource {
21 pub name: &'static str,
22 pub type_id: std::any::TypeId,
23 pub present: fn(&hecs::World, &Resources) -> bool,
24 pub hint: Option<&'static str>,
31}
32
33pub struct Res<'a, T: hecs::Component> {
37 pub(crate) data: hecs::Ref<'a, T>,
38}
39
40impl<'a, T: hecs::Component> Deref for Res<'a, T> {
41 type Target = T;
42 fn deref(&self) -> &Self::Target {
43 &self.data
44 }
45}
46
47pub struct ResMut<'a, T: hecs::Component> {
51 data: hecs::RefMut<'a, T>,
52}
53
54impl<'a, T: hecs::Component> Deref for ResMut<'a, T> {
55 type Target = T;
56 fn deref(&self) -> &Self::Target {
57 &self.data
58 }
59}
60
61impl<'a, T: hecs::Component> DerefMut for ResMut<'a, T> {
62 fn deref_mut(&mut self) -> &mut Self::Target {
63 &mut self.data
64 }
65}
66
67pub struct Query<'a, Q: hecs::Query> {
92 world: &'a hecs::World,
93 borrow: hecs::QueryBorrow<'a, Q>,
94}
95
96impl<'a, Q: hecs::Query> Deref for Query<'a, Q> {
97 type Target = hecs::QueryBorrow<'a, Q>;
98 fn deref(&self) -> &Self::Target {
99 &self.borrow
100 }
101}
102
103impl<'a, Q: hecs::Query> DerefMut for Query<'a, Q> {
104 fn deref_mut(&mut self) -> &mut Self::Target {
105 &mut self.borrow
106 }
107}
108
109impl<'q, Q: hecs::Query> IntoIterator for &'q mut Query<'_, Q> {
110 type Item = Q::Item<'q>;
111 type IntoIter = hecs::QueryIter<'q, Q>;
112
113 fn into_iter(self) -> Self::IntoIter {
114 (&mut self.borrow).into_iter()
115 }
116}
117
118impl<'a, Q: hecs::Query> Query<'a, Q> {
119 pub fn get(&self, entity: hecs::Entity) -> hecs::QueryOne<'_, Q> {
122 self.world.query_one::<Q>(entity)
123 }
124
125 pub fn with<R: hecs::Query>(self) -> hecs::QueryBorrow<'a, hecs::With<Q, R>> {
129 self.borrow.with::<R>()
130 }
131
132 pub fn without<R: hecs::Query>(self) -> hecs::QueryBorrow<'a, hecs::Without<Q, R>> {
135 self.borrow.without::<R>()
136 }
137
138 pub fn single(&mut self) -> Q::Item<'_> {
146 self.get_single()
147 .expect("Query::single: expected exactly one matching entity")
148 }
149
150 pub fn get_single(&mut self) -> Option<Q::Item<'_>> {
153 let mut iter = self.borrow.iter();
154 let first = iter.next()?;
155 if iter.next().is_some() {
156 return None;
157 }
158 Some(first)
159 }
160}
161
162pub struct Commands<'a> {
171 buffer: RefMut<'a, hecs::CommandBuffer>,
172 resource_entity: hecs::Entity,
173 resources: &'a Resources,
175}
176
177impl<'a> Commands<'a> {
178 pub fn insert_resource<T: hecs::Component>(&mut self, res: T) {
184 self.buffer.insert_one(self.resource_entity, res);
185 self.resources.bump_generation();
186 }
187
188 pub fn remove_resource<T: hecs::Component>(&mut self) {
190 self.buffer.remove_one::<T>(self.resource_entity);
191 }
192}
193
194impl<'a> Deref for Commands<'a> {
195 type Target = hecs::CommandBuffer;
196 fn deref(&self) -> &Self::Target {
197 &self.buffer
198 }
199}
200
201impl<'a> DerefMut for Commands<'a> {
202 fn deref_mut(&mut self) -> &mut Self::Target {
203 &mut self.buffer
204 }
205}
206
207pub struct Local<'a, T: Default + Send + Sync + 'static> {
217 data: &'a mut T,
218}
219
220impl<'a, T: Default + Send + Sync + 'static> Deref for Local<'a, T> {
221 type Target = T;
222 fn deref(&self) -> &Self::Target {
223 self.data
224 }
225}
226
227impl<'a, T: Default + Send + Sync + 'static> DerefMut for Local<'a, T> {
228 fn deref_mut(&mut self) -> &mut Self::Target {
229 self.data
230 }
231}
232
233pub trait SystemParam {
241 type Item<'a>;
242 type State: Default + 'static;
243 fn fetch<'a>(
244 state: &'a mut Self::State,
245 world: &'a hecs::World,
246 resources: &'a Resources,
247 ) -> Self::Item<'a>;
248
249 fn requires() -> Vec<RequiredResource> {
260 Vec::new()
261 }
262}
263
264impl<T> SystemParam for Res<'static, T>
265where
266 T: 'static + Sync + Send,
267{
268 type Item<'a> = Res<'a, T>;
269 type State = ();
270
271 fn fetch<'a>(
272 _state: &'a mut Self::State,
273 world: &'a hecs::World,
274 resource: &'a Resources,
275 ) -> Self::Item<'a> {
276 Res {
277 data: resource.get_resource(world),
278 }
279 }
280
281 fn requires() -> Vec<RequiredResource> {
282 vec![RequiredResource {
283 name: std::any::type_name::<T>(),
284 type_id: std::any::TypeId::of::<T>(),
285 present: |world, resources| resources.has_resource::<T>(world),
286 hint: None,
287 }]
288 }
289}
290
291impl<T> SystemParam for Option<Res<'static, T>>
292where
293 T: 'static + Sync + Send,
294{
295 type Item<'a> = Option<Res<'a, T>>;
296 type State = ();
297
298 fn fetch<'a>(
299 _state: &'a mut Self::State,
300 world: &'a hecs::World,
301 resource: &'a Resources,
302 ) -> Self::Item<'a> {
303 if resource.has_resource::<T>(world) {
304 return Some(Res {
305 data: resource.get_resource(world),
306 });
307 }
308
309 None
310 }
311}
312
313impl<T> SystemParam for ResMut<'static, T>
314where
315 T: 'static + Sync + Send,
316{
317 type Item<'a> = ResMut<'a, T>;
318 type State = ();
319
320 fn fetch<'a>(
321 _state: &'a mut Self::State,
322 world: &'a hecs::World,
323 resource: &'a Resources,
324 ) -> Self::Item<'a> {
325 ResMut {
326 data: resource.get_resource_mut(world),
327 }
328 }
329
330 fn requires() -> Vec<RequiredResource> {
331 vec![RequiredResource {
332 name: std::any::type_name::<T>(),
333 type_id: std::any::TypeId::of::<T>(),
334 present: |world, resources| resources.has_resource::<T>(world),
335 hint: None,
336 }]
337 }
338}
339
340impl<T> SystemParam for Option<ResMut<'static, T>>
341where
342 T: 'static + Sync + Send,
343{
344 type Item<'a> = Option<ResMut<'a, T>>;
345 type State = ();
346
347 fn fetch<'a>(
348 _state: &'a mut Self::State,
349 world: &'a hecs::World,
350 resource: &'a Resources,
351 ) -> Self::Item<'a> {
352 if resource.has_resource::<T>(world) {
353 return Some(ResMut {
354 data: resource.get_resource_mut(world),
355 });
356 }
357
358 None
359 }
360}
361
362impl<Q> SystemParam for Query<'static, Q>
363where
364 Q: hecs::Query + 'static,
365{
366 type Item<'a> = Query<'a, Q>;
367 type State = ();
368
369 fn fetch<'a>(
370 _state: &'a mut Self::State,
371 world: &'a hecs::World,
372 _resources: &'a Resources,
373 ) -> Self::Item<'a> {
374 Query {
375 world: world,
376 borrow: world.query::<Q>(),
377 }
378 }
379}
380
381impl SystemParam for Commands<'static> {
382 type Item<'a> = Commands<'a>;
383 type State = ();
384
385 fn fetch<'a>(
386 _state: &'a mut Self::State,
387 _world: &'a hecs::World,
388 resources: &'a Resources,
389 ) -> Self::Item<'a> {
390 Commands {
391 buffer: resources.get_command_buffer(),
392 resource_entity: resources.resource_entity,
393 resources,
394 }
395 }
396}
397
398impl SystemParam for &'static hecs::World {
399 type Item<'a> = &'a hecs::World;
400 type State = ();
401
402 fn fetch<'a>(
403 _state: &'a mut Self::State,
404 world: &'a hecs::World,
405 _resources: &'a Resources,
406 ) -> Self::Item<'a> {
407 world
408 }
409}
410
411impl SystemParam for &'static Resources {
412 type Item<'a> = &'a Resources;
413 type State = ();
414
415 fn fetch<'a>(
416 _state: &'a mut Self::State,
417 _world: &'a hecs::World,
418 resources: &'a Resources,
419 ) -> Self::Item<'a> {
420 resources
421 }
422}
423
424impl<T> SystemParam for Local<'static, T>
425where
426 T: Default + Send + Sync + 'static,
427{
428 type Item<'a> = Local<'a, T>;
429 type State = T;
430
431 fn fetch<'a>(
432 state: &'a mut Self::State,
433 _world: &'a hecs::World,
434 _resources: &'a Resources,
435 ) -> Self::Item<'a> {
436 Local { data: state }
437 }
438}
439
440pub trait System: 'static {
442 fn run(&mut self, world: &hecs::World, resources: &Resources);
443
444 fn requires(&self) -> Vec<RequiredResource> {
451 Vec::new()
452 }
453
454 fn name(&self) -> &'static str {
460 std::any::type_name::<Self>()
461 }
462
463 fn ordering_id(&self) -> std::any::TypeId {
472 std::any::TypeId::of::<Self>()
473 }
474
475 fn after_ids(&self) -> &[std::any::TypeId] {
479 &[]
480 }
481
482 fn before_ids(&self) -> &[std::any::TypeId] {
486 &[]
487 }
488}
489
490pub struct Labeled<S: System> {
499 inner: S,
500 after: Vec<std::any::TypeId>,
501 before: Vec<std::any::TypeId>,
502}
503
504impl<S: System> Labeled<S> {
505 pub fn after<F: 'static, Marker>(mut self, system: F) -> Self
508 where
509 F: IntoSystem<Marker>,
510 {
511 let _ = system;
512 self.after.push(std::any::TypeId::of::<F>());
513 self
514 }
515
516 pub fn before<F: 'static, Marker>(mut self, system: F) -> Self
519 where
520 F: IntoSystem<Marker>,
521 {
522 let _ = system;
523 self.before.push(std::any::TypeId::of::<F>());
524 self
525 }
526}
527
528impl<S: System> System for Labeled<S> {
529 fn run(&mut self, world: &hecs::World, resources: &Resources) {
530 self.inner.run(world, resources)
531 }
532
533 fn requires(&self) -> Vec<RequiredResource> {
534 self.inner.requires()
535 }
536
537 fn name(&self) -> &'static str {
538 self.inner.name()
539 }
540
541 fn ordering_id(&self) -> std::any::TypeId {
542 self.inner.ordering_id()
543 }
544
545 fn after_ids(&self) -> &[std::any::TypeId] {
546 &self.after
547 }
548
549 fn before_ids(&self) -> &[std::any::TypeId] {
550 &self.before
551 }
552}
553
554impl<S: System> IntoSystem<()> for Labeled<S> {
555 type System = Self;
556
557 fn into_system(self) -> Self::System {
558 self
559 }
560}
561
562pub trait SystemOrderingExt<Marker>: IntoSystem<Marker> + Sized {
572 fn after<F: 'static, Marker2>(self, system: F) -> Labeled<Self::System>
574 where
575 F: IntoSystem<Marker2>,
576 {
577 let _ = system;
578 Labeled {
579 inner: self.into_system(),
580 after: vec![std::any::TypeId::of::<F>()],
581 before: Vec::new(),
582 }
583 }
584
585 fn before<F: 'static, Marker2>(self, system: F) -> Labeled<Self::System>
587 where
588 F: IntoSystem<Marker2>,
589 {
590 let _ = system;
591 Labeled {
592 inner: self.into_system(),
593 after: Vec::new(),
594 before: vec![std::any::TypeId::of::<F>()],
595 }
596 }
597}
598
599impl<T, Marker> SystemOrderingExt<Marker> for T where T: IntoSystem<Marker> {}
600
601pub struct FunctionSystem<F, Marker, State = ()> {
606 pub func: F,
607 state: State,
608 _marker: std::marker::PhantomData<Marker>,
609}
610
611pub trait IntoSystem<Marker> {
616 type System: System;
617
618 fn into_system(self) -> Self::System;
619}
620
621macro_rules! impl_system {
622 ($($param:ident),*) => {
623 impl<T, $($param),*> IntoSystem<($($param,)*)> for T
624 where
625 T: for<'a> FnMut($($param::Item<'a>),*) + 'static,
626 for<'a> &'a mut T: FnMut($($param),*),
627 $($param: SystemParam + 'static),*
628 {
629 type System = FunctionSystem<T, ($($param,)*), ($($param::State,)*)>;
630
631 fn into_system(self) -> Self::System {
632 FunctionSystem {
633 func: self,
634 state: Default::default(),
635 _marker: std::marker::PhantomData,
636 }
637 }
638 }
639
640 impl<T, $($param),*> System for FunctionSystem<T, ($($param,)*), ($($param::State,)*)>
641 where
642 T: for<'a> FnMut($($param::Item<'a>),*) + 'static,
643 $($param: SystemParam + 'static),*
644 {
645 fn run(&mut self, _world: &hecs::World, _resources: &Resources) {
646 #[allow(non_snake_case)]
647 let ($($param,)*) = &mut self.state;
648 (self.func)($($param::fetch($param, _world, _resources)),*);
649 }
650
651 fn requires(&self) -> Vec<RequiredResource> {
652 let mut _v = Vec::new();
653 $(_v.extend($param::requires());)*
654 _v
655 }
656
657 fn name(&self) -> &'static str {
658 std::any::type_name::<T>()
659 }
660
661 fn ordering_id(&self) -> std::any::TypeId {
662 std::any::TypeId::of::<T>()
663 }
664 }
665 };
666}
667
668impl_system!();
669impl_system!(A);
670impl_system!(A, B);
671impl_system!(A, B, C);
672impl_system!(A, B, C, D);
673impl_system!(A, B, C, D, E);
674impl_system!(A, B, C, D, E, F);
675impl_system!(A, B, C, D, E, F, G);
676impl_system!(A, B, C, D, E, F, G, H);
677impl_system!(A, B, C, D, E, F, G, H, I);
678impl_system!(A, B, C, D, E, F, G, H, I, J);
679impl_system!(A, B, C, D, E, F, G, H, I, J, K);
680impl_system!(A, B, C, D, E, F, G, H, I, J, K, L);
681
682pub struct OnceFunctionSystem<F, Marker, State = ()> {
689 func: F,
690 state: State,
691 done: bool,
692 _marker: std::marker::PhantomData<Marker>,
693}
694
695pub trait OnceExt<Marker> {
717 type System: System;
718 fn once(self) -> Self::System;
719}
720
721macro_rules! impl_once_system {
722 ($($param:ident),*) => {
723 impl<T, $($param),*> OnceExt<($($param,)*)> for T
724 where
725 T: for<'a> FnMut($($param::Item<'a>),*) -> Option<()> + 'static,
726 for<'a> &'a mut T: FnMut($($param),*) -> Option<()>,
727 $($param: SystemParam + 'static),*
728 {
729 type System = OnceFunctionSystem<T, ($($param,)*), ($($param::State,)*)>;
730
731 fn once(self) -> Self::System {
732 OnceFunctionSystem {
733 func: self,
734 state: Default::default(),
735 done: false,
736 _marker: std::marker::PhantomData,
737 }
738 }
739 }
740
741 impl<T, $($param),*> IntoSystem<($($param,)*)> for OnceFunctionSystem<T, ($($param,)*), ($($param::State,)*)>
742 where
743 T: for<'a> FnMut($($param::Item<'a>),*) -> Option<()> + 'static,
744 $($param: SystemParam + 'static),*
745 {
746 type System = Self;
747
748 fn into_system(self) -> Self::System {
749 self
750 }
751 }
752
753 impl<T, $($param),*> System for OnceFunctionSystem<T, ($($param,)*), ($($param::State,)*)>
754 where
755 T: for<'a> FnMut($($param::Item<'a>),*) -> Option<()> + 'static,
756 $($param: SystemParam + 'static),*
757 {
758 fn run(&mut self, _world: &hecs::World, _resources: &Resources) {
759 if self.done {
760 return;
761 }
762 #[allow(non_snake_case)]
763 let ($($param,)*) = &mut self.state;
764 let result = (self.func)($($param::fetch($param, _world, _resources)),*);
765 if result.is_some() {
766 self.done = true;
767 }
768 }
769
770 fn requires(&self) -> Vec<RequiredResource> {
771 if self.done {
772 return Vec::new();
773 }
774 let mut _v = Vec::new();
775 $(_v.extend($param::requires());)*
776 _v
777 }
778
779 fn name(&self) -> &'static str {
780 std::any::type_name::<T>()
781 }
782
783 fn ordering_id(&self) -> std::any::TypeId {
784 std::any::TypeId::of::<T>()
785 }
786 }
787 };
788}
789
790impl_once_system!();
791impl_once_system!(A);
792impl_once_system!(A, B);
793impl_once_system!(A, B, C);
794impl_once_system!(A, B, C, D);
795impl_once_system!(A, B, C, D, E);
796impl_once_system!(A, B, C, D, E, F);
797impl_once_system!(A, B, C, D, E, F, G);
798impl_once_system!(A, B, C, D, E, F, G, H);
799impl_once_system!(A, B, C, D, E, F, G, H, I);
800impl_once_system!(A, B, C, D, E, F, G, H, I, J);
801impl_once_system!(A, B, C, D, E, F, G, H, I, J, K);
802impl_once_system!(A, B, C, D, E, F, G, H, I, J, K, L);
803
804pub struct DetachedFunctionSystem<F, Marker, State = ()> {
807 func: F,
808 state: State,
809 _marker: std::marker::PhantomData<Marker>,
810}
811
812pub trait AsyncExt<Marker> {
855 type System: System;
856 fn detach(self) -> Self::System;
857}
858
859macro_rules! impl_async_system {
860 ($($param:ident),*) => {
861 impl<T, Fut, $($param),*> AsyncExt<($($param,)*)> for T
862 where
863 T: for<'a> FnMut($($param::Item<'a>),*) -> Fut + 'static,
864 for<'a> &'a mut T: FnMut($($param),*) -> Fut,
865 Fut: SpawnableFuture<()>,
866 $($param: SystemParam + 'static),*
867 {
868 type System = DetachedFunctionSystem<T, ($($param,)*), ($($param::State,)*)>;
869
870 fn detach(self) -> Self::System {
871 DetachedFunctionSystem {
872 func: self,
873 state: Default::default(),
874 _marker: std::marker::PhantomData,
875 }
876 }
877 }
878
879 impl<T, Fut, $($param),*> IntoSystem<($($param,)*)> for DetachedFunctionSystem<T, ($($param,)*), ($($param::State,)*)>
880 where
881 T: for<'a> FnMut($($param::Item<'a>),*) -> Fut + 'static,
882 Fut: SpawnableFuture<()>,
883 $($param: SystemParam + 'static),*
884 {
885 type System = Self;
886
887 fn into_system(self) -> Self::System {
888 self
889 }
890 }
891
892 impl<T, Fut, $($param),*> System for DetachedFunctionSystem<T, ($($param,)*), ($($param::State,)*)>
893 where
894 T: for<'a> FnMut($($param::Item<'a>),*) -> Fut + 'static,
895 Fut: SpawnableFuture<()>,
896 $($param: SystemParam + 'static),*
897 {
898 fn run(&mut self, _world: &hecs::World, _resources: &Resources) {
899 #[allow(non_snake_case)]
900 let ($($param,)*) = &mut self.state;
901 let future = (self.func)($($param::fetch($param, _world, _resources)),*);
902 let tasks = _resources.get_resource::<crate::threading::BackgroundTasks>(_world);
903 let _ = tasks.spawn_async(future);
904 }
905
906 fn requires(&self) -> Vec<RequiredResource> {
907 let mut _v = vec![RequiredResource {
908 name: std::any::type_name::<crate::threading::BackgroundTasks>(),
909 type_id: std::any::TypeId::of::<crate::threading::BackgroundTasks>(),
910 present: |world, resources| resources.has_resource::<crate::threading::BackgroundTasks>(world),
911 hint: Some(
912 "`.detach()` drives its future through `BackgroundTasks` — register \
913 `app.add_plugin(BackgroundTasksPlugin::new(worker_count))` before this system runs.",
914 ),
915 }];
916 $(_v.extend($param::requires());)*
917 _v
918 }
919
920 fn name(&self) -> &'static str {
921 std::any::type_name::<T>()
922 }
923
924 fn ordering_id(&self) -> std::any::TypeId {
925 std::any::TypeId::of::<T>()
926 }
927 }
928 };
929}
930
931impl_async_system!();
932impl_async_system!(A);
933impl_async_system!(A, B);
934impl_async_system!(A, B, C);
935impl_async_system!(A, B, C, D);
936impl_async_system!(A, B, C, D, E);
937impl_async_system!(A, B, C, D, E, F);
938impl_async_system!(A, B, C, D, E, F, G);
939impl_async_system!(A, B, C, D, E, F, G, H);
940impl_async_system!(A, B, C, D, E, F, G, H, I);
941impl_async_system!(A, B, C, D, E, F, G, H, I, J);
942impl_async_system!(A, B, C, D, E, F, G, H, I, J, K);
943impl_async_system!(A, B, C, D, E, F, G, H, I, J, K, L);