1use 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 name(&self) -> &'static str {
63 self.inner.name()
64 }
65}
66
67pub trait RunIfExt<Marker>: IntoSystem<Marker> + Sized {
70 fn run_if<C: RunCondition>(self) -> RunIfSystem<Self, Marker, C> {
71 RunIfSystem {
72 inner: self,
73 _marker: std::marker::PhantomData,
74 }
75 }
76}
77
78impl<Marker, T: IntoSystem<Marker>> RunIfExt<Marker> for T {}
79
80pub struct RunIfSystem<T, Marker, C> {
81 inner: T,
82 _marker: std::marker::PhantomData<(Marker, C)>,
83}
84
85impl<T, Marker, C> IntoSystem<Marker> for RunIfSystem<T, Marker, C>
86where
87 T: IntoSystem<Marker>,
88 C: RunCondition,
89{
90 type System = Conditional<T::System, C>;
91
92 fn into_system(self) -> Self::System {
93 Conditional {
94 inner: self.inner.into_system(),
95 _marker: std::marker::PhantomData,
96 }
97 }
98}
99
100pub trait RunIfFnExt<Marker>: IntoSystem<Marker> + Sized {
114 fn run_if_fn<F>(self, cond: F) -> RunIfFnSystem<Self, Marker, F>
115 where
116 F: Fn(&hecs::World, &Resources) -> bool + 'static,
117 {
118 RunIfFnSystem {
119 inner: self,
120 cond,
121 _marker: std::marker::PhantomData,
122 }
123 }
124}
125
126impl<Marker, T: IntoSystem<Marker>> RunIfFnExt<Marker> for T {}
127
128pub struct RunIfFnSystem<T, Marker, F> {
129 inner: T,
130 cond: F,
131 _marker: std::marker::PhantomData<Marker>,
132}
133
134impl<T, Marker, F> IntoSystem<Marker> for RunIfFnSystem<T, Marker, F>
135where
136 T: IntoSystem<Marker>,
137 F: Fn(&hecs::World, &Resources) -> bool + 'static,
138 Marker: 'static,
139{
140 type System = ConditionalFn<T::System, F>;
141
142 fn into_system(self) -> Self::System {
143 ConditionalFn {
144 inner: self.inner.into_system(),
145 cond: self.cond,
146 }
147 }
148}
149
150pub struct ConditionalFn<S, F> {
154 inner: S,
155 cond: F,
156}
157
158impl<S: System, F: Fn(&hecs::World, &Resources) -> bool + 'static> System for ConditionalFn<S, F> {
159 fn run(&mut self, world: &hecs::World, resources: &Resources) {
160 if (self.cond)(world, resources) {
161 self.inner.run(world, resources);
162 }
163 }
164
165 fn name(&self) -> &'static str {
168 self.inner.name()
169 }
170}
171
172pub trait SystemSetRunIfExt<M>: IntoSystemSet<M> + Sized {
176 fn run_if<C: RunCondition>(self) -> ConditionalSet<Self, M, C> {
177 ConditionalSet {
178 inner: self,
179 _marker: std::marker::PhantomData,
180 }
181 }
182}
183
184impl<M, T: IntoSystemSet<M>> SystemSetRunIfExt<M> for T {}
185
186pub struct ConditionalSet<T, M, C> {
187 inner: T,
188 _marker: std::marker::PhantomData<(M, C)>,
189}
190
191struct BoxedConditional<C> {
195 inner: Box<dyn System>,
196 _marker: std::marker::PhantomData<C>,
197}
198
199impl<C: RunCondition> System for BoxedConditional<C> {
200 fn run(&mut self, world: &hecs::World, resources: &Resources) {
201 if C::should_run(world, resources) {
202 self.inner.run(world, resources);
203 }
204 }
205
206 fn name(&self) -> &'static str {
208 self.inner.name()
209 }
210}
211
212impl<T, M, C> IntoSystemSet<M> for ConditionalSet<T, M, C>
213where
214 T: IntoSystemSet<M>,
215 C: RunCondition,
216{
217 fn into_system_set(self) -> Vec<Box<dyn System>> {
218 self.inner
219 .into_system_set()
220 .into_iter()
221 .map(|system| {
222 Box::new(BoxedConditional::<C> {
223 inner: system,
224 _marker: std::marker::PhantomData,
225 }) as Box<dyn System>
226 })
227 .collect()
228 }
229}