pebble/ecs/
system_condition.rs1use crate::ecs::{
2 resources::Resources,
3 system::{IntoSystem, System},
4 system_set::IntoSystemSet,
5};
6
7pub trait RunCondition: 'static {
16 fn should_run(world: &hecs::World, resources: &Resources) -> bool;
17}
18
19pub struct ResourceExists<T>(std::marker::PhantomData<T>);
21impl<T: 'static + Send + Sync> RunCondition for ResourceExists<T> {
22 fn should_run(world: &hecs::World, resources: &Resources) -> bool {
23 resources.has_resource::<T>(world)
24 }
25}
26
27pub struct And<A, B>(std::marker::PhantomData<(A, B)>);
29impl<A: RunCondition, B: RunCondition> RunCondition for And<A, B> {
30 fn should_run(world: &hecs::World, resources: &Resources) -> bool {
31 A::should_run(world, resources) && B::should_run(world, resources)
32 }
33}
34
35pub struct Or<A, B>(std::marker::PhantomData<(A, B)>);
37impl<A: RunCondition, B: RunCondition> RunCondition for Or<A, B> {
38 fn should_run(world: &hecs::World, resources: &Resources) -> bool {
39 A::should_run(world, resources) || B::should_run(world, resources)
40 }
41}
42
43pub struct Conditional<S, C> {
46 inner: S,
47 _marker: std::marker::PhantomData<C>,
48}
49
50impl<S: System, C: RunCondition> System for Conditional<S, C> {
51 fn run(&mut self, world: &hecs::World, resources: &Resources) {
52 if C::should_run(world, resources) {
53 self.inner.run(world, resources);
54 }
55 }
56
57 fn requires(&self) -> Vec<crate::ecs::system::RequiredResource> {
58 self.inner.requires()
59 }
60}
61
62pub trait RunIfExt<Marker>: IntoSystem<Marker> + Sized {
65 fn run_if<C: RunCondition>(self) -> RunIfSystem<Self, Marker, C> {
66 RunIfSystem {
67 inner: self,
68 _marker: std::marker::PhantomData,
69 }
70 }
71}
72
73impl<Marker, T: IntoSystem<Marker>> RunIfExt<Marker> for T {}
74
75pub struct RunIfSystem<T, Marker, C> {
76 inner: T,
77 _marker: std::marker::PhantomData<(Marker, C)>,
78}
79
80impl<T, Marker, C> IntoSystem<Marker> for RunIfSystem<T, Marker, C>
81where
82 T: IntoSystem<Marker>,
83 C: RunCondition,
84{
85 type System = Conditional<T::System, C>;
86
87 fn into_system(self) -> Self::System {
88 Conditional {
89 inner: self.inner.into_system(),
90 _marker: std::marker::PhantomData,
91 }
92 }
93}
94
95pub trait SystemSetRunIfExt<M>: IntoSystemSet<M> + Sized {
99 fn run_if<C: RunCondition>(self) -> ConditionalSet<Self, M, C> {
100 ConditionalSet {
101 inner: self,
102 _marker: std::marker::PhantomData,
103 }
104 }
105}
106
107impl<M, T: IntoSystemSet<M>> SystemSetRunIfExt<M> for T {}
108
109pub struct ConditionalSet<T, M, C> {
110 inner: T,
111 _marker: std::marker::PhantomData<(M, C)>,
112}
113
114struct BoxedConditional<C> {
118 inner: Box<dyn System>,
119 _marker: std::marker::PhantomData<C>,
120}
121
122impl<C: RunCondition> System for BoxedConditional<C> {
123 fn run(&mut self, world: &hecs::World, resources: &Resources) {
124 if C::should_run(world, resources) {
125 self.inner.run(world, resources);
126 }
127 }
128
129 fn requires(&self) -> Vec<crate::ecs::system::RequiredResource> {
130 self.inner.requires()
131 }
132}
133
134impl<T, M, C> IntoSystemSet<M> for ConditionalSet<T, M, C>
135where
136 T: IntoSystemSet<M>,
137 C: RunCondition,
138{
139 fn into_system_set(self) -> Vec<Box<dyn System>> {
140 self.inner
141 .into_system_set()
142 .into_iter()
143 .map(|system| {
144 Box::new(BoxedConditional::<C> {
145 inner: system,
146 _marker: std::marker::PhantomData,
147 }) as Box<dyn System>
148 })
149 .collect()
150 }
151}