bevy_ecs/schedule/
condition.rs

1use alloc::{borrow::Cow, boxed::Box, format};
2use core::ops::Not;
3
4use crate::system::{
5    Adapt, AdapterSystem, CombinatorSystem, Combine, IntoSystem, ReadOnlySystem, System, SystemIn,
6    SystemInput,
7};
8
9/// A type-erased run condition stored in a [`Box`].
10pub type BoxedCondition<In = ()> = Box<dyn ReadOnlySystem<In = In, Out = bool>>;
11
12/// A system that determines if one or more scheduled systems should run.
13///
14/// Implemented for functions and closures that convert into [`System<Out=bool>`](System)
15/// with [read-only](crate::system::ReadOnlySystemParam) parameters.
16///
17/// # Marker type parameter
18///
19/// `Condition` trait has `Marker` type parameter, which has no special meaning,
20/// but exists to work around the limitation of Rust's trait system.
21///
22/// Type parameter in return type can be set to `<()>` by calling [`IntoSystem::into_system`],
23/// but usually have to be specified when passing a condition to a function.
24///
25/// ```
26/// # use bevy_ecs::schedule::Condition;
27/// # use bevy_ecs::system::IntoSystem;
28/// fn not_condition<Marker>(a: impl Condition<Marker>) -> impl Condition<()> {
29///    IntoSystem::into_system(a.map(|x| !x))
30/// }
31/// ```
32///
33/// # Examples
34/// A condition that returns true every other time it's called.
35/// ```
36/// # use bevy_ecs::prelude::*;
37/// fn every_other_time() -> impl Condition<()> {
38///     IntoSystem::into_system(|mut flag: Local<bool>| {
39///         *flag = !*flag;
40///         *flag
41///     })
42/// }
43///
44/// # #[derive(Resource)] struct DidRun(bool);
45/// # fn my_system(mut did_run: ResMut<DidRun>) { did_run.0 = true; }
46/// # let mut schedule = Schedule::default();
47/// schedule.add_systems(my_system.run_if(every_other_time()));
48/// # let mut world = World::new();
49/// # world.insert_resource(DidRun(false));
50/// # schedule.run(&mut world);
51/// # assert!(world.resource::<DidRun>().0);
52/// # world.insert_resource(DidRun(false));
53/// # schedule.run(&mut world);
54/// # assert!(!world.resource::<DidRun>().0);
55/// ```
56///
57/// A condition that takes a bool as an input and returns it unchanged.
58///
59/// ```
60/// # use bevy_ecs::prelude::*;
61/// fn identity() -> impl Condition<(), In<bool>> {
62///     IntoSystem::into_system(|In(x)| x)
63/// }
64///
65/// # fn always_true() -> bool { true }
66/// # let mut app = Schedule::default();
67/// # #[derive(Resource)] struct DidRun(bool);
68/// # fn my_system(mut did_run: ResMut<DidRun>) { did_run.0 = true; }
69/// app.add_systems(my_system.run_if(always_true.pipe(identity())));
70/// # let mut world = World::new();
71/// # world.insert_resource(DidRun(false));
72/// # app.run(&mut world);
73/// # assert!(world.resource::<DidRun>().0);
74pub trait Condition<Marker, In: SystemInput = ()>: sealed::Condition<Marker, In> {
75    /// Returns a new run condition that only returns `true`
76    /// if both this one and the passed `and` return `true`.
77    ///
78    /// The returned run condition is short-circuiting, meaning
79    /// `and` will only be invoked if `self` returns `true`.
80    ///
81    /// # Examples
82    ///
83    /// ```should_panic
84    /// use bevy_ecs::prelude::*;
85    ///
86    /// #[derive(Resource, PartialEq)]
87    /// struct R(u32);
88    ///
89    /// # let mut app = Schedule::default();
90    /// # let mut world = World::new();
91    /// # fn my_system() {}
92    /// app.add_systems(
93    ///     // The `resource_equals` run condition will panic since we don't initialize `R`,
94    ///     // just like if we used `Res<R>` in a system.
95    ///     my_system.run_if(resource_equals(R(0))),
96    /// );
97    /// # app.run(&mut world);
98    /// ```
99    ///
100    /// Use `.and()` to avoid checking the condition.
101    ///
102    /// ```
103    /// # use bevy_ecs::prelude::*;
104    /// # #[derive(Resource, PartialEq)]
105    /// # struct R(u32);
106    /// # let mut app = Schedule::default();
107    /// # let mut world = World::new();
108    /// # fn my_system() {}
109    /// app.add_systems(
110    ///     // `resource_equals` will only get run if the resource `R` exists.
111    ///     my_system.run_if(resource_exists::<R>.and(resource_equals(R(0)))),
112    /// );
113    /// # app.run(&mut world);
114    /// ```
115    ///
116    /// Note that in this case, it's better to just use the run condition [`resource_exists_and_equals`].
117    ///
118    /// [`resource_exists_and_equals`]: common_conditions::resource_exists_and_equals
119    fn and<M, C: Condition<M, In>>(self, and: C) -> And<Self::System, C::System> {
120        let a = IntoSystem::into_system(self);
121        let b = IntoSystem::into_system(and);
122        let name = format!("{} && {}", a.name(), b.name());
123        CombinatorSystem::new(a, b, Cow::Owned(name))
124    }
125
126    /// Returns a new run condition that only returns `false`
127    /// if both this one and the passed `nand` return `true`.
128    ///
129    /// The returned run condition is short-circuiting, meaning
130    /// `nand` will only be invoked if `self` returns `true`.
131    ///
132    /// # Examples
133    ///
134    /// ```compile_fail
135    /// use bevy::prelude::*;
136    ///
137    /// #[derive(States, Debug, Clone, PartialEq, Eq, Hash)]
138    /// pub enum PlayerState {
139    ///     Alive,
140    ///     Dead,
141    /// }
142    ///
143    /// #[derive(States, Debug, Clone, PartialEq, Eq, Hash)]
144    /// pub enum EnemyState {
145    ///     Alive,
146    ///     Dead,
147    /// }
148    ///
149    /// # let mut app = Schedule::default();
150    /// # let mut world = World::new();
151    /// # fn game_over_credits() {}
152    /// app.add_systems(
153    ///     // The game_over_credits system will only execute if either the `in_state(PlayerState::Alive)`
154    ///     // run condition or `in_state(EnemyState::Alive)` run condition evaluates to `false`.
155    ///     game_over_credits.run_if(
156    ///         in_state(PlayerState::Alive).nand(in_state(EnemyState::Alive))
157    ///     ),
158    /// );
159    /// # app.run(&mut world);
160    /// ```
161    ///
162    /// Equivalent logic can be achieved by using `not` in concert with `and`:
163    ///
164    /// ```compile_fail
165    /// app.add_systems(
166    ///     game_over_credits.run_if(
167    ///         not(in_state(PlayerState::Alive).and(in_state(EnemyState::Alive)))
168    ///     ),
169    /// );
170    /// ```
171    fn nand<M, C: Condition<M, In>>(self, nand: C) -> Nand<Self::System, C::System> {
172        let a = IntoSystem::into_system(self);
173        let b = IntoSystem::into_system(nand);
174        let name = format!("!({} && {})", a.name(), b.name());
175        CombinatorSystem::new(a, b, Cow::Owned(name))
176    }
177
178    /// Returns a new run condition that only returns `true`
179    /// if both this one and the passed `nor` return `false`.
180    ///
181    /// The returned run condition is short-circuiting, meaning
182    /// `nor` will only be invoked if `self` returns `false`.
183    ///
184    /// # Examples
185    ///
186    /// ```compile_fail
187    /// use bevy::prelude::*;
188    ///
189    /// #[derive(States, Debug, Clone, PartialEq, Eq, Hash)]
190    /// pub enum WeatherState {
191    ///     Sunny,
192    ///     Cloudy,
193    /// }
194    ///
195    /// #[derive(States, Debug, Clone, PartialEq, Eq, Hash)]
196    /// pub enum SoilState {
197    ///     Fertilized,
198    ///     NotFertilized,
199    /// }
200    ///
201    /// # let mut app = Schedule::default();
202    /// # let mut world = World::new();
203    /// # fn slow_plant_growth() {}
204    /// app.add_systems(
205    ///     // The slow_plant_growth system will only execute if both the `in_state(WeatherState::Sunny)`
206    ///     // run condition and `in_state(SoilState::Fertilized)` run condition evaluate to `false`.
207    ///     slow_plant_growth.run_if(
208    ///         in_state(WeatherState::Sunny).nor(in_state(SoilState::Fertilized))
209    ///     ),
210    /// );
211    /// # app.run(&mut world);
212    /// ```
213    ///
214    /// Equivalent logic can be achieved by using `not` in concert with `or`:
215    ///
216    /// ```compile_fail
217    /// app.add_systems(
218    ///     slow_plant_growth.run_if(
219    ///         not(in_state(WeatherState::Sunny).or(in_state(SoilState::Fertilized)))
220    ///     ),
221    /// );
222    /// ```
223    fn nor<M, C: Condition<M, In>>(self, nor: C) -> Nor<Self::System, C::System> {
224        let a = IntoSystem::into_system(self);
225        let b = IntoSystem::into_system(nor);
226        let name = format!("!({} || {})", a.name(), b.name());
227        CombinatorSystem::new(a, b, Cow::Owned(name))
228    }
229
230    /// Returns a new run condition that returns `true`
231    /// if either this one or the passed `or` return `true`.
232    ///
233    /// The returned run condition is short-circuiting, meaning
234    /// `or` will only be invoked if `self` returns `false`.
235    ///
236    /// # Examples
237    ///
238    /// ```
239    /// use bevy_ecs::prelude::*;
240    ///
241    /// #[derive(Resource, PartialEq)]
242    /// struct A(u32);
243    ///
244    /// #[derive(Resource, PartialEq)]
245    /// struct B(u32);
246    ///
247    /// # let mut app = Schedule::default();
248    /// # let mut world = World::new();
249    /// # #[derive(Resource)] struct C(bool);
250    /// # fn my_system(mut c: ResMut<C>) { c.0 = true; }
251    /// app.add_systems(
252    ///     // Only run the system if either `A` or `B` exist.
253    ///     my_system.run_if(resource_exists::<A>.or(resource_exists::<B>)),
254    /// );
255    /// #
256    /// # world.insert_resource(C(false));
257    /// # app.run(&mut world);
258    /// # assert!(!world.resource::<C>().0);
259    /// #
260    /// # world.insert_resource(A(0));
261    /// # app.run(&mut world);
262    /// # assert!(world.resource::<C>().0);
263    /// #
264    /// # world.remove_resource::<A>();
265    /// # world.insert_resource(B(0));
266    /// # world.insert_resource(C(false));
267    /// # app.run(&mut world);
268    /// # assert!(world.resource::<C>().0);
269    /// ```
270    fn or<M, C: Condition<M, In>>(self, or: C) -> Or<Self::System, C::System> {
271        let a = IntoSystem::into_system(self);
272        let b = IntoSystem::into_system(or);
273        let name = format!("{} || {}", a.name(), b.name());
274        CombinatorSystem::new(a, b, Cow::Owned(name))
275    }
276
277    /// Returns a new run condition that only returns `true`
278    /// if `self` and `xnor` **both** return `false` or **both** return `true`.
279    ///
280    /// # Examples
281    ///
282    /// ```compile_fail
283    /// use bevy::prelude::*;
284    ///
285    /// #[derive(States, Debug, Clone, PartialEq, Eq, Hash)]
286    /// pub enum CoffeeMachineState {
287    ///     Heating,
288    ///     Brewing,
289    ///     Inactive,
290    /// }
291    ///
292    /// #[derive(States, Debug, Clone, PartialEq, Eq, Hash)]
293    /// pub enum TeaKettleState {
294    ///     Heating,
295    ///     Steeping,
296    ///     Inactive,
297    /// }
298    ///
299    /// # let mut app = Schedule::default();
300    /// # let mut world = World::new();
301    /// # fn take_drink_orders() {}
302    /// app.add_systems(
303    ///     // The take_drink_orders system will only execute if the `in_state(CoffeeMachineState::Inactive)`
304    ///     // run condition and `in_state(TeaKettleState::Inactive)` run conditions both evaluate to `false`,
305    ///     // or both evaluate to `true`.
306    ///     take_drink_orders.run_if(
307    ///         in_state(CoffeeMachineState::Inactive).xnor(in_state(TeaKettleState::Inactive))
308    ///     ),
309    /// );
310    /// # app.run(&mut world);
311    /// ```
312    ///
313    /// Equivalent logic can be achieved by using `not` in concert with `xor`:
314    ///
315    /// ```compile_fail
316    /// app.add_systems(
317    ///     take_drink_orders.run_if(
318    ///         not(in_state(CoffeeMachineState::Inactive).xor(in_state(TeaKettleState::Inactive)))
319    ///     ),
320    /// );
321    /// ```
322    fn xnor<M, C: Condition<M, In>>(self, xnor: C) -> Xnor<Self::System, C::System> {
323        let a = IntoSystem::into_system(self);
324        let b = IntoSystem::into_system(xnor);
325        let name = format!("!({} ^ {})", a.name(), b.name());
326        CombinatorSystem::new(a, b, Cow::Owned(name))
327    }
328
329    /// Returns a new run condition that only returns `true`
330    /// if either `self` or `xor` return `true`, but not both.
331    ///
332    /// # Examples
333    ///
334    /// ```compile_fail
335    /// use bevy::prelude::*;
336    ///
337    /// #[derive(States, Debug, Clone, PartialEq, Eq, Hash)]
338    /// pub enum CoffeeMachineState {
339    ///     Heating,
340    ///     Brewing,
341    ///     Inactive,
342    /// }
343    ///
344    /// #[derive(States, Debug, Clone, PartialEq, Eq, Hash)]
345    /// pub enum TeaKettleState {
346    ///     Heating,
347    ///     Steeping,
348    ///     Inactive,
349    /// }
350    ///
351    /// # let mut app = Schedule::default();
352    /// # let mut world = World::new();
353    /// # fn prepare_beverage() {}
354    /// app.add_systems(
355    ///     // The prepare_beverage system will only execute if either the `in_state(CoffeeMachineState::Inactive)`
356    ///     // run condition or `in_state(TeaKettleState::Inactive)` run condition evaluates to `true`,
357    ///     // but not both.
358    ///     prepare_beverage.run_if(
359    ///         in_state(CoffeeMachineState::Inactive).xor(in_state(TeaKettleState::Inactive))
360    ///     ),
361    /// );
362    /// # app.run(&mut world);
363    /// ```
364    fn xor<M, C: Condition<M, In>>(self, xor: C) -> Xor<Self::System, C::System> {
365        let a = IntoSystem::into_system(self);
366        let b = IntoSystem::into_system(xor);
367        let name = format!("({} ^ {})", a.name(), b.name());
368        CombinatorSystem::new(a, b, Cow::Owned(name))
369    }
370}
371
372impl<Marker, In: SystemInput, F> Condition<Marker, In> for F where F: sealed::Condition<Marker, In> {}
373
374mod sealed {
375    use crate::system::{IntoSystem, ReadOnlySystem, SystemInput};
376
377    pub trait Condition<Marker, In: SystemInput>:
378        IntoSystem<In, bool, Marker, System = Self::ReadOnlySystem>
379    {
380        // This associated type is necessary to let the compiler
381        // know that `Self::System` is `ReadOnlySystem`.
382        type ReadOnlySystem: ReadOnlySystem<In = In, Out = bool>;
383    }
384
385    impl<Marker, In: SystemInput, F> Condition<Marker, In> for F
386    where
387        F: IntoSystem<In, bool, Marker>,
388        F::System: ReadOnlySystem,
389    {
390        type ReadOnlySystem = F::System;
391    }
392}
393
394/// A collection of [run conditions](Condition) that may be useful in any bevy app.
395pub mod common_conditions {
396    use super::{Condition, NotSystem};
397    use crate::{
398        change_detection::DetectChanges,
399        event::{Event, EventReader},
400        prelude::{Component, Query, With},
401        query::QueryFilter,
402        removal_detection::RemovedComponents,
403        resource::Resource,
404        system::{In, IntoSystem, Local, Res, System, SystemInput},
405    };
406    use alloc::format;
407
408    /// A [`Condition`]-satisfying system that returns `true`
409    /// on the first time the condition is run and false every time after.
410    ///
411    /// # Example
412    ///
413    /// ```
414    /// # use bevy_ecs::prelude::*;
415    /// # #[derive(Resource, Default)]
416    /// # struct Counter(u8);
417    /// # let mut app = Schedule::default();
418    /// # let mut world = World::new();
419    /// # world.init_resource::<Counter>();
420    /// app.add_systems(
421    ///     // `run_once` will only return true the first time it's evaluated
422    ///     my_system.run_if(run_once),
423    /// );
424    ///
425    /// fn my_system(mut counter: ResMut<Counter>) {
426    ///     counter.0 += 1;
427    /// }
428    ///
429    /// // This is the first time the condition will be evaluated so `my_system` will run
430    /// app.run(&mut world);
431    /// assert_eq!(world.resource::<Counter>().0, 1);
432    ///
433    /// // This is the seconds time the condition will be evaluated so `my_system` won't run
434    /// app.run(&mut world);
435    /// assert_eq!(world.resource::<Counter>().0, 1);
436    /// ```
437    pub fn run_once(mut has_run: Local<bool>) -> bool {
438        if !*has_run {
439            *has_run = true;
440            true
441        } else {
442            false
443        }
444    }
445
446    /// A [`Condition`]-satisfying system that returns `true`
447    /// if the resource exists.
448    ///
449    /// # Example
450    ///
451    /// ```
452    /// # use bevy_ecs::prelude::*;
453    /// # #[derive(Resource, Default)]
454    /// # struct Counter(u8);
455    /// # let mut app = Schedule::default();
456    /// # let mut world = World::new();
457    /// app.add_systems(
458    ///     // `resource_exists` will only return true if the given resource exists in the world
459    ///     my_system.run_if(resource_exists::<Counter>),
460    /// );
461    ///
462    /// fn my_system(mut counter: ResMut<Counter>) {
463    ///     counter.0 += 1;
464    /// }
465    ///
466    /// // `Counter` hasn't been added so `my_system` won't run
467    /// app.run(&mut world);
468    /// world.init_resource::<Counter>();
469    ///
470    /// // `Counter` has now been added so `my_system` can run
471    /// app.run(&mut world);
472    /// assert_eq!(world.resource::<Counter>().0, 1);
473    /// ```
474    pub fn resource_exists<T>(res: Option<Res<T>>) -> bool
475    where
476        T: Resource,
477    {
478        res.is_some()
479    }
480
481    /// Generates a [`Condition`]-satisfying closure that returns `true`
482    /// if the resource is equal to `value`.
483    ///
484    /// # Panics
485    ///
486    /// The condition will panic if the resource does not exist.
487    ///
488    /// # Example
489    ///
490    /// ```
491    /// # use bevy_ecs::prelude::*;
492    /// # #[derive(Resource, Default, PartialEq)]
493    /// # struct Counter(u8);
494    /// # let mut app = Schedule::default();
495    /// # let mut world = World::new();
496    /// # world.init_resource::<Counter>();
497    /// app.add_systems(
498    ///     // `resource_equals` will only return true if the given resource equals the given value
499    ///     my_system.run_if(resource_equals(Counter(0))),
500    /// );
501    ///
502    /// fn my_system(mut counter: ResMut<Counter>) {
503    ///     counter.0 += 1;
504    /// }
505    ///
506    /// // `Counter` is `0` so `my_system` can run
507    /// app.run(&mut world);
508    /// assert_eq!(world.resource::<Counter>().0, 1);
509    ///
510    /// // `Counter` is no longer `0` so `my_system` won't run
511    /// app.run(&mut world);
512    /// assert_eq!(world.resource::<Counter>().0, 1);
513    /// ```
514    pub fn resource_equals<T>(value: T) -> impl FnMut(Res<T>) -> bool
515    where
516        T: Resource + PartialEq,
517    {
518        move |res: Res<T>| *res == value
519    }
520
521    /// Generates a [`Condition`]-satisfying closure that returns `true`
522    /// if the resource exists and is equal to `value`.
523    ///
524    /// The condition will return `false` if the resource does not exist.
525    ///
526    /// # Example
527    ///
528    /// ```
529    /// # use bevy_ecs::prelude::*;
530    /// # #[derive(Resource, Default, PartialEq)]
531    /// # struct Counter(u8);
532    /// # let mut app = Schedule::default();
533    /// # let mut world = World::new();
534    /// app.add_systems(
535    ///     // `resource_exists_and_equals` will only return true
536    ///     // if the given resource exists and equals the given value
537    ///     my_system.run_if(resource_exists_and_equals(Counter(0))),
538    /// );
539    ///
540    /// fn my_system(mut counter: ResMut<Counter>) {
541    ///     counter.0 += 1;
542    /// }
543    ///
544    /// // `Counter` hasn't been added so `my_system` can't run
545    /// app.run(&mut world);
546    /// world.init_resource::<Counter>();
547    ///
548    /// // `Counter` is `0` so `my_system` can run
549    /// app.run(&mut world);
550    /// assert_eq!(world.resource::<Counter>().0, 1);
551    ///
552    /// // `Counter` is no longer `0` so `my_system` won't run
553    /// app.run(&mut world);
554    /// assert_eq!(world.resource::<Counter>().0, 1);
555    /// ```
556    pub fn resource_exists_and_equals<T>(value: T) -> impl FnMut(Option<Res<T>>) -> bool
557    where
558        T: Resource + PartialEq,
559    {
560        move |res: Option<Res<T>>| match res {
561            Some(res) => *res == value,
562            None => false,
563        }
564    }
565
566    /// A [`Condition`]-satisfying system that returns `true`
567    /// if the resource of the given type has been added since the condition was last checked.
568    ///
569    /// # Example
570    ///
571    /// ```
572    /// # use bevy_ecs::prelude::*;
573    /// # #[derive(Resource, Default)]
574    /// # struct Counter(u8);
575    /// # let mut app = Schedule::default();
576    /// # let mut world = World::new();
577    /// app.add_systems(
578    ///     // `resource_added` will only return true if the
579    ///     // given resource was just added
580    ///     my_system.run_if(resource_added::<Counter>),
581    /// );
582    ///
583    /// fn my_system(mut counter: ResMut<Counter>) {
584    ///     counter.0 += 1;
585    /// }
586    ///
587    /// world.init_resource::<Counter>();
588    ///
589    /// // `Counter` was just added so `my_system` will run
590    /// app.run(&mut world);
591    /// assert_eq!(world.resource::<Counter>().0, 1);
592    ///
593    /// // `Counter` was not just added so `my_system` will not run
594    /// app.run(&mut world);
595    /// assert_eq!(world.resource::<Counter>().0, 1);
596    /// ```
597    pub fn resource_added<T>(res: Option<Res<T>>) -> bool
598    where
599        T: Resource,
600    {
601        match res {
602            Some(res) => res.is_added(),
603            None => false,
604        }
605    }
606
607    /// A [`Condition`]-satisfying system that returns `true`
608    /// if the resource of the given type has had its value changed since the condition
609    /// was last checked.
610    ///
611    /// The value is considered changed when it is added. The first time this condition
612    /// is checked after the resource was added, it will return `true`.
613    /// Change detection behaves like this everywhere in Bevy.
614    ///
615    /// # Panics
616    ///
617    /// The condition will panic if the resource does not exist.
618    ///
619    /// # Example
620    ///
621    /// ```
622    /// # use bevy_ecs::prelude::*;
623    /// # #[derive(Resource, Default)]
624    /// # struct Counter(u8);
625    /// # let mut app = Schedule::default();
626    /// # let mut world = World::new();
627    /// # world.init_resource::<Counter>();
628    /// app.add_systems(
629    ///     // `resource_changed` will only return true if the
630    ///     // given resource was just changed (or added)
631    ///     my_system.run_if(
632    ///         resource_changed::<Counter>
633    ///         // By default detecting changes will also trigger if the resource was
634    ///         // just added, this won't work with my example so I will add a second
635    ///         // condition to make sure the resource wasn't just added
636    ///         .and(not(resource_added::<Counter>))
637    ///     ),
638    /// );
639    ///
640    /// fn my_system(mut counter: ResMut<Counter>) {
641    ///     counter.0 += 1;
642    /// }
643    ///
644    /// // `Counter` hasn't been changed so `my_system` won't run
645    /// app.run(&mut world);
646    /// assert_eq!(world.resource::<Counter>().0, 0);
647    ///
648    /// world.resource_mut::<Counter>().0 = 50;
649    ///
650    /// // `Counter` was just changed so `my_system` will run
651    /// app.run(&mut world);
652    /// assert_eq!(world.resource::<Counter>().0, 51);
653    /// ```
654    pub fn resource_changed<T>(res: Res<T>) -> bool
655    where
656        T: Resource,
657    {
658        res.is_changed()
659    }
660
661    /// A [`Condition`]-satisfying system that returns `true`
662    /// if the resource of the given type has had its value changed since the condition
663    /// was last checked.
664    ///
665    /// The value is considered changed when it is added. The first time this condition
666    /// is checked after the resource was added, it will return `true`.
667    /// Change detection behaves like this everywhere in Bevy.
668    ///
669    /// This run condition does not detect when the resource is removed.
670    ///
671    /// The condition will return `false` if the resource does not exist.
672    ///
673    /// # Example
674    ///
675    /// ```
676    /// # use bevy_ecs::prelude::*;
677    /// # #[derive(Resource, Default)]
678    /// # struct Counter(u8);
679    /// # let mut app = Schedule::default();
680    /// # let mut world = World::new();
681    /// app.add_systems(
682    ///     // `resource_exists_and_changed` will only return true if the
683    ///     // given resource exists and was just changed (or added)
684    ///     my_system.run_if(
685    ///         resource_exists_and_changed::<Counter>
686    ///         // By default detecting changes will also trigger if the resource was
687    ///         // just added, this won't work with my example so I will add a second
688    ///         // condition to make sure the resource wasn't just added
689    ///         .and(not(resource_added::<Counter>))
690    ///     ),
691    /// );
692    ///
693    /// fn my_system(mut counter: ResMut<Counter>) {
694    ///     counter.0 += 1;
695    /// }
696    ///
697    /// // `Counter` doesn't exist so `my_system` won't run
698    /// app.run(&mut world);
699    /// world.init_resource::<Counter>();
700    ///
701    /// // `Counter` hasn't been changed so `my_system` won't run
702    /// app.run(&mut world);
703    /// assert_eq!(world.resource::<Counter>().0, 0);
704    ///
705    /// world.resource_mut::<Counter>().0 = 50;
706    ///
707    /// // `Counter` was just changed so `my_system` will run
708    /// app.run(&mut world);
709    /// assert_eq!(world.resource::<Counter>().0, 51);
710    /// ```
711    pub fn resource_exists_and_changed<T>(res: Option<Res<T>>) -> bool
712    where
713        T: Resource,
714    {
715        match res {
716            Some(res) => res.is_changed(),
717            None => false,
718        }
719    }
720
721    /// A [`Condition`]-satisfying system that returns `true`
722    /// if the resource of the given type has had its value changed since the condition
723    /// was last checked.
724    ///
725    /// The value is considered changed when it is added. The first time this condition
726    /// is checked after the resource was added, it will return `true`.
727    /// Change detection behaves like this everywhere in Bevy.
728    ///
729    /// This run condition also detects removal. It will return `true` if the resource
730    /// has been removed since the run condition was last checked.
731    ///
732    /// The condition will return `false` if the resource does not exist.
733    ///
734    /// # Example
735    ///
736    /// ```
737    /// # use bevy_ecs::prelude::*;
738    /// # #[derive(Resource, Default)]
739    /// # struct Counter(u8);
740    /// # let mut app = Schedule::default();
741    /// # let mut world = World::new();
742    /// # world.init_resource::<Counter>();
743    /// app.add_systems(
744    ///     // `resource_changed_or_removed` will only return true if the
745    ///     // given resource was just changed or removed (or added)
746    ///     my_system.run_if(
747    ///         resource_changed_or_removed::<Counter>
748    ///         // By default detecting changes will also trigger if the resource was
749    ///         // just added, this won't work with my example so I will add a second
750    ///         // condition to make sure the resource wasn't just added
751    ///         .and(not(resource_added::<Counter>))
752    ///     ),
753    /// );
754    ///
755    /// #[derive(Resource, Default)]
756    /// struct MyResource;
757    ///
758    /// // If `Counter` exists, increment it, otherwise insert `MyResource`
759    /// fn my_system(mut commands: Commands, mut counter: Option<ResMut<Counter>>) {
760    ///     if let Some(mut counter) = counter {
761    ///         counter.0 += 1;
762    ///     } else {
763    ///         commands.init_resource::<MyResource>();
764    ///     }
765    /// }
766    ///
767    /// // `Counter` hasn't been changed so `my_system` won't run
768    /// app.run(&mut world);
769    /// assert_eq!(world.resource::<Counter>().0, 0);
770    ///
771    /// world.resource_mut::<Counter>().0 = 50;
772    ///
773    /// // `Counter` was just changed so `my_system` will run
774    /// app.run(&mut world);
775    /// assert_eq!(world.resource::<Counter>().0, 51);
776    ///
777    /// world.remove_resource::<Counter>();
778    ///
779    /// // `Counter` was just removed so `my_system` will run
780    /// app.run(&mut world);
781    /// assert_eq!(world.contains_resource::<MyResource>(), true);
782    /// ```
783    pub fn resource_changed_or_removed<T>(res: Option<Res<T>>, mut existed: Local<bool>) -> bool
784    where
785        T: Resource,
786    {
787        if let Some(value) = res {
788            *existed = true;
789            value.is_changed()
790        } else if *existed {
791            *existed = false;
792            true
793        } else {
794            false
795        }
796    }
797
798    /// A [`Condition`]-satisfying system that returns `true`
799    /// if the resource of the given type has been removed since the condition was last checked.
800    ///
801    /// # Example
802    ///
803    /// ```
804    /// # use bevy_ecs::prelude::*;
805    /// # #[derive(Resource, Default)]
806    /// # struct Counter(u8);
807    /// # let mut app = Schedule::default();
808    /// # let mut world = World::new();
809    /// # world.init_resource::<Counter>();
810    /// app.add_systems(
811    ///     // `resource_removed` will only return true if the
812    ///     // given resource was just removed
813    ///     my_system.run_if(resource_removed::<MyResource>),
814    /// );
815    ///
816    /// #[derive(Resource, Default)]
817    /// struct MyResource;
818    ///
819    /// fn my_system(mut counter: ResMut<Counter>) {
820    ///     counter.0 += 1;
821    /// }
822    ///
823    /// world.init_resource::<MyResource>();
824    ///
825    /// // `MyResource` hasn't just been removed so `my_system` won't run
826    /// app.run(&mut world);
827    /// assert_eq!(world.resource::<Counter>().0, 0);
828    ///
829    /// world.remove_resource::<MyResource>();
830    ///
831    /// // `MyResource` was just removed so `my_system` will run
832    /// app.run(&mut world);
833    /// assert_eq!(world.resource::<Counter>().0, 1);
834    /// ```
835    pub fn resource_removed<T>(res: Option<Res<T>>, mut existed: Local<bool>) -> bool
836    where
837        T: Resource,
838    {
839        if res.is_some() {
840            *existed = true;
841            false
842        } else if *existed {
843            *existed = false;
844            true
845        } else {
846            false
847        }
848    }
849
850    /// A [`Condition`]-satisfying system that returns `true`
851    /// if there are any new events of the given type since it was last called.
852    ///
853    /// # Example
854    ///
855    /// ```
856    /// # use bevy_ecs::prelude::*;
857    /// # #[derive(Resource, Default)]
858    /// # struct Counter(u8);
859    /// # let mut app = Schedule::default();
860    /// # let mut world = World::new();
861    /// # world.init_resource::<Counter>();
862    /// # world.init_resource::<Events<MyEvent>>();
863    /// # app.add_systems(bevy_ecs::event::event_update_system.before(my_system));
864    ///
865    /// app.add_systems(
866    ///     my_system.run_if(on_event::<MyEvent>),
867    /// );
868    ///
869    /// #[derive(Event)]
870    /// struct MyEvent;
871    ///
872    /// fn my_system(mut counter: ResMut<Counter>) {
873    ///     counter.0 += 1;
874    /// }
875    ///
876    /// // No new `MyEvent` events have been push so `my_system` won't run
877    /// app.run(&mut world);
878    /// assert_eq!(world.resource::<Counter>().0, 0);
879    ///
880    /// world.resource_mut::<Events<MyEvent>>().send(MyEvent);
881    ///
882    /// // A `MyEvent` event has been pushed so `my_system` will run
883    /// app.run(&mut world);
884    /// assert_eq!(world.resource::<Counter>().0, 1);
885    /// ```
886    pub fn on_event<T: Event>(mut reader: EventReader<T>) -> bool {
887        // The events need to be consumed, so that there are no false positives on subsequent
888        // calls of the run condition. Simply checking `is_empty` would not be enough.
889        // PERF: note that `count` is efficient (not actually looping/iterating),
890        // due to Bevy having a specialized implementation for events.
891        reader.read().count() > 0
892    }
893
894    /// A [`Condition`]-satisfying system that returns `true`
895    /// if there are any entities with the given component type.
896    ///
897    /// # Example
898    ///
899    /// ```
900    /// # use bevy_ecs::prelude::*;
901    /// # #[derive(Resource, Default)]
902    /// # struct Counter(u8);
903    /// # let mut app = Schedule::default();
904    /// # let mut world = World::new();
905    /// # world.init_resource::<Counter>();
906    /// app.add_systems(
907    ///     my_system.run_if(any_with_component::<MyComponent>),
908    /// );
909    ///
910    /// #[derive(Component)]
911    /// struct MyComponent;
912    ///
913    /// fn my_system(mut counter: ResMut<Counter>) {
914    ///     counter.0 += 1;
915    /// }
916    ///
917    /// // No entities exist yet with a `MyComponent` component so `my_system` won't run
918    /// app.run(&mut world);
919    /// assert_eq!(world.resource::<Counter>().0, 0);
920    ///
921    /// world.spawn(MyComponent);
922    ///
923    /// // An entities with `MyComponent` now exists so `my_system` will run
924    /// app.run(&mut world);
925    /// assert_eq!(world.resource::<Counter>().0, 1);
926    /// ```
927    pub fn any_with_component<T: Component>(query: Query<(), With<T>>) -> bool {
928        !query.is_empty()
929    }
930
931    /// A [`Condition`]-satisfying system that returns `true`
932    /// if there are any entity with a component of the given type removed.
933    pub fn any_component_removed<T: Component>(mut removals: RemovedComponents<T>) -> bool {
934        // `RemovedComponents` based on events and therefore events need to be consumed,
935        // so that there are no false positives on subsequent calls of the run condition.
936        // Simply checking `is_empty` would not be enough.
937        // PERF: note that `count` is efficient (not actually looping/iterating),
938        // due to Bevy having a specialized implementation for events.
939        removals.read().count() > 0
940    }
941
942    /// A [`Condition`]-satisfying system that returns `true`
943    /// if there are any entities that match the given [`QueryFilter`].
944    pub fn any_match_filter<F: QueryFilter>(query: Query<(), F>) -> bool {
945        !query.is_empty()
946    }
947
948    /// Generates a [`Condition`] that inverses the result of passed one.
949    ///
950    /// # Example
951    ///
952    /// ```
953    /// # use bevy_ecs::prelude::*;
954    /// # #[derive(Resource, Default)]
955    /// # struct Counter(u8);
956    /// # let mut app = Schedule::default();
957    /// # let mut world = World::new();
958    /// # world.init_resource::<Counter>();
959    /// app.add_systems(
960    ///     // `not` will inverse any condition you pass in.
961    ///     // Since the condition we choose always returns true
962    ///     // this system will never run
963    ///     my_system.run_if(not(always)),
964    /// );
965    ///
966    /// fn my_system(mut counter: ResMut<Counter>) {
967    ///     counter.0 += 1;
968    /// }
969    ///
970    /// fn always() -> bool {
971    ///     true
972    /// }
973    ///
974    /// app.run(&mut world);
975    /// assert_eq!(world.resource::<Counter>().0, 0);
976    /// ```
977    pub fn not<Marker, TOut, T>(condition: T) -> NotSystem<T::System>
978    where
979        TOut: core::ops::Not,
980        T: IntoSystem<(), TOut, Marker>,
981    {
982        let condition = IntoSystem::into_system(condition);
983        let name = format!("!{}", condition.name());
984        NotSystem::new(super::NotMarker, condition, name.into())
985    }
986
987    /// Generates a [`Condition`] that returns true when the passed one changes.
988    ///
989    /// The first time this is called, the passed condition is assumed to have been previously false.
990    ///
991    /// # Example
992    ///
993    /// ```
994    /// # use bevy_ecs::prelude::*;
995    /// # #[derive(Resource, Default)]
996    /// # struct Counter(u8);
997    /// # let mut app = Schedule::default();
998    /// # let mut world = World::new();
999    /// # world.init_resource::<Counter>();
1000    /// app.add_systems(
1001    ///     my_system.run_if(condition_changed(resource_exists::<MyResource>)),
1002    /// );
1003    ///
1004    /// #[derive(Resource)]
1005    /// struct MyResource;
1006    ///
1007    /// fn my_system(mut counter: ResMut<Counter>) {
1008    ///     counter.0 += 1;
1009    /// }
1010    ///
1011    /// // `MyResource` is initially there, the inner condition is true, the system runs once
1012    /// world.insert_resource(MyResource);
1013    /// app.run(&mut world);
1014    /// assert_eq!(world.resource::<Counter>().0, 1);
1015    /// app.run(&mut world);
1016    /// assert_eq!(world.resource::<Counter>().0, 1);
1017    ///
1018    /// // We remove `MyResource`, the inner condition is now false, the system runs one more time.
1019    /// world.remove_resource::<MyResource>();
1020    /// app.run(&mut world);
1021    /// assert_eq!(world.resource::<Counter>().0, 2);
1022    /// app.run(&mut world);
1023    /// assert_eq!(world.resource::<Counter>().0, 2);
1024    /// ```
1025    pub fn condition_changed<Marker, CIn, C>(condition: C) -> impl Condition<(), CIn>
1026    where
1027        CIn: SystemInput,
1028        C: Condition<Marker, CIn>,
1029    {
1030        IntoSystem::into_system(condition.pipe(|In(new): In<bool>, mut prev: Local<bool>| {
1031            let changed = *prev != new;
1032            *prev = new;
1033            changed
1034        }))
1035    }
1036
1037    /// Generates a [`Condition`] that returns true when the result of
1038    /// the passed one went from false to true since the last time this was called.
1039    ///
1040    /// The first time this is called, the passed condition is assumed to have been previously false.
1041    ///
1042    /// # Example
1043    ///
1044    /// ```
1045    /// # use bevy_ecs::prelude::*;
1046    /// # #[derive(Resource, Default)]
1047    /// # struct Counter(u8);
1048    /// # let mut app = Schedule::default();
1049    /// # let mut world = World::new();
1050    /// # world.init_resource::<Counter>();
1051    /// app.add_systems(
1052    ///     my_system.run_if(condition_changed_to(true, resource_exists::<MyResource>)),
1053    /// );
1054    ///
1055    /// #[derive(Resource)]
1056    /// struct MyResource;
1057    ///
1058    /// fn my_system(mut counter: ResMut<Counter>) {
1059    ///     counter.0 += 1;
1060    /// }
1061    ///
1062    /// // `MyResource` is initially there, the inner condition is true, the system runs once
1063    /// world.insert_resource(MyResource);
1064    /// app.run(&mut world);
1065    /// assert_eq!(world.resource::<Counter>().0, 1);
1066    /// app.run(&mut world);
1067    /// assert_eq!(world.resource::<Counter>().0, 1);
1068    ///
1069    /// // We remove `MyResource`, the inner condition is now false, the system doesn't run.
1070    /// world.remove_resource::<MyResource>();
1071    /// app.run(&mut world);
1072    /// assert_eq!(world.resource::<Counter>().0, 1);
1073    ///
1074    /// // We reinsert `MyResource` again, so the system will run one more time
1075    /// world.insert_resource(MyResource);
1076    /// app.run(&mut world);
1077    /// assert_eq!(world.resource::<Counter>().0, 2);
1078    /// app.run(&mut world);
1079    /// assert_eq!(world.resource::<Counter>().0, 2);
1080    /// ```
1081    pub fn condition_changed_to<Marker, CIn, C>(to: bool, condition: C) -> impl Condition<(), CIn>
1082    where
1083        CIn: SystemInput,
1084        C: Condition<Marker, CIn>,
1085    {
1086        IntoSystem::into_system(condition.pipe(
1087            move |In(new): In<bool>, mut prev: Local<bool>| -> bool {
1088                let now_true = *prev != new && new == to;
1089                *prev = new;
1090                now_true
1091            },
1092        ))
1093    }
1094}
1095
1096/// Invokes [`Not`] with the output of another system.
1097///
1098/// See [`common_conditions::not`] for examples.
1099pub type NotSystem<S> = AdapterSystem<NotMarker, S>;
1100
1101/// Used with [`AdapterSystem`] to negate the output of a system via the [`Not`] operator.
1102#[doc(hidden)]
1103#[derive(Clone, Copy)]
1104pub struct NotMarker;
1105
1106impl<S: System<Out: Not>> Adapt<S> for NotMarker {
1107    type In = S::In;
1108    type Out = <S::Out as Not>::Output;
1109
1110    fn adapt(
1111        &mut self,
1112        input: <Self::In as SystemInput>::Inner<'_>,
1113        run_system: impl FnOnce(SystemIn<'_, S>) -> S::Out,
1114    ) -> Self::Out {
1115        !run_system(input)
1116    }
1117}
1118
1119/// Combines the outputs of two systems using the `&&` operator.
1120pub type And<A, B> = CombinatorSystem<AndMarker, A, B>;
1121
1122/// Combines and inverts the outputs of two systems using the `&&` and `!` operators.
1123pub type Nand<A, B> = CombinatorSystem<NandMarker, A, B>;
1124
1125/// Combines and inverts the outputs of two systems using the `&&` and `!` operators.
1126pub type Nor<A, B> = CombinatorSystem<NorMarker, A, B>;
1127
1128/// Combines the outputs of two systems using the `||` operator.
1129pub type Or<A, B> = CombinatorSystem<OrMarker, A, B>;
1130
1131/// Combines and inverts the outputs of two systems using the `^` and `!` operators.
1132pub type Xnor<A, B> = CombinatorSystem<XnorMarker, A, B>;
1133
1134/// Combines the outputs of two systems using the `^` operator.
1135pub type Xor<A, B> = CombinatorSystem<XorMarker, A, B>;
1136
1137#[doc(hidden)]
1138pub struct AndMarker;
1139
1140impl<In, A, B> Combine<A, B> for AndMarker
1141where
1142    for<'a> In: SystemInput<Inner<'a>: Copy>,
1143    A: System<In = In, Out = bool>,
1144    B: System<In = In, Out = bool>,
1145{
1146    type In = In;
1147    type Out = bool;
1148
1149    fn combine(
1150        input: <Self::In as SystemInput>::Inner<'_>,
1151        a: impl FnOnce(SystemIn<'_, A>) -> A::Out,
1152        b: impl FnOnce(SystemIn<'_, A>) -> B::Out,
1153    ) -> Self::Out {
1154        a(input) && b(input)
1155    }
1156}
1157
1158#[doc(hidden)]
1159pub struct NandMarker;
1160
1161impl<In, A, B> Combine<A, B> for NandMarker
1162where
1163    for<'a> In: SystemInput<Inner<'a>: Copy>,
1164    A: System<In = In, Out = bool>,
1165    B: System<In = In, Out = bool>,
1166{
1167    type In = In;
1168    type Out = bool;
1169
1170    fn combine(
1171        input: <Self::In as SystemInput>::Inner<'_>,
1172        a: impl FnOnce(SystemIn<'_, A>) -> A::Out,
1173        b: impl FnOnce(SystemIn<'_, B>) -> B::Out,
1174    ) -> Self::Out {
1175        !(a(input) && b(input))
1176    }
1177}
1178
1179#[doc(hidden)]
1180pub struct NorMarker;
1181
1182impl<In, A, B> Combine<A, B> for NorMarker
1183where
1184    for<'a> In: SystemInput<Inner<'a>: Copy>,
1185    A: System<In = In, Out = bool>,
1186    B: System<In = In, Out = bool>,
1187{
1188    type In = In;
1189    type Out = bool;
1190
1191    fn combine(
1192        input: <Self::In as SystemInput>::Inner<'_>,
1193        a: impl FnOnce(SystemIn<'_, A>) -> A::Out,
1194        b: impl FnOnce(SystemIn<'_, B>) -> B::Out,
1195    ) -> Self::Out {
1196        !(a(input) || b(input))
1197    }
1198}
1199
1200#[doc(hidden)]
1201pub struct OrMarker;
1202
1203impl<In, A, B> Combine<A, B> for OrMarker
1204where
1205    for<'a> In: SystemInput<Inner<'a>: Copy>,
1206    A: System<In = In, Out = bool>,
1207    B: System<In = In, Out = bool>,
1208{
1209    type In = In;
1210    type Out = bool;
1211
1212    fn combine(
1213        input: <Self::In as SystemInput>::Inner<'_>,
1214        a: impl FnOnce(SystemIn<'_, A>) -> A::Out,
1215        b: impl FnOnce(SystemIn<'_, B>) -> B::Out,
1216    ) -> Self::Out {
1217        a(input) || b(input)
1218    }
1219}
1220
1221#[doc(hidden)]
1222pub struct XnorMarker;
1223
1224impl<In, A, B> Combine<A, B> for XnorMarker
1225where
1226    for<'a> In: SystemInput<Inner<'a>: Copy>,
1227    A: System<In = In, Out = bool>,
1228    B: System<In = In, Out = bool>,
1229{
1230    type In = In;
1231    type Out = bool;
1232
1233    fn combine(
1234        input: <Self::In as SystemInput>::Inner<'_>,
1235        a: impl FnOnce(SystemIn<'_, A>) -> A::Out,
1236        b: impl FnOnce(SystemIn<'_, B>) -> B::Out,
1237    ) -> Self::Out {
1238        !(a(input) ^ b(input))
1239    }
1240}
1241
1242#[doc(hidden)]
1243pub struct XorMarker;
1244
1245impl<In, A, B> Combine<A, B> for XorMarker
1246where
1247    for<'a> In: SystemInput<Inner<'a>: Copy>,
1248    A: System<In = In, Out = bool>,
1249    B: System<In = In, Out = bool>,
1250{
1251    type In = In;
1252    type Out = bool;
1253
1254    fn combine(
1255        input: <Self::In as SystemInput>::Inner<'_>,
1256        a: impl FnOnce(SystemIn<'_, A>) -> A::Out,
1257        b: impl FnOnce(SystemIn<'_, B>) -> B::Out,
1258    ) -> Self::Out {
1259        a(input) ^ b(input)
1260    }
1261}
1262
1263#[cfg(test)]
1264mod tests {
1265    use super::{common_conditions::*, Condition};
1266    use crate::query::With;
1267    use crate::{
1268        change_detection::ResMut,
1269        component::Component,
1270        schedule::{IntoScheduleConfigs, Schedule},
1271        system::Local,
1272        world::World,
1273    };
1274    use bevy_ecs_macros::{Event, Resource};
1275
1276    #[derive(Resource, Default)]
1277    struct Counter(usize);
1278
1279    fn increment_counter(mut counter: ResMut<Counter>) {
1280        counter.0 += 1;
1281    }
1282
1283    fn double_counter(mut counter: ResMut<Counter>) {
1284        counter.0 *= 2;
1285    }
1286
1287    fn every_other_time(mut has_ran: Local<bool>) -> bool {
1288        *has_ran = !*has_ran;
1289        *has_ran
1290    }
1291
1292    #[test]
1293    fn run_condition() {
1294        let mut world = World::new();
1295        world.init_resource::<Counter>();
1296        let mut schedule = Schedule::default();
1297
1298        // Run every other cycle
1299        schedule.add_systems(increment_counter.run_if(every_other_time));
1300
1301        schedule.run(&mut world);
1302        schedule.run(&mut world);
1303        assert_eq!(world.resource::<Counter>().0, 1);
1304        schedule.run(&mut world);
1305        schedule.run(&mut world);
1306        assert_eq!(world.resource::<Counter>().0, 2);
1307
1308        // Run every other cycle opposite to the last one
1309        schedule.add_systems(increment_counter.run_if(not(every_other_time)));
1310
1311        schedule.run(&mut world);
1312        schedule.run(&mut world);
1313        assert_eq!(world.resource::<Counter>().0, 4);
1314        schedule.run(&mut world);
1315        schedule.run(&mut world);
1316        assert_eq!(world.resource::<Counter>().0, 6);
1317    }
1318
1319    #[test]
1320    fn run_condition_combinators() {
1321        let mut world = World::new();
1322        world.init_resource::<Counter>();
1323        let mut schedule = Schedule::default();
1324
1325        schedule.add_systems(
1326            (
1327                increment_counter.run_if(every_other_time.and(|| true)), // Run every odd cycle.
1328                increment_counter.run_if(every_other_time.nand(|| false)), // Always run.
1329                double_counter.run_if(every_other_time.nor(|| false)),   // Run every even cycle.
1330                increment_counter.run_if(every_other_time.or(|| true)),  // Always run.
1331                increment_counter.run_if(every_other_time.xnor(|| true)), // Run every odd cycle.
1332                double_counter.run_if(every_other_time.xnor(|| false)),  // Run every even cycle.
1333                increment_counter.run_if(every_other_time.xor(|| false)), // Run every odd cycle.
1334                double_counter.run_if(every_other_time.xor(|| true)),    // Run every even cycle.
1335            )
1336                .chain(),
1337        );
1338
1339        schedule.run(&mut world);
1340        assert_eq!(world.resource::<Counter>().0, 5);
1341        schedule.run(&mut world);
1342        assert_eq!(world.resource::<Counter>().0, 52);
1343    }
1344
1345    #[test]
1346    fn multiple_run_conditions() {
1347        let mut world = World::new();
1348        world.init_resource::<Counter>();
1349        let mut schedule = Schedule::default();
1350
1351        // Run every other cycle
1352        schedule.add_systems(increment_counter.run_if(every_other_time).run_if(|| true));
1353        // Never run
1354        schedule.add_systems(increment_counter.run_if(every_other_time).run_if(|| false));
1355
1356        schedule.run(&mut world);
1357        assert_eq!(world.resource::<Counter>().0, 1);
1358        schedule.run(&mut world);
1359        assert_eq!(world.resource::<Counter>().0, 1);
1360    }
1361
1362    #[test]
1363    fn multiple_run_conditions_is_and_operation() {
1364        let mut world = World::new();
1365        world.init_resource::<Counter>();
1366
1367        let mut schedule = Schedule::default();
1368
1369        // This should never run, if multiple run conditions worked
1370        // like an OR condition then it would always run
1371        schedule.add_systems(
1372            increment_counter
1373                .run_if(every_other_time)
1374                .run_if(not(every_other_time)),
1375        );
1376
1377        schedule.run(&mut world);
1378        assert_eq!(world.resource::<Counter>().0, 0);
1379        schedule.run(&mut world);
1380        assert_eq!(world.resource::<Counter>().0, 0);
1381    }
1382    #[derive(Component)]
1383    struct TestComponent;
1384
1385    #[derive(Event)]
1386    struct TestEvent;
1387
1388    #[derive(Resource)]
1389    struct TestResource(());
1390
1391    fn test_system() {}
1392
1393    // Ensure distributive_run_if compiles with the common conditions.
1394    #[test]
1395    fn distributive_run_if_compiles() {
1396        Schedule::default().add_systems(
1397            (test_system, test_system)
1398                .distributive_run_if(run_once)
1399                .distributive_run_if(resource_exists::<TestResource>)
1400                .distributive_run_if(resource_added::<TestResource>)
1401                .distributive_run_if(resource_changed::<TestResource>)
1402                .distributive_run_if(resource_exists_and_changed::<TestResource>)
1403                .distributive_run_if(resource_changed_or_removed::<TestResource>)
1404                .distributive_run_if(resource_removed::<TestResource>)
1405                .distributive_run_if(on_event::<TestEvent>)
1406                .distributive_run_if(any_with_component::<TestComponent>)
1407                .distributive_run_if(any_match_filter::<With<TestComponent>>)
1408                .distributive_run_if(not(run_once)),
1409        );
1410    }
1411}