Skip to main content

bevy_ecs/schedule/
condition.rs

1use alloc::{boxed::Box, format};
2use bevy_utils::prelude::DebugName;
3use core::ops::Not;
4
5use crate::system::{
6    Adapt, AdapterSystem, CombinatorSystem, Combine, IntoSystem, ReadOnlySystem, RunSystemError,
7    System, SystemIn, SystemInput,
8};
9
10/// A type-erased run condition stored in a [`Box`].
11pub type BoxedCondition<In = ()> = Box<dyn ReadOnlySystem<In = In, Out = bool>>;
12
13/// A system that determines if one or more scheduled systems should run.
14///
15/// Implemented for functions and closures that convert into [`System<Out=bool>`](System)
16/// with [read-only](crate::system::ReadOnlySystemParam) parameters.
17///
18/// # Marker type parameter
19///
20/// `SystemCondition` trait has `Marker` type parameter, which has no special meaning,
21/// but exists to work around the limitation of Rust's trait system.
22///
23/// Type parameter in return type can be set to `<()>` by calling [`IntoSystem::into_system`],
24/// but usually have to be specified when passing a condition to a function.
25///
26/// ```
27/// # use bevy_ecs::schedule::SystemCondition;
28/// # use bevy_ecs::system::IntoSystem;
29/// fn not_condition<Marker>(a: impl SystemCondition<Marker>) -> impl SystemCondition<()> {
30///    IntoSystem::into_system(a.map(|x| !x))
31/// }
32/// ```
33///
34/// # Examples
35/// A condition that returns true every other time it's called.
36/// ```
37/// # use bevy_ecs::prelude::*;
38/// fn every_other_time() -> impl SystemCondition<()> {
39///     IntoSystem::into_system(|mut flag: Local<bool>| {
40///         *flag = !*flag;
41///         *flag
42///     })
43/// }
44///
45/// # #[derive(Resource)] struct DidRun(bool);
46/// # fn my_system(mut did_run: ResMut<DidRun>) { did_run.0 = true; }
47/// # let mut schedule = Schedule::default();
48/// schedule.add_systems(my_system.run_if(every_other_time()));
49/// # let mut world = World::new();
50/// # world.insert_resource(DidRun(false));
51/// # schedule.run(&mut world);
52/// # assert!(world.resource::<DidRun>().0);
53/// # world.insert_resource(DidRun(false));
54/// # schedule.run(&mut world);
55/// # assert!(!world.resource::<DidRun>().0);
56/// ```
57///
58/// A condition that takes a bool as an input and returns it unchanged.
59///
60/// ```
61/// # use bevy_ecs::prelude::*;
62/// fn identity() -> impl SystemCondition<(), In<bool>> {
63///     IntoSystem::into_system(|In(x): In<bool>| x)
64/// }
65///
66/// # fn always_true() -> bool { true }
67/// # let mut app = Schedule::default();
68/// # #[derive(Resource)] struct DidRun(bool);
69/// # fn my_system(mut did_run: ResMut<DidRun>) { did_run.0 = true; }
70/// app.add_systems(my_system.run_if(always_true.pipe(identity())));
71/// # let mut world = World::new();
72/// # world.insert_resource(DidRun(false));
73/// # app.run(&mut world);
74/// # assert!(world.resource::<DidRun>().0);
75pub trait SystemCondition<Marker, In: SystemInput = ()>:
76    IntoSystem<In, bool, Marker, System: ReadOnlySystem>
77{
78    /// Returns a new run condition that only returns `true`
79    /// if both this one and the passed `then_run` return `true`.
80    ///
81    /// The returned run condition is short-circuiting, meaning
82    /// `then_run` will only be invoked if `self` returns `true`.
83    ///
84    /// Short-circuiting may not be desired in all cases; when utilizing change detection,
85    /// the `then_run` condition will react to changes since the last time that _`self` returned `true`_,
86    /// which may introduce subtle inconsistencies if short-circuiting was not intended. Similar issues
87    /// may arise for run conditions that rely on internal state, such as those using [`Local<T>`] parameters
88    /// or [`MessageReader<T>`], as they may not be updated every time the combined condition is evaluated.
89    ///
90    /// [`Local<T>`]: crate::system::Local
91    /// [`MessageReader<T>`]: crate::message::MessageReader
92    ///
93    /// See also [`and_eager`], which always evaluates both conditions.
94    ///
95    /// [`and_eager`]: SystemCondition::and_eager
96    ///
97    /// # Examples
98    ///
99    /// ```should_panic
100    /// use bevy_ecs::prelude::*;
101    ///
102    /// #[derive(Resource, PartialEq)]
103    /// struct R(u32);
104    ///
105    /// # let mut schedule = Schedule::default();
106    /// # let mut world = World::new();
107    /// # fn my_system() {}
108    /// schedule.add_systems(
109    ///     // The `resource_equals` run condition will panic since we don't initialize `R`,
110    ///     // just like if we used `Res<R>` in a system.
111    ///     my_system.run_if(resource_equals(R(0))),
112    /// );
113    /// # schedule.run(&mut world);
114    /// ```
115    ///
116    /// Use `.and_then()` to avoid checking the condition.
117    ///
118    /// ```
119    /// # use bevy_ecs::prelude::*;
120    /// # #[derive(Resource, PartialEq)]
121    /// # struct R(u32);
122    /// # let mut schedule = Schedule::default();
123    /// # let mut world = World::new();
124    /// # fn my_system() { unreachable!() }
125    /// schedule.add_systems(
126    ///     // `resource_equals` will only get run if the resource `R` exists.
127    ///     my_system.run_if(resource_exists::<R>.and_then(resource_equals(R(0)))),
128    /// );
129    /// # schedule.run(&mut world);
130    /// ```
131    ///
132    /// Note that in this specific case, it's better to just use the run condition [`resource_exists_and_equals`].
133    ///
134    /// [`resource_exists_and_equals`]: common_conditions::resource_exists_and_equals
135    fn and_then<M, C: SystemCondition<M, In>>(
136        self,
137        then_run: C,
138    ) -> AndThen<Self::System, C::System> {
139        let a = IntoSystem::into_system(self);
140        let b = IntoSystem::into_system(then_run);
141        let name = format!("{} && {}", a.name(), b.name());
142        CombinatorSystem::new(a, b, DebugName::owned(name))
143    }
144
145    /// Returns a new run condition that only returns `true`
146    /// if both this one and the passed `then_run` return `true`.
147    ///
148    /// The returned run condition is eagerly evaluated, meaning
149    /// it will always execute both run conditions in order.
150    ///
151    /// When applied directly to a system using [`run_if`], the use of this combinator
152    /// is behaviorally identical to simply calling `run_if` multiple times. However,
153    /// `.and_eager` may be more efficient, as it does not erase the types of the inner conditions
154    /// when evaluating them, which may allow for compiler optimizations that are not possible
155    /// with separate calls to `run_if`.
156    ///
157    /// See also [`and_then`], which short-circuits if `self` returns `false`.
158    ///
159    /// [`run_if`]: crate::schedule::IntoScheduleConfigs::run_if
160    /// [`and_then`]: SystemCondition::and_then
161    ///
162    /// # Examples
163    ///
164    /// ```
165    /// # use bevy_ecs::prelude::*;
166    /// # use std::sync::atomic::AtomicBool;
167    /// # use std::sync::atomic::Ordering;
168    /// # #[derive(Resource, PartialEq)]
169    /// # struct R(u32);
170    /// # let mut schedule = Schedule::default();
171    /// # let mut world = World::new();
172    /// # fn my_system() { unreachable!() }
173    /// # static CONDITION_A_RAN: AtomicBool = AtomicBool::new(false);
174    /// # static CONDITION_B_RAN: AtomicBool = AtomicBool::new(false);
175    /// # fn returns_false() -> bool {
176    /// #   CONDITION_A_RAN.store(true, Ordering::Relaxed);
177    /// #   false
178    /// # }
179    /// # fn returns_true() -> bool {
180    /// #   CONDITION_B_RAN.store(true, Ordering::Relaxed);
181    /// #   true
182    /// # }
183    /// schedule.add_systems(
184    ///     // both conditions will execute, even though the first one returned false
185    ///     my_system.run_if(returns_false.and_eager(returns_true)),
186    /// );
187    /// # schedule.run(&mut world);
188    /// # assert!(CONDITION_A_RAN.load(Ordering::Relaxed));
189    /// # assert!(CONDITION_B_RAN.load(Ordering::Relaxed));
190    /// ```
191    fn and_eager<M, C: SystemCondition<M, In>>(
192        self,
193        other: C,
194    ) -> AndEager<Self::System, C::System> {
195        let a = IntoSystem::into_system(self);
196        let b = IntoSystem::into_system(other);
197        let name = format!("{} & {}", a.name(), b.name());
198        CombinatorSystem::new(a, b, DebugName::owned(name))
199    }
200
201    /// Returns a new run condition that only returns `true`
202    /// if both this one and the passed `then_run` return `true`.
203    #[deprecated(
204        since = "0.19.0",
205        note = "use `.and_then(...)` instead, or `.and_eager(...)` to evaluate the conditions eagerly"
206    )]
207    fn and<M, C: SystemCondition<M, In>>(self, then_run: C) -> AndThen<Self::System, C::System> {
208        let a = IntoSystem::into_system(self);
209        let b = IntoSystem::into_system(then_run);
210        let name = format!("{} && {}", a.name(), b.name());
211        CombinatorSystem::new(a, b, DebugName::owned(name))
212    }
213
214    /// Returns a new run condition that only returns `false`
215    /// if both this one and the passed `then_run` return `true`.
216    ///
217    /// The returned run condition is short-circuiting, meaning
218    /// `then_run` will only be invoked if `self` returns `true`.
219    ///
220    /// Short-circuiting may not be desired in all cases; when utilizing change detection,
221    /// the `then_run` condition will react to changes since the last time that _`self` returned `true`_,
222    /// which may introduce subtle inconsistencies if short-circuiting was not intended. Similar issues
223    /// may arise for run conditions that rely on internal state, such as those using [`Local<T>`] parameters
224    /// or [`MessageReader<T>`], as they may not be updated every time the combined condition is evaluated.
225    ///
226    /// [`Local<T>`]: crate::system::Local
227    /// [`MessageReader<T>`]: crate::message::MessageReader
228    ///
229    /// See also [`nand_eager`], which always evaluates both conditions.
230    ///
231    /// [`nand_eager`]: SystemCondition::nand_eager
232    ///
233    /// # Examples
234    ///
235    /// ```
236    /// # use bevy_ecs::prelude::*;
237    /// #
238    /// # #[derive(Resource, Debug, Clone, PartialEq, Eq, Hash)]
239    /// # pub enum PlayerState {
240    /// #     Alive,
241    /// #     Dead,
242    /// # }
243    /// # #[derive(Resource, Debug, Clone, PartialEq, Eq, Hash)]
244    /// # pub enum EnemyState {
245    /// #     Alive,
246    /// #     Dead,
247    /// # }
248    /// #
249    /// # use std::sync::atomic::AtomicUsize;
250    /// # use std::sync::atomic::Ordering;
251    /// # static IN_STATE_RUN_COUNT: AtomicUsize = AtomicUsize::new(0);
252    /// # fn in_state<R: Resource + PartialEq>(state: R) -> impl Fn(Res<R>) -> bool {
253    /// #   move |current_state| {
254    /// #       IN_STATE_RUN_COUNT.fetch_add(1, Ordering::Relaxed);
255    /// #       state == *current_state
256    /// #   }
257    /// # }
258    /// #
259    /// # #[derive(Resource)]
260    /// # struct RanGameOver(bool);
261    /// # fn game_over_credits(mut commands: Commands) { commands.insert_resource(RanGameOver(true)); }
262    /// # let mut schedule = Schedule::default();
263    /// # let mut world = World::new();
264    /// # world.insert_resource(PlayerState::Dead);
265    /// schedule.add_systems(
266    ///     // The game_over_credits system will only execute if either the `in_state(PlayerState::Alive)`
267    ///     // run condition or `in_state(EnemyState::Alive)` run condition evaluates to `false`.
268    ///     game_over_credits.run_if(
269    ///         in_state(PlayerState::Alive).nand_then(in_state(EnemyState::Alive)),
270    ///     ),
271    /// );
272    /// # schedule.run(&mut world);
273    /// # assert_eq!(IN_STATE_RUN_COUNT.load(Ordering::Relaxed), 1);
274    /// # assert!(world.resource::<RanGameOver>().0);
275    /// # IN_STATE_RUN_COUNT.store(0, Ordering::Relaxed);
276    /// # world.insert_resource(RanGameOver(false));
277    /// # world.insert_resource(PlayerState::Alive);
278    /// # world.insert_resource(EnemyState::Dead);
279    /// # schedule.run(&mut world);
280    /// # assert_eq!(IN_STATE_RUN_COUNT.load(Ordering::Relaxed), 2);
281    /// # assert!(world.resource::<RanGameOver>().0);
282    /// # IN_STATE_RUN_COUNT.store(0, Ordering::Relaxed);
283    /// # world.insert_resource(RanGameOver(false));
284    /// # world.insert_resource(EnemyState::Alive);
285    /// # schedule.run(&mut world);
286    /// # assert_eq!(IN_STATE_RUN_COUNT.load(Ordering::Relaxed), 2);
287    /// # assert!(!world.resource::<RanGameOver>().0);
288    /// ```
289    ///
290    /// Equivalent logic can be achieved by using `not` in concert with `and_then`:
291    ///
292    /// ```
293    /// # use bevy_ecs::prelude::*;
294    /// # #[derive(Resource, Debug, Clone, PartialEq, Eq, Hash)]
295    /// # pub enum PlayerState {
296    /// #     Alive,
297    /// #     Dead,
298    /// # }
299    /// # #[derive(Resource, Debug, Clone, PartialEq, Eq, Hash)]
300    /// # pub enum EnemyState {
301    /// #     Alive,
302    /// #     Dead,
303    /// # }
304    /// # fn in_state<R: Resource + PartialEq>(state: R) -> impl Fn(Res<R>) -> bool {
305    /// #   move |current_state| state == *current_state
306    /// # }
307    /// # fn game_over_credits() { unreachable!() }
308    /// # let mut schedule = Schedule::default();
309    /// # let mut world = World::new();
310    /// # world.insert_resource(PlayerState::Alive);
311    /// # world.insert_resource(EnemyState::Alive);
312    /// schedule.add_systems(
313    ///     game_over_credits.run_if(
314    ///         not(in_state(PlayerState::Alive).and_then(in_state(EnemyState::Alive))),
315    ///     ),
316    /// );
317    /// # schedule.run(&mut world);
318    /// ```
319    fn nand_then<M, C: SystemCondition<M, In>>(
320        self,
321        then_run: C,
322    ) -> NandThen<Self::System, C::System> {
323        let a = IntoSystem::into_system(self);
324        let b = IntoSystem::into_system(then_run);
325        let name = format!("!({} && {})", a.name(), b.name());
326        CombinatorSystem::new(a, b, DebugName::owned(name))
327    }
328
329    /// Returns a new run condition that only returns `false`
330    /// if both this one and the passed `then_run` return `true`.
331    ///
332    /// The returned run condition is eagerly evaluated, meaning
333    /// it will always execute both run conditions in order.
334    ///
335    /// See also [`nand_then`], which short-circuits if `self` returns `false`.
336    ///
337    /// [`nand_then`]: SystemCondition::nand_then
338    fn nand_eager<M, C: SystemCondition<M, In>>(
339        self,
340        other: C,
341    ) -> NandEager<Self::System, C::System> {
342        let a = IntoSystem::into_system(self);
343        let b = IntoSystem::into_system(other);
344        let name = format!("!({} & {})", a.name(), b.name());
345        CombinatorSystem::new(a, b, DebugName::owned(name))
346    }
347
348    /// Returns a new run condition that only returns `false`
349    /// if both this one and the passed `then_run` return `true`.
350    #[deprecated(
351        since = "0.19.0",
352        note = "use `.nand_then(...) instead, or `.nand_eager(...)` to evaluate the conditions eagerly"
353    )]
354    fn nand<M, C: SystemCondition<M, In>>(self, nand: C) -> NandThen<Self::System, C::System> {
355        self.nand_then(nand)
356    }
357
358    /// Returns a new run condition that only returns `true`
359    /// if both this one and the passed `else_run` return `false`.
360    ///
361    /// The returned run condition is short-circuiting, meaning
362    /// `else_run` will only be invoked if `self` returns `true`.
363    ///
364    /// Short-circuiting may not be desired in all cases; when utilizing change detection,
365    /// the `else_run` condition will react to changes since the last time that _`self` returned `true`_,
366    /// which may introduce subtle inconsistencies if short-circuiting was not intended. Similar issues
367    /// may arise for run conditions that rely on internal state, such as those using [`Local<T>`] parameters
368    /// or [`MessageReader<T>`], as they may not be updated every time the combined condition is evaluated.
369    ///
370    /// [`Local<T>`]: crate::system::Local
371    /// [`MessageReader<T>`]: crate::message::MessageReader
372    ///
373    /// See also [`nor_eager`], which always evaluates both conditions.
374    ///
375    /// [`nor_eager`]: SystemCondition::nor_eager
376    ///
377    /// # Examples
378    ///
379    /// ```compile_fail
380    /// use bevy::prelude::*;
381    ///
382    /// #[derive(States, Debug, Clone, PartialEq, Eq, Hash)]
383    /// pub enum WeatherState {
384    ///     Sunny,
385    ///     Cloudy,
386    /// }
387    ///
388    /// #[derive(States, Debug, Clone, PartialEq, Eq, Hash)]
389    /// pub enum SoilState {
390    ///     Fertilized,
391    ///     NotFertilized,
392    /// }
393    ///
394    /// # let mut app = Schedule::default();
395    /// # let mut world = World::new();
396    /// # fn slow_plant_growth() {}
397    /// app.add_systems(
398    ///     // The slow_plant_growth system will only execute if both the `in_state(WeatherState::Sunny)`
399    ///     // run condition and `in_state(SoilState::Fertilized)` run condition evaluate to `false`.
400    ///     slow_plant_growth.run_if(
401    ///         in_state(WeatherState::Sunny).nor_else(in_state(SoilState::Fertilized)),
402    ///     ),
403    /// );
404    /// # app.run(&mut world);
405    /// ```
406    ///
407    /// Equivalent logic can be achieved by using `not` in concert with `or`:
408    ///
409    /// ```compile_fail
410    /// app.add_systems(
411    ///     slow_plant_growth.run_if(
412    ///         not(in_state(WeatherState::Sunny).or_else(in_state(SoilState::Fertilized))),
413    ///     ),
414    /// );
415    /// ```
416    fn nor_else<M, C: SystemCondition<M, In>>(
417        self,
418        else_run: C,
419    ) -> NorElse<Self::System, C::System> {
420        let a = IntoSystem::into_system(self);
421        let b = IntoSystem::into_system(else_run);
422        let name = format!("!({} || {})", a.name(), b.name());
423        CombinatorSystem::new(a, b, DebugName::owned(name))
424    }
425
426    /// Returns a new run condition that only returns `true`
427    /// if both this one and the passed `else_run` return `false`.
428    ///
429    /// The returned run condition is eagerly evaluated, meaning
430    /// it will always execute both run conditions in order.
431    ///
432    /// See also [`nor_else`], which short-circuits if `self` returns `true`.
433    ///
434    /// [`nor_else`]: SystemCondition::nor_else
435    fn nor_eager<M, C: SystemCondition<M, In>>(
436        self,
437        other: C,
438    ) -> NorEager<Self::System, C::System> {
439        let a = IntoSystem::into_system(self);
440        let b = IntoSystem::into_system(other);
441        let name = format!("!({} | {})", a.name(), b.name());
442        CombinatorSystem::new(a, b, DebugName::owned(name))
443    }
444
445    /// Returns a new run condition that only returns `true`
446    /// if both this one and the passed `else_run` return `false`.
447    #[deprecated(
448        since = "0.19.0",
449        note = "use `.nor_else(...)` instead, or `.nor_eager(...)` to evaluate the conditions eagerly"
450    )]
451    fn nor<M, C: SystemCondition<M, In>>(self, else_run: C) -> NorElse<Self::System, C::System> {
452        self.nor_else(else_run)
453    }
454
455    /// Returns a new run condition that returns `true`
456    /// if either this one or the passed `or` return `true`.
457    ///
458    /// The returned run condition is short-circuiting, meaning
459    /// `or` will only be invoked if `self` returns `false`.
460    ///
461    /// Short-circuiting may not be desired in all cases; when utilizing change detection,
462    /// the `else_run` condition will react to changes since the last time that _`self` returned `false`_,
463    /// which may introduce subtle inconsistencies if short-circuiting was not intended. Similar issues
464    /// may arise for run conditions that rely on internal state, such as those using [`Local<T>`] parameters
465    /// or [`MessageReader<T>`], as they may not be updated every time the combined condition is evaluated.
466    ///
467    /// [`Local<T>`]: crate::system::Local
468    /// [`MessageReader<T>`]: crate::message::MessageReader
469    ///
470    /// See also [`or_eager`], which always evaluates both conditions.
471    ///
472    /// [`or_eager`]: SystemCondition::or_eager
473    ///
474    /// # Examples
475    ///
476    /// ```
477    /// use bevy_ecs::prelude::*;
478    ///
479    /// #[derive(Resource, PartialEq)]
480    /// struct A(u32);
481    ///
482    /// #[derive(Resource, PartialEq)]
483    /// struct B(u32);
484    ///
485    /// # let mut app = Schedule::default();
486    /// # let mut world = World::new();
487    /// # #[derive(Resource)] struct C(bool);
488    /// # fn my_system(mut c: ResMut<C>) { c.0 = true; }
489    /// app.add_systems(
490    ///     // Only run the system if either `A` or `B` exist.
491    ///     my_system.run_if(resource_exists::<A>.or(resource_exists::<B>)),
492    /// );
493    /// #
494    /// # world.insert_resource(C(false));
495    /// # app.run(&mut world);
496    /// # assert!(!world.resource::<C>().0);
497    /// #
498    /// # world.insert_resource(A(0));
499    /// # app.run(&mut world);
500    /// # assert!(world.resource::<C>().0);
501    /// #
502    /// # world.remove_resource::<A>();
503    /// # world.insert_resource(B(0));
504    /// # world.insert_resource(C(false));
505    /// # app.run(&mut world);
506    /// # assert!(world.resource::<C>().0);
507    /// ```
508    fn or_else<M, C: SystemCondition<M, In>>(self, else_run: C) -> OrElse<Self::System, C::System> {
509        let a = IntoSystem::into_system(self);
510        let b = IntoSystem::into_system(else_run);
511        let name = format!("{} || {}", a.name(), b.name());
512        CombinatorSystem::new(a, b, DebugName::owned(name))
513    }
514
515    /// Returns a new run condition that returns `true`
516    /// if either this one or the passed `or` return `true`.
517    ///
518    /// The returned run condition is eagerly evaluated, meaning
519    /// it will always execute both run conditions in order.
520    ///
521    /// See also [`or_else`], which short-circuits if `self` returns `true`.
522    ///
523    /// [`or_else`]: SystemCondition::or_else
524    fn or_eager<M, C: SystemCondition<M, In>>(self, other: C) -> OrEager<Self::System, C::System> {
525        let a = IntoSystem::into_system(self);
526        let b = IntoSystem::into_system(other);
527        let name = format!("{} | {}", a.name(), b.name());
528        CombinatorSystem::new(a, b, DebugName::owned(name))
529    }
530
531    /// Returns a new run condition that returns `true`
532    /// if either this one or the passed `or` return `true`.
533    #[deprecated(
534        since = "0.19.0",
535        note = "use `.or_else(...)` instead, or `.or_eager(...)` to eagerly evaluate both conditions"
536    )]
537    fn or<M, C: SystemCondition<M, In>>(self, else_run: C) -> OrElse<Self::System, C::System> {
538        self.or_else(else_run)
539    }
540
541    /// Returns a new run condition that only returns `true`
542    /// if `self` and `xnor` **both** return `false` or **both** return `true`.
543    ///
544    /// The returned run condition is eagerly evaluated, meaning
545    /// it will always execute both run conditions in order.
546    ///
547    /// # Examples
548    ///
549    /// ```compile_fail
550    /// use bevy::prelude::*;
551    ///
552    /// #[derive(States, Debug, Clone, PartialEq, Eq, Hash)]
553    /// pub enum CoffeeMachineState {
554    ///     Heating,
555    ///     Brewing,
556    ///     Inactive,
557    /// }
558    ///
559    /// #[derive(States, Debug, Clone, PartialEq, Eq, Hash)]
560    /// pub enum TeaKettleState {
561    ///     Heating,
562    ///     Steeping,
563    ///     Inactive,
564    /// }
565    ///
566    /// # let mut app = Schedule::default();
567    /// # let mut world = World::new();
568    /// # fn take_drink_orders() {}
569    /// app.add_systems(
570    ///     // The take_drink_orders system will only execute if the `in_state(CoffeeMachineState::Inactive)`
571    ///     // run condition and `in_state(TeaKettleState::Inactive)` run conditions both evaluate to `false`,
572    ///     // or both evaluate to `true`.
573    ///     take_drink_orders.run_if(
574    ///         in_state(CoffeeMachineState::Inactive).xnor(in_state(TeaKettleState::Inactive))
575    ///     ),
576    /// );
577    /// # app.run(&mut world);
578    /// ```
579    ///
580    /// Equivalent logic can be achieved by using `not` in concert with `xor`:
581    ///
582    /// ```compile_fail
583    /// app.add_systems(
584    ///     take_drink_orders.run_if(
585    ///         not(in_state(CoffeeMachineState::Inactive).xor(in_state(TeaKettleState::Inactive)))
586    ///     ),
587    /// );
588    /// ```
589    fn xnor<M, C: SystemCondition<M, In>>(self, other: C) -> Xnor<Self::System, C::System> {
590        let a = IntoSystem::into_system(self);
591        let b = IntoSystem::into_system(other);
592        let name = format!("!({} ^ {})", a.name(), b.name());
593        CombinatorSystem::new(a, b, DebugName::owned(name))
594    }
595
596    /// Returns a new run condition that only returns `true`
597    /// if either `self` or `xor` return `true`, but not both.
598    ///
599    /// The returned run condition is eagerly evaluated, meaning
600    /// it will always execute both run conditions in order.
601    ///
602    /// # Examples
603    ///
604    /// ```compile_fail
605    /// use bevy::prelude::*;
606    ///
607    /// #[derive(States, Debug, Clone, PartialEq, Eq, Hash)]
608    /// pub enum CoffeeMachineState {
609    ///     Heating,
610    ///     Brewing,
611    ///     Inactive,
612    /// }
613    ///
614    /// #[derive(States, Debug, Clone, PartialEq, Eq, Hash)]
615    /// pub enum TeaKettleState {
616    ///     Heating,
617    ///     Steeping,
618    ///     Inactive,
619    /// }
620    ///
621    /// # let mut app = Schedule::default();
622    /// # let mut world = World::new();
623    /// # fn prepare_beverage() {}
624    /// app.add_systems(
625    ///     // The prepare_beverage system will only execute if either the `in_state(CoffeeMachineState::Inactive)`
626    ///     // run condition or `in_state(TeaKettleState::Inactive)` run condition evaluates to `true`,
627    ///     // but not both.
628    ///     prepare_beverage.run_if(
629    ///         in_state(CoffeeMachineState::Inactive).xor(in_state(TeaKettleState::Inactive))
630    ///     ),
631    /// );
632    /// # app.run(&mut world);
633    /// ```
634    fn xor<M, C: SystemCondition<M, In>>(self, other: C) -> Xor<Self::System, C::System> {
635        let a = IntoSystem::into_system(self);
636        let b = IntoSystem::into_system(other);
637        let name = format!("({} ^ {})", a.name(), b.name());
638        CombinatorSystem::new(a, b, DebugName::owned(name))
639    }
640}
641
642impl<Marker, In: SystemInput, F> SystemCondition<Marker, In> for F where
643    F: IntoSystem<In, bool, Marker, System: ReadOnlySystem>
644{
645}
646
647/// A collection of [run conditions](SystemCondition) that may be useful in any bevy app.
648pub mod common_conditions {
649    use super::{NotSystem, SystemCondition};
650    use crate::{
651        change_detection::DetectChanges,
652        lifecycle::RemovedComponents,
653        message::{Message, MessageReader},
654        prelude::{Component, Query, With},
655        query::QueryFilter,
656        resource::Resource,
657        system::{In, IntoSystem, Local, Res, System, SystemInput},
658    };
659    use alloc::format;
660
661    /// A [`SystemCondition`]-satisfying system that returns `true`
662    /// on the first time the condition is run and false every time after.
663    ///
664    /// # Example
665    ///
666    /// ```
667    /// # use bevy_ecs::prelude::*;
668    /// # #[derive(Resource, Default)]
669    /// # struct Counter(u8);
670    /// # let mut app = Schedule::default();
671    /// # let mut world = World::new();
672    /// # world.init_resource::<Counter>();
673    /// app.add_systems(
674    ///     // `run_once` will only return true the first time it's evaluated
675    ///     my_system.run_if(run_once),
676    /// );
677    ///
678    /// fn my_system(mut counter: ResMut<Counter>) {
679    ///     counter.0 += 1;
680    /// }
681    ///
682    /// // This is the first time the condition will be evaluated so `my_system` will run
683    /// app.run(&mut world);
684    /// assert_eq!(world.resource::<Counter>().0, 1);
685    ///
686    /// // This is the seconds time the condition will be evaluated so `my_system` won't run
687    /// app.run(&mut world);
688    /// assert_eq!(world.resource::<Counter>().0, 1);
689    /// ```
690    pub fn run_once(mut has_run: Local<bool>) -> bool {
691        if !*has_run {
692            *has_run = true;
693            true
694        } else {
695            false
696        }
697    }
698
699    /// A [`SystemCondition`]-satisfying system that returns `true`
700    /// if the resource exists.
701    ///
702    /// To skip a system with a [`Res`] or [`ResMut`](crate::prelude::ResMut) parameter if the resource does not exist,
703    /// you may instead wrap the parameter in [`If`](crate::prelude::If), like `If<Res<T>>` or `If<ResMut<T>>`.
704    ///
705    /// # Example
706    ///
707    /// ```
708    /// # use bevy_ecs::prelude::*;
709    /// # #[derive(Resource, Default)]
710    /// # struct Counter(u8);
711    /// # let mut app = Schedule::default();
712    /// # let mut world = World::new();
713    /// app.add_systems(
714    ///     // `resource_exists` will only return true if the given resource exists in the world
715    ///     my_system.run_if(resource_exists::<Counter>),
716    /// );
717    ///
718    /// fn my_system(mut counter: ResMut<Counter>) {
719    ///     counter.0 += 1;
720    /// }
721    ///
722    /// // `Counter` hasn't been added so `my_system` won't run
723    /// app.run(&mut world);
724    /// world.init_resource::<Counter>();
725    ///
726    /// // `Counter` has now been added so `my_system` can run
727    /// app.run(&mut world);
728    /// assert_eq!(world.resource::<Counter>().0, 1);
729    /// ```
730    pub fn resource_exists<T>(res: Option<Res<T>>) -> bool
731    where
732        T: Resource,
733    {
734        res.is_some()
735    }
736
737    /// Generates a [`SystemCondition`]-satisfying closure that returns `true`
738    /// if the resource is equal to `value`.
739    ///
740    /// # Panics
741    ///
742    /// The condition will panic if the resource does not exist.
743    ///
744    /// # Example
745    ///
746    /// ```
747    /// # use bevy_ecs::prelude::*;
748    /// # #[derive(Resource, Default, PartialEq)]
749    /// # struct Counter(u8);
750    /// # let mut app = Schedule::default();
751    /// # let mut world = World::new();
752    /// # world.init_resource::<Counter>();
753    /// app.add_systems(
754    ///     // `resource_equals` will only return true if the given resource equals the given value
755    ///     my_system.run_if(resource_equals(Counter(0))),
756    /// );
757    ///
758    /// fn my_system(mut counter: ResMut<Counter>) {
759    ///     counter.0 += 1;
760    /// }
761    ///
762    /// // `Counter` is `0` so `my_system` can run
763    /// app.run(&mut world);
764    /// assert_eq!(world.resource::<Counter>().0, 1);
765    ///
766    /// // `Counter` is no longer `0` so `my_system` won't run
767    /// app.run(&mut world);
768    /// assert_eq!(world.resource::<Counter>().0, 1);
769    /// ```
770    pub fn resource_equals<T>(value: T) -> impl FnMut(Res<T>) -> bool
771    where
772        T: Resource + PartialEq,
773    {
774        move |res: Res<T>| *res == value
775    }
776
777    /// Generates a [`SystemCondition`]-satisfying closure that returns `true`
778    /// if the resource exists and is equal to `value`.
779    ///
780    /// The condition will return `false` if the resource does not exist.
781    ///
782    /// # Example
783    ///
784    /// ```
785    /// # use bevy_ecs::prelude::*;
786    /// # #[derive(Resource, Default, PartialEq)]
787    /// # struct Counter(u8);
788    /// # let mut app = Schedule::default();
789    /// # let mut world = World::new();
790    /// app.add_systems(
791    ///     // `resource_exists_and_equals` will only return true
792    ///     // if the given resource exists and equals the given value
793    ///     my_system.run_if(resource_exists_and_equals(Counter(0))),
794    /// );
795    ///
796    /// fn my_system(mut counter: ResMut<Counter>) {
797    ///     counter.0 += 1;
798    /// }
799    ///
800    /// // `Counter` hasn't been added so `my_system` can't run
801    /// app.run(&mut world);
802    /// world.init_resource::<Counter>();
803    ///
804    /// // `Counter` is `0` so `my_system` can run
805    /// app.run(&mut world);
806    /// assert_eq!(world.resource::<Counter>().0, 1);
807    ///
808    /// // `Counter` is no longer `0` so `my_system` won't run
809    /// app.run(&mut world);
810    /// assert_eq!(world.resource::<Counter>().0, 1);
811    /// ```
812    pub fn resource_exists_and_equals<T>(value: T) -> impl FnMut(Option<Res<T>>) -> bool
813    where
814        T: Resource + PartialEq,
815    {
816        move |res: Option<Res<T>>| match res {
817            Some(res) => *res == value,
818            None => false,
819        }
820    }
821
822    /// A [`SystemCondition`]-satisfying system that returns `true`
823    /// if the resource of the given type has been added since the condition was last checked.
824    ///
825    /// # Example
826    ///
827    /// ```
828    /// # use bevy_ecs::prelude::*;
829    /// # #[derive(Resource, Default)]
830    /// # struct Counter(u8);
831    /// # let mut app = Schedule::default();
832    /// # let mut world = World::new();
833    /// app.add_systems(
834    ///     // `resource_added` will only return true if the
835    ///     // given resource was just added
836    ///     my_system.run_if(resource_added::<Counter>),
837    /// );
838    ///
839    /// fn my_system(mut counter: ResMut<Counter>) {
840    ///     counter.0 += 1;
841    /// }
842    ///
843    /// world.init_resource::<Counter>();
844    ///
845    /// // `Counter` was just added so `my_system` will run
846    /// app.run(&mut world);
847    /// assert_eq!(world.resource::<Counter>().0, 1);
848    ///
849    /// // `Counter` was not just added so `my_system` will not run
850    /// app.run(&mut world);
851    /// assert_eq!(world.resource::<Counter>().0, 1);
852    /// ```
853    pub fn resource_added<T>(res: Option<Res<T>>) -> bool
854    where
855        T: Resource,
856    {
857        match res {
858            Some(res) => res.is_added(),
859            None => false,
860        }
861    }
862
863    /// A [`SystemCondition`]-satisfying system that returns `true`
864    /// if the resource of the given type has been added or mutably dereferenced
865    /// since the condition was last checked.
866    ///
867    /// **Note** that simply *mutably dereferencing* a resource is considered a change ([`DerefMut`](std::ops::DerefMut)).
868    /// Bevy does not compare resources to their previous values.
869    ///
870    /// # Panics
871    ///
872    /// The condition will panic if the resource does not exist.
873    ///
874    /// # Example
875    ///
876    /// ```
877    /// # use bevy_ecs::prelude::*;
878    /// # #[derive(Resource, Default)]
879    /// # struct Counter(u8);
880    /// # let mut app = Schedule::default();
881    /// # let mut world = World::new();
882    /// # world.init_resource::<Counter>();
883    /// app.add_systems(
884    ///     // `resource_changed` will only return true if the
885    ///     // given resource was just changed (or added)
886    ///     my_system.run_if(
887    ///         resource_changed::<Counter>
888    ///         // By default detecting changes will also trigger if the resource was
889    ///         // just added, this won't work with my example so I will add a second
890    ///         // condition to make sure the resource wasn't just added
891    ///         .and(not(resource_added::<Counter>))
892    ///     ),
893    /// );
894    ///
895    /// fn my_system(mut counter: ResMut<Counter>) {
896    ///     counter.0 += 1;
897    /// }
898    ///
899    /// // `Counter` hasn't been changed so `my_system` won't run
900    /// app.run(&mut world);
901    /// assert_eq!(world.resource::<Counter>().0, 0);
902    ///
903    /// world.resource_mut::<Counter>().0 = 50;
904    ///
905    /// // `Counter` was just changed so `my_system` will run
906    /// app.run(&mut world);
907    /// assert_eq!(world.resource::<Counter>().0, 51);
908    /// ```
909    pub fn resource_changed<T>(res: Res<T>) -> bool
910    where
911        T: Resource,
912    {
913        res.is_changed()
914    }
915
916    /// A [`SystemCondition`]-satisfying system that returns `true`
917    /// if the resource of the given type has been added or mutably dereferenced since the condition
918    /// was last checked.
919    ///
920    /// **Note** that simply *mutably dereferencing* a resource is considered a change ([`DerefMut`](std::ops::DerefMut)).
921    /// Bevy does not compare resources to their previous values.
922    ///
923    /// The condition will return `false` if the resource does not exist.
924    ///
925    /// # Example
926    ///
927    /// ```
928    /// # use bevy_ecs::prelude::*;
929    /// # #[derive(Resource, Default)]
930    /// # struct Counter(u8);
931    /// # let mut app = Schedule::default();
932    /// # let mut world = World::new();
933    /// app.add_systems(
934    ///     // `resource_exists_and_changed` will only return true if the
935    ///     // given resource exists and was just changed (or added)
936    ///     my_system.run_if(
937    ///         resource_exists_and_changed::<Counter>
938    ///         // By default detecting changes will also trigger if the resource was
939    ///         // just added, this won't work with my example so I will add a second
940    ///         // condition to make sure the resource wasn't just added
941    ///         .and(not(resource_added::<Counter>))
942    ///     ),
943    /// );
944    ///
945    /// fn my_system(mut counter: ResMut<Counter>) {
946    ///     counter.0 += 1;
947    /// }
948    ///
949    /// // `Counter` doesn't exist so `my_system` won't run
950    /// app.run(&mut world);
951    /// world.init_resource::<Counter>();
952    ///
953    /// // `Counter` hasn't been changed so `my_system` won't run
954    /// app.run(&mut world);
955    /// assert_eq!(world.resource::<Counter>().0, 0);
956    ///
957    /// world.resource_mut::<Counter>().0 = 50;
958    ///
959    /// // `Counter` was just changed so `my_system` will run
960    /// app.run(&mut world);
961    /// assert_eq!(world.resource::<Counter>().0, 51);
962    /// ```
963    pub fn resource_exists_and_changed<T>(res: Option<Res<T>>) -> bool
964    where
965        T: Resource,
966    {
967        match res {
968            Some(res) => res.is_changed(),
969            None => false,
970        }
971    }
972
973    /// A [`SystemCondition`]-satisfying system that returns `true`
974    /// if the resource of the given type has been added, removed or mutably dereferenced since the condition
975    /// was last checked.
976    ///
977    /// **Note** that simply *mutably dereferencing* a resource is considered a change ([`DerefMut`](std::ops::DerefMut)).
978    /// Bevy does not compare resources to their previous values.
979    ///
980    /// The condition will return `false` if the resource does not exist.
981    ///
982    /// # Example
983    ///
984    /// ```
985    /// # use bevy_ecs::prelude::*;
986    /// # #[derive(Resource, Default)]
987    /// # struct Counter(u8);
988    /// # let mut app = Schedule::default();
989    /// # let mut world = World::new();
990    /// # world.init_resource::<Counter>();
991    /// app.add_systems(
992    ///     // `resource_changed_or_removed` will only return true if the
993    ///     // given resource was just changed or removed (or added)
994    ///     my_system.run_if(
995    ///         resource_changed_or_removed::<Counter>
996    ///         // By default detecting changes will also trigger if the resource was
997    ///         // just added, this won't work with my example so I will add a second
998    ///         // condition to make sure the resource wasn't just added
999    ///         .and(not(resource_added::<Counter>))
1000    ///     ),
1001    /// );
1002    ///
1003    /// #[derive(Resource, Default)]
1004    /// struct MyResource;
1005    ///
1006    /// // If `Counter` exists, increment it, otherwise insert `MyResource`
1007    /// fn my_system(mut commands: Commands, mut counter: Option<ResMut<Counter>>) {
1008    ///     if let Some(mut counter) = counter {
1009    ///         counter.0 += 1;
1010    ///     } else {
1011    ///         commands.init_resource::<MyResource>();
1012    ///     }
1013    /// }
1014    ///
1015    /// // `Counter` hasn't been changed so `my_system` won't run
1016    /// app.run(&mut world);
1017    /// assert_eq!(world.resource::<Counter>().0, 0);
1018    ///
1019    /// world.resource_mut::<Counter>().0 = 50;
1020    ///
1021    /// // `Counter` was just changed so `my_system` will run
1022    /// app.run(&mut world);
1023    /// assert_eq!(world.resource::<Counter>().0, 51);
1024    ///
1025    /// world.remove_resource::<Counter>();
1026    ///
1027    /// // `Counter` was just removed so `my_system` will run
1028    /// app.run(&mut world);
1029    /// assert_eq!(world.contains_resource::<MyResource>(), true);
1030    /// ```
1031    pub fn resource_changed_or_removed<T>(res: Option<Res<T>>, mut existed: Local<bool>) -> bool
1032    where
1033        T: Resource,
1034    {
1035        if let Some(value) = res {
1036            *existed = true;
1037            value.is_changed()
1038        } else if *existed {
1039            *existed = false;
1040            true
1041        } else {
1042            false
1043        }
1044    }
1045
1046    /// A [`SystemCondition`]-satisfying system that returns `true`
1047    /// if the resource of the given type has been removed since the condition was last checked.
1048    ///
1049    /// # Example
1050    ///
1051    /// ```
1052    /// # use bevy_ecs::prelude::*;
1053    /// # #[derive(Resource, Default)]
1054    /// # struct Counter(u8);
1055    /// # let mut app = Schedule::default();
1056    /// # let mut world = World::new();
1057    /// # world.init_resource::<Counter>();
1058    /// app.add_systems(
1059    ///     // `resource_removed` will only return true if the
1060    ///     // given resource was just removed
1061    ///     my_system.run_if(resource_removed::<MyResource>),
1062    /// );
1063    ///
1064    /// #[derive(Resource, Default)]
1065    /// struct MyResource;
1066    ///
1067    /// fn my_system(mut counter: ResMut<Counter>) {
1068    ///     counter.0 += 1;
1069    /// }
1070    ///
1071    /// world.init_resource::<MyResource>();
1072    ///
1073    /// // `MyResource` hasn't just been removed so `my_system` won't run
1074    /// app.run(&mut world);
1075    /// assert_eq!(world.resource::<Counter>().0, 0);
1076    ///
1077    /// world.remove_resource::<MyResource>();
1078    ///
1079    /// // `MyResource` was just removed so `my_system` will run
1080    /// app.run(&mut world);
1081    /// assert_eq!(world.resource::<Counter>().0, 1);
1082    /// ```
1083    pub fn resource_removed<T>(res: Option<Res<T>>, mut existed: Local<bool>) -> bool
1084    where
1085        T: Resource,
1086    {
1087        if res.is_some() {
1088            *existed = true;
1089            false
1090        } else if *existed {
1091            *existed = false;
1092            true
1093        } else {
1094            false
1095        }
1096    }
1097
1098    /// A [`SystemCondition`]-satisfying system that returns `true`
1099    /// if there are any new messages of the given type since it was last called.
1100    ///
1101    /// To skip a system based on messages that it reads, use [`PopulatedMessageReader`](crate::prelude::PopulatedMessageReader) instead.
1102    ///
1103    /// # Example
1104    ///
1105    /// ```
1106    /// # use bevy_ecs::prelude::*;
1107    /// # #[derive(Resource, Default)]
1108    /// # struct Counter(u8);
1109    /// # let mut app = Schedule::default();
1110    /// # let mut world = World::new();
1111    /// # world.init_resource::<Counter>();
1112    /// # world.init_resource::<Messages<MyMessage>>();
1113    /// # app.add_systems(bevy_ecs::message::message_update_system.before(my_system));
1114    ///
1115    /// app.add_systems(
1116    ///     my_system.run_if(on_message::<MyMessage>),
1117    /// );
1118    ///
1119    /// #[derive(Message)]
1120    /// struct MyMessage;
1121    ///
1122    /// fn my_system(mut counter: ResMut<Counter>) {
1123    ///     counter.0 += 1;
1124    /// }
1125    ///
1126    /// // No new `MyMessage` messages have been pushed so `my_system` won't run
1127    /// app.run(&mut world);
1128    /// assert_eq!(world.resource::<Counter>().0, 0);
1129    ///
1130    /// world.resource_mut::<Messages<MyMessage>>().write(MyMessage);
1131    ///
1132    /// // A `MyMessage` message has been pushed so `my_system` will run
1133    /// app.run(&mut world);
1134    /// assert_eq!(world.resource::<Counter>().0, 1);
1135    /// ```
1136    pub fn on_message<M: Message>(mut reader: MessageReader<M>) -> bool {
1137        // The messages need to be consumed, so that there are no false positives on subsequent
1138        // calls of the run condition. Simply checking `is_empty` would not be enough.
1139        // PERF: note that `count` is efficient (not actually looping/iterating),
1140        // due to Bevy having a specialized implementation for messages.
1141        reader.read().count() > 0
1142    }
1143
1144    /// A [`SystemCondition`]-satisfying system that returns `true`
1145    /// if there are any entities with the given component type.
1146    ///
1147    /// This is equivalent to [`any_match_filter::<With<T>>()`]
1148    ///
1149    /// To skip a system with a [`Query`] parameter if the query is empty,
1150    /// you may instead use [`Populated`](crate::prelude::Populated), if the query may match multiple entities,
1151    /// or [`Single`](crate::prelude::Single), if it will only match one.
1152    ///
1153    /// # Example
1154    ///
1155    /// ```
1156    /// # use bevy_ecs::prelude::*;
1157    /// # #[derive(Resource, Default)]
1158    /// # struct Counter(u8);
1159    /// # let mut app = Schedule::default();
1160    /// # let mut world = World::new();
1161    /// # world.init_resource::<Counter>();
1162    /// app.add_systems(
1163    ///     my_system.run_if(any_with_component::<MyComponent>),
1164    /// );
1165    ///
1166    /// #[derive(Component)]
1167    /// struct MyComponent;
1168    ///
1169    /// fn my_system(mut counter: ResMut<Counter>) {
1170    ///     counter.0 += 1;
1171    /// }
1172    ///
1173    /// // No entities exist yet with a `MyComponent` component so `my_system` won't run
1174    /// app.run(&mut world);
1175    /// assert_eq!(world.resource::<Counter>().0, 0);
1176    ///
1177    /// world.spawn(MyComponent);
1178    ///
1179    /// // An entities with `MyComponent` now exists so `my_system` will run
1180    /// app.run(&mut world);
1181    /// assert_eq!(world.resource::<Counter>().0, 1);
1182    /// ```
1183    pub fn any_with_component<T: Component>(query: Query<(), With<T>>) -> bool {
1184        !query.is_empty()
1185    }
1186
1187    /// A [`SystemCondition`]-satisfying system that returns `true`
1188    /// if there are any entity with a component of the given type removed.
1189    pub fn any_component_removed<T: Component>(mut removals: RemovedComponents<T>) -> bool {
1190        // `RemovedComponents` based on events and therefore events need to be consumed,
1191        // so that there are no false positives on subsequent calls of the run condition.
1192        // Simply checking `is_empty` would not be enough.
1193        // PERF: note that `count` is efficient (not actually looping/iterating),
1194        // due to Bevy having a specialized implementation for events.
1195        removals.read().count() > 0
1196    }
1197
1198    /// A [`SystemCondition`]-satisfying system that returns `true`
1199    /// if there are any entities that match the given [`QueryFilter`].
1200    ///
1201    /// For a simple `With<T>` filter, this is equivalent to [`any_with_component::<T>()`].
1202    ///
1203    /// To skip a system with a [`Query`] parameter if the query is empty,
1204    /// you may instead use [`Populated`](crate::prelude::Populated), if the query may match multiple entities,
1205    /// or [`Single`](crate::prelude::Single), if it will only match one.
1206    pub fn any_match_filter<F: QueryFilter>(query: Query<(), F>) -> bool {
1207        !query.is_empty()
1208    }
1209
1210    /// Generates a [`SystemCondition`] that inverses the result of passed one.
1211    ///
1212    /// # Example
1213    ///
1214    /// ```
1215    /// # use bevy_ecs::prelude::*;
1216    /// # #[derive(Resource, Default)]
1217    /// # struct Counter(u8);
1218    /// # let mut app = Schedule::default();
1219    /// # let mut world = World::new();
1220    /// # world.init_resource::<Counter>();
1221    /// app.add_systems(
1222    ///     // `not` will inverse any condition you pass in.
1223    ///     // Since the condition we choose always returns true
1224    ///     // this system will never run
1225    ///     my_system.run_if(not(always)),
1226    /// );
1227    ///
1228    /// fn my_system(mut counter: ResMut<Counter>) {
1229    ///     counter.0 += 1;
1230    /// }
1231    ///
1232    /// fn always() -> bool {
1233    ///     true
1234    /// }
1235    ///
1236    /// app.run(&mut world);
1237    /// assert_eq!(world.resource::<Counter>().0, 0);
1238    /// ```
1239    pub fn not<Marker, TOut, T>(condition: T) -> NotSystem<T::System>
1240    where
1241        TOut: core::ops::Not,
1242        T: IntoSystem<(), TOut, Marker>,
1243    {
1244        let condition = IntoSystem::into_system(condition);
1245        let name = format!("!{}", condition.name());
1246        NotSystem::new(super::NotMarker, condition, name.into())
1247    }
1248
1249    /// Generates a [`SystemCondition`] that returns true when the passed one changes.
1250    ///
1251    /// The first time this is called, the passed condition is assumed to have been previously false.
1252    ///
1253    /// # Example
1254    ///
1255    /// ```
1256    /// # use bevy_ecs::prelude::*;
1257    /// # #[derive(Resource, Default)]
1258    /// # struct Counter(u8);
1259    /// # let mut app = Schedule::default();
1260    /// # let mut world = World::new();
1261    /// # world.init_resource::<Counter>();
1262    /// app.add_systems(
1263    ///     my_system.run_if(condition_changed(resource_exists::<MyResource>)),
1264    /// );
1265    ///
1266    /// #[derive(Resource)]
1267    /// struct MyResource;
1268    ///
1269    /// fn my_system(mut counter: ResMut<Counter>) {
1270    ///     counter.0 += 1;
1271    /// }
1272    ///
1273    /// // `MyResource` is initially there, the inner condition is true, the system runs once
1274    /// world.insert_resource(MyResource);
1275    /// app.run(&mut world);
1276    /// assert_eq!(world.resource::<Counter>().0, 1);
1277    /// app.run(&mut world);
1278    /// assert_eq!(world.resource::<Counter>().0, 1);
1279    ///
1280    /// // We remove `MyResource`, the inner condition is now false, the system runs one more time.
1281    /// world.remove_resource::<MyResource>();
1282    /// app.run(&mut world);
1283    /// assert_eq!(world.resource::<Counter>().0, 2);
1284    /// app.run(&mut world);
1285    /// assert_eq!(world.resource::<Counter>().0, 2);
1286    /// ```
1287    pub fn condition_changed<Marker, CIn, C>(condition: C) -> impl SystemCondition<(), CIn>
1288    where
1289        CIn: SystemInput,
1290        C: SystemCondition<Marker, CIn>,
1291    {
1292        IntoSystem::into_system(condition.pipe(|In(new): In<bool>, mut prev: Local<bool>| {
1293            let changed = *prev != new;
1294            *prev = new;
1295            changed
1296        }))
1297    }
1298
1299    /// Generates a [`SystemCondition`] that returns true when the result of
1300    /// the passed one went from false to true since the last time this was called.
1301    ///
1302    /// The first time this is called, the passed condition is assumed to have been previously false.
1303    ///
1304    /// # Example
1305    ///
1306    /// ```
1307    /// # use bevy_ecs::prelude::*;
1308    /// # #[derive(Resource, Default)]
1309    /// # struct Counter(u8);
1310    /// # let mut app = Schedule::default();
1311    /// # let mut world = World::new();
1312    /// # world.init_resource::<Counter>();
1313    /// app.add_systems(
1314    ///     my_system.run_if(condition_changed_to(true, resource_exists::<MyResource>)),
1315    /// );
1316    ///
1317    /// #[derive(Resource)]
1318    /// struct MyResource;
1319    ///
1320    /// fn my_system(mut counter: ResMut<Counter>) {
1321    ///     counter.0 += 1;
1322    /// }
1323    ///
1324    /// // `MyResource` is initially there, the inner condition is true, the system runs once
1325    /// world.insert_resource(MyResource);
1326    /// app.run(&mut world);
1327    /// assert_eq!(world.resource::<Counter>().0, 1);
1328    /// app.run(&mut world);
1329    /// assert_eq!(world.resource::<Counter>().0, 1);
1330    ///
1331    /// // We remove `MyResource`, the inner condition is now false, the system doesn't run.
1332    /// world.remove_resource::<MyResource>();
1333    /// app.run(&mut world);
1334    /// assert_eq!(world.resource::<Counter>().0, 1);
1335    ///
1336    /// // We reinsert `MyResource` again, so the system will run one more time
1337    /// world.insert_resource(MyResource);
1338    /// app.run(&mut world);
1339    /// assert_eq!(world.resource::<Counter>().0, 2);
1340    /// app.run(&mut world);
1341    /// assert_eq!(world.resource::<Counter>().0, 2);
1342    /// ```
1343    pub fn condition_changed_to<Marker, CIn, C>(
1344        to: bool,
1345        condition: C,
1346    ) -> impl SystemCondition<(), CIn>
1347    where
1348        CIn: SystemInput,
1349        C: SystemCondition<Marker, CIn>,
1350    {
1351        IntoSystem::into_system(condition.pipe(
1352            move |In(new): In<bool>, mut prev: Local<bool>| -> bool {
1353                let now_true = *prev != new && new == to;
1354                *prev = new;
1355                now_true
1356            },
1357        ))
1358    }
1359}
1360
1361/// Invokes [`Not`] with the output of another system.
1362///
1363/// See [`common_conditions::not`] for examples.
1364pub type NotSystem<S> = AdapterSystem<NotMarker, S>;
1365
1366/// Used with [`AdapterSystem`] to negate the output of a system via the [`Not`] operator.
1367#[doc(hidden)]
1368#[derive(Clone, Copy)]
1369pub struct NotMarker;
1370
1371impl<S: System<Out: Not>> Adapt<S> for NotMarker {
1372    type In = S::In;
1373    type Out = <S::Out as Not>::Output;
1374
1375    fn adapt(
1376        &mut self,
1377        input: <Self::In as SystemInput>::Inner<'_>,
1378        run_system: impl FnOnce(SystemIn<'_, S>) -> Result<S::Out, RunSystemError>,
1379    ) -> Result<Self::Out, RunSystemError> {
1380        run_system(input).map(Not::not)
1381    }
1382}
1383
1384/// Combines the outputs of two systems using the `&&` operator (short-circuiting).
1385pub type AndThen<A, B> = CombinatorSystem<AndThenMarker, A, B>;
1386
1387/// Combines the outputs of two systems using the `&` operator (eagerly evaluated).
1388pub type AndEager<A, B> = CombinatorSystem<AndEagerMarker, A, B>;
1389
1390/// Combines and inverts the outputs of two systems using the `&&` and `!` operators (short-circuiting).
1391pub type NandThen<A, B> = CombinatorSystem<NandThenMarker, A, B>;
1392
1393/// Combines and inverts the outputs of two systems using the `&` and `!` operators (eagerly evaluated).
1394pub type NandEager<A, B> = CombinatorSystem<NandEagerMarker, A, B>;
1395
1396/// Combines and inverts the outputs of two systems using the `||` and `!` operators (short-circuiting).
1397pub type NorElse<A, B> = CombinatorSystem<NorElseMarker, A, B>;
1398
1399/// Combines and inverts the outputs of two systems using the `|` and `!` operators (eagerly evaluated).
1400pub type NorEager<A, B> = CombinatorSystem<NorEagerMarker, A, B>;
1401
1402/// Combines the outputs of two systems using the `||` operator (short-circuiting).
1403pub type OrElse<A, B> = CombinatorSystem<OrElseMarker, A, B>;
1404
1405/// Combines the outputs of two systems using the `|` operator (short-circuiting).
1406pub type OrEager<A, B> = CombinatorSystem<OrEagerMarker, A, B>;
1407
1408/// Combines and inverts the outputs of two systems using the `^` and `!` operators (eagerly evaluated).
1409pub type Xnor<A, B> = CombinatorSystem<XnorMarker, A, B>;
1410
1411/// Combines the outputs of two systems using the `^` operator (eagerly evaluated).
1412pub type Xor<A, B> = CombinatorSystem<XorMarker, A, B>;
1413
1414#[doc(hidden)]
1415pub struct AndThenMarker;
1416
1417impl<In, A, B> Combine<A, B> for AndThenMarker
1418where
1419    for<'a> In: SystemInput<Inner<'a>: Copy>,
1420    A: System<In = In, Out = bool>,
1421    B: System<In = In, Out = bool>,
1422{
1423    type In = In;
1424    type Out = bool;
1425
1426    fn combine<T>(
1427        input: <Self::In as SystemInput>::Inner<'_>,
1428        data: &mut T,
1429        a: impl FnOnce(SystemIn<'_, A>, &mut T) -> Result<A::Out, RunSystemError>,
1430        b: impl FnOnce(SystemIn<'_, A>, &mut T) -> Result<B::Out, RunSystemError>,
1431    ) -> Result<Self::Out, RunSystemError> {
1432        Ok(a(input, data).unwrap_or(false) && b(input, data).unwrap_or(false))
1433    }
1434}
1435
1436#[doc(hidden)]
1437pub struct AndEagerMarker;
1438
1439impl<In, A, B> Combine<A, B> for AndEagerMarker
1440where
1441    for<'a> In: SystemInput<Inner<'a>: Copy>,
1442    A: System<In = In, Out = bool>,
1443    B: System<In = In, Out = bool>,
1444{
1445    type In = In;
1446    type Out = bool;
1447
1448    fn combine<T>(
1449        input: <Self::In as SystemInput>::Inner<'_>,
1450        data: &mut T,
1451        a: impl FnOnce(SystemIn<'_, A>, &mut T) -> Result<A::Out, RunSystemError>,
1452        b: impl FnOnce(SystemIn<'_, A>, &mut T) -> Result<B::Out, RunSystemError>,
1453    ) -> Result<Self::Out, RunSystemError> {
1454        Ok(a(input, data).unwrap_or(false) & b(input, data).unwrap_or(false))
1455    }
1456}
1457
1458#[doc(hidden)]
1459pub struct NandThenMarker;
1460
1461impl<In, A, B> Combine<A, B> for NandThenMarker
1462where
1463    for<'a> In: SystemInput<Inner<'a>: Copy>,
1464    A: System<In = In, Out = bool>,
1465    B: System<In = In, Out = bool>,
1466{
1467    type In = In;
1468    type Out = bool;
1469
1470    fn combine<T>(
1471        input: <Self::In as SystemInput>::Inner<'_>,
1472        data: &mut T,
1473        a: impl FnOnce(SystemIn<'_, A>, &mut T) -> Result<A::Out, RunSystemError>,
1474        b: impl FnOnce(SystemIn<'_, A>, &mut T) -> Result<B::Out, RunSystemError>,
1475    ) -> Result<Self::Out, RunSystemError> {
1476        Ok(!(a(input, data).unwrap_or(false) && b(input, data).unwrap_or(false)))
1477    }
1478}
1479
1480#[doc(hidden)]
1481pub struct NandEagerMarker;
1482
1483impl<In, A, B> Combine<A, B> for NandEagerMarker
1484where
1485    for<'a> In: SystemInput<Inner<'a>: Copy>,
1486    A: System<In = In, Out = bool>,
1487    B: System<In = In, Out = bool>,
1488{
1489    type In = In;
1490    type Out = bool;
1491
1492    fn combine<T>(
1493        input: <Self::In as SystemInput>::Inner<'_>,
1494        data: &mut T,
1495        a: impl FnOnce(SystemIn<'_, A>, &mut T) -> Result<A::Out, RunSystemError>,
1496        b: impl FnOnce(SystemIn<'_, A>, &mut T) -> Result<B::Out, RunSystemError>,
1497    ) -> Result<Self::Out, RunSystemError> {
1498        Ok(!(a(input, data).unwrap_or(false) & b(input, data).unwrap_or(false)))
1499    }
1500}
1501
1502#[doc(hidden)]
1503pub struct NorElseMarker;
1504
1505impl<In, A, B> Combine<A, B> for NorElseMarker
1506where
1507    for<'a> In: SystemInput<Inner<'a>: Copy>,
1508    A: System<In = In, Out = bool>,
1509    B: System<In = In, Out = bool>,
1510{
1511    type In = In;
1512    type Out = bool;
1513
1514    fn combine<T>(
1515        input: <Self::In as SystemInput>::Inner<'_>,
1516        data: &mut T,
1517        a: impl FnOnce(SystemIn<'_, A>, &mut T) -> Result<A::Out, RunSystemError>,
1518        b: impl FnOnce(SystemIn<'_, A>, &mut T) -> Result<B::Out, RunSystemError>,
1519    ) -> Result<Self::Out, RunSystemError> {
1520        Ok(!(a(input, data).unwrap_or(false) || b(input, data).unwrap_or(false)))
1521    }
1522}
1523
1524#[doc(hidden)]
1525pub struct NorEagerMarker;
1526
1527impl<In, A, B> Combine<A, B> for NorEagerMarker
1528where
1529    for<'a> In: SystemInput<Inner<'a>: Copy>,
1530    A: System<In = In, Out = bool>,
1531    B: System<In = In, Out = bool>,
1532{
1533    type In = In;
1534    type Out = bool;
1535
1536    fn combine<T>(
1537        input: <Self::In as SystemInput>::Inner<'_>,
1538        data: &mut T,
1539        a: impl FnOnce(SystemIn<'_, A>, &mut T) -> Result<A::Out, RunSystemError>,
1540        b: impl FnOnce(SystemIn<'_, A>, &mut T) -> Result<B::Out, RunSystemError>,
1541    ) -> Result<Self::Out, RunSystemError> {
1542        Ok(!(a(input, data).unwrap_or(false) | b(input, data).unwrap_or(false)))
1543    }
1544}
1545
1546#[doc(hidden)]
1547pub struct OrElseMarker;
1548
1549impl<In, A, B> Combine<A, B> for OrElseMarker
1550where
1551    for<'a> In: SystemInput<Inner<'a>: Copy>,
1552    A: System<In = In, Out = bool>,
1553    B: System<In = In, Out = bool>,
1554{
1555    type In = In;
1556    type Out = bool;
1557
1558    fn combine<T>(
1559        input: <Self::In as SystemInput>::Inner<'_>,
1560        data: &mut T,
1561        a: impl FnOnce(SystemIn<'_, A>, &mut T) -> Result<A::Out, RunSystemError>,
1562        b: impl FnOnce(SystemIn<'_, A>, &mut T) -> Result<B::Out, RunSystemError>,
1563    ) -> Result<Self::Out, RunSystemError> {
1564        Ok(a(input, data).unwrap_or(false) || b(input, data).unwrap_or(false))
1565    }
1566}
1567
1568#[doc(hidden)]
1569pub struct OrEagerMarker;
1570
1571impl<In, A, B> Combine<A, B> for OrEagerMarker
1572where
1573    for<'a> In: SystemInput<Inner<'a>: Copy>,
1574    A: System<In = In, Out = bool>,
1575    B: System<In = In, Out = bool>,
1576{
1577    type In = In;
1578    type Out = bool;
1579
1580    fn combine<T>(
1581        input: <Self::In as SystemInput>::Inner<'_>,
1582        data: &mut T,
1583        a: impl FnOnce(SystemIn<'_, A>, &mut T) -> Result<A::Out, RunSystemError>,
1584        b: impl FnOnce(SystemIn<'_, A>, &mut T) -> Result<B::Out, RunSystemError>,
1585    ) -> Result<Self::Out, RunSystemError> {
1586        Ok(a(input, data).unwrap_or(false) | b(input, data).unwrap_or(false))
1587    }
1588}
1589
1590#[doc(hidden)]
1591pub struct XnorMarker;
1592
1593impl<In, A, B> Combine<A, B> for XnorMarker
1594where
1595    for<'a> In: SystemInput<Inner<'a>: Copy>,
1596    A: System<In = In, Out = bool>,
1597    B: System<In = In, Out = bool>,
1598{
1599    type In = In;
1600    type Out = bool;
1601
1602    fn combine<T>(
1603        input: <Self::In as SystemInput>::Inner<'_>,
1604        data: &mut T,
1605        a: impl FnOnce(SystemIn<'_, A>, &mut T) -> Result<A::Out, RunSystemError>,
1606        b: impl FnOnce(SystemIn<'_, A>, &mut T) -> Result<B::Out, RunSystemError>,
1607    ) -> Result<Self::Out, RunSystemError> {
1608        Ok(!(a(input, data).unwrap_or(false) ^ b(input, data).unwrap_or(false)))
1609    }
1610}
1611
1612#[doc(hidden)]
1613pub struct XorMarker;
1614
1615impl<In, A, B> Combine<A, B> for XorMarker
1616where
1617    for<'a> In: SystemInput<Inner<'a>: Copy>,
1618    A: System<In = In, Out = bool>,
1619    B: System<In = In, Out = bool>,
1620{
1621    type In = In;
1622    type Out = bool;
1623
1624    fn combine<T>(
1625        input: <Self::In as SystemInput>::Inner<'_>,
1626        data: &mut T,
1627        a: impl FnOnce(SystemIn<'_, A>, &mut T) -> Result<A::Out, RunSystemError>,
1628        b: impl FnOnce(SystemIn<'_, A>, &mut T) -> Result<B::Out, RunSystemError>,
1629    ) -> Result<Self::Out, RunSystemError> {
1630        Ok(a(input, data).unwrap_or(false) ^ b(input, data).unwrap_or(false))
1631    }
1632}
1633
1634#[cfg(test)]
1635mod tests {
1636    use super::{common_conditions::*, SystemCondition};
1637    use crate::error::{BevyError, ErrorContext, FallbackErrorHandler};
1638    use crate::{
1639        change_detection::{Res, ResMut},
1640        component::Component,
1641        message::Message,
1642        query::With,
1643        schedule::{IntoScheduleConfigs, Schedule},
1644        system::{IntoSystem, Local, System},
1645        world::World,
1646    };
1647    use bevy_ecs_macros::{Resource, SystemSet};
1648
1649    #[derive(Resource, Default)]
1650    struct Counter(usize);
1651
1652    fn increment_counter(mut counter: ResMut<Counter>) {
1653        counter.0 += 1;
1654    }
1655
1656    fn double_counter(mut counter: ResMut<Counter>) {
1657        counter.0 *= 2;
1658    }
1659
1660    fn every_other_time(mut has_ran: Local<bool>) -> bool {
1661        *has_ran = !*has_ran;
1662        *has_ran
1663    }
1664
1665    #[test]
1666    fn run_condition() {
1667        let mut world = World::new();
1668        world.init_resource::<Counter>();
1669        let mut schedule = Schedule::default();
1670
1671        // Run every other cycle
1672        schedule.add_systems(increment_counter.run_if(every_other_time));
1673
1674        schedule.run(&mut world);
1675        schedule.run(&mut world);
1676        assert_eq!(world.resource::<Counter>().0, 1);
1677        schedule.run(&mut world);
1678        schedule.run(&mut world);
1679        assert_eq!(world.resource::<Counter>().0, 2);
1680
1681        // Run every other cycle opposite to the last one
1682        schedule.add_systems(increment_counter.run_if(not(every_other_time)));
1683
1684        schedule.run(&mut world);
1685        schedule.run(&mut world);
1686        assert_eq!(world.resource::<Counter>().0, 4);
1687        schedule.run(&mut world);
1688        schedule.run(&mut world);
1689        assert_eq!(world.resource::<Counter>().0, 6);
1690    }
1691
1692    #[test]
1693    fn combinators_with_maybe_failing_condition() {
1694        #![allow(
1695            clippy::nonminimal_bool,
1696            clippy::overly_complex_bool_expr,
1697            reason = "Trailing `|| false` and `&& true` are used in this test to visually remain consistent with the combinators"
1698        )]
1699
1700        use crate::system::RunSystemOnce;
1701        use alloc::sync::Arc;
1702        use std::sync::Mutex;
1703
1704        // Things that should be tested:
1705        // - the final result of the combinator is correct
1706        // - the systems that are expected to run do run
1707        // - the systems that are expected to not run do not run
1708
1709        #[derive(Component)]
1710        struct Vacant;
1711
1712        // SystemConditions don't have mutable access to the world, so we use a
1713        // `Res<AtomicCounter>` to count invocations.
1714        #[derive(Resource, Default)]
1715        struct Counter(Arc<Mutex<usize>>);
1716
1717        // The following constants are used to represent a system having run.
1718        // both are prime so that when multiplied they give a unique value for any TRUE^n*FALSE^m
1719        const FALSE: usize = 2;
1720        const TRUE: usize = 3;
1721
1722        // this is a system, but has the same side effect as `test_true`
1723        fn is_true_inc(counter: Res<Counter>) -> bool {
1724            test_true(&counter)
1725        }
1726
1727        // this is a system, but has the same side effect as `test_false`
1728        fn is_false_inc(counter: Res<Counter>) -> bool {
1729            test_false(&counter)
1730        }
1731
1732        // This condition will always yield `false`, because `Vacant` is never present.
1733        fn vacant(_: crate::system::Single<&Vacant>) -> bool {
1734            true
1735        }
1736
1737        fn test_true(counter: &Counter) -> bool {
1738            *counter.0.lock().unwrap() *= TRUE;
1739            true
1740        }
1741
1742        fn test_false(counter: &Counter) -> bool {
1743            *counter.0.lock().unwrap() *= FALSE;
1744            false
1745        }
1746
1747        // Helper function that runs a logic call and returns the result, as
1748        // well as the composite number of the calls.
1749        fn logic_call_result(f: impl FnOnce(&Counter) -> bool) -> (usize, bool) {
1750            let counter = Counter(Arc::new(Mutex::new(1)));
1751            let result = f(&counter);
1752            (*counter.0.lock().unwrap(), result)
1753        }
1754
1755        // `test_true` and `test_false` can't fail like the systems can, and so
1756        // we use them to model the short circuiting behavior of rust's logical
1757        // operators. The goal is to end up with a composite number that
1758        // describes rust's behavior and compare that to the result of the
1759        // combinators.
1760
1761        // we expect `true() || false()` to yield `true`, and short circuit
1762        // after `true()`
1763        assert_eq!(
1764            logic_call_result(|c| test_true(c) || test_false(c)),
1765            (TRUE.pow(1) * FALSE.pow(0), true)
1766        );
1767
1768        let mut world = World::new();
1769        world.init_resource::<Counter>();
1770
1771        // ensure there are no `Vacant` entities
1772        assert!(world.query::<&Vacant>().iter(&world).next().is_none());
1773        assert!(matches!(
1774            world.run_system_once((|| true).or_else(vacant)),
1775            Ok(true)
1776        ));
1777
1778        // This system should fail
1779        assert!(RunSystemOnce::run_system_once(&mut world, vacant).is_err());
1780
1781        #[track_caller]
1782        fn assert_system<Marker>(
1783            world: &mut World,
1784            system: impl IntoSystem<(), bool, Marker>,
1785            equivalent_to: impl FnOnce(&Counter) -> bool,
1786        ) {
1787            use crate::system::System;
1788
1789            *world.resource::<Counter>().0.lock().unwrap() = 1;
1790
1791            let system = IntoSystem::into_system(system);
1792            let name = system.name();
1793
1794            let out = RunSystemOnce::run_system_once(&mut *world, system).unwrap_or(false);
1795
1796            let (expected_counter, expected) = logic_call_result(equivalent_to);
1797            let caller = core::panic::Location::caller();
1798            let counter = *world.resource::<Counter>().0.lock().unwrap();
1799
1800            assert_eq!(
1801                out,
1802                expected,
1803                "At {}:{} System `{name}` yielded unexpected value `{out}`, expected `{expected}`",
1804                caller.file(),
1805                caller.line(),
1806            );
1807
1808            assert_eq!(
1809                counter, expected_counter,
1810                "At {}:{} System `{name}` did not increment counter as expected: expected `{expected_counter}`, got `{counter}`",
1811                caller.file(),
1812                caller.line(),
1813            );
1814        }
1815
1816        assert_system(&mut world, is_true_inc.or_else(vacant), |c| {
1817            test_true(c) || false
1818        });
1819        assert_system(&mut world, is_true_inc.nor_else(vacant), |c| {
1820            !(test_true(c) || false)
1821        });
1822        assert_system(&mut world, is_true_inc.xor(vacant), |c| {
1823            test_true(c) ^ false
1824        });
1825        assert_system(&mut world, is_true_inc.xnor(vacant), |c| {
1826            !(test_true(c) ^ false)
1827        });
1828        assert_system(&mut world, is_true_inc.and_then(vacant), |c| {
1829            test_true(c) && false
1830        });
1831        assert_system(&mut world, is_true_inc.nand_then(vacant), |c| {
1832            !(test_true(c) && false)
1833        });
1834
1835        // even if `vacant` fails as the first condition, where applicable (or,
1836        // xor), `is_true_inc` should still be called. `and` and `nand` short
1837        // circuit on an initial `false`.
1838        assert_system(&mut world, vacant.or_else(is_true_inc), |c| {
1839            false || test_true(c)
1840        });
1841        assert_system(&mut world, vacant.nor_else(is_true_inc), |c| {
1842            !(false || test_true(c))
1843        });
1844        assert_system(&mut world, vacant.xor(is_true_inc), |c| {
1845            false ^ test_true(c)
1846        });
1847        assert_system(&mut world, vacant.xnor(is_true_inc), |c| {
1848            !(false ^ test_true(c))
1849        });
1850        assert_system(&mut world, vacant.and_then(is_true_inc), |c| {
1851            false && test_true(c)
1852        });
1853        assert_system(&mut world, vacant.nand_then(is_true_inc), |c| {
1854            !(false && test_true(c))
1855        });
1856
1857        // the same logic ought to be the case with a condition that runs, but yields `false`:
1858        assert_system(&mut world, is_true_inc.or_else(is_false_inc), |c| {
1859            test_true(c) || test_false(c)
1860        });
1861        assert_system(&mut world, is_true_inc.nor_else(is_false_inc), |c| {
1862            !(test_true(c) || test_false(c))
1863        });
1864        assert_system(&mut world, is_true_inc.xor(is_false_inc), |c| {
1865            test_true(c) ^ test_false(c)
1866        });
1867        assert_system(&mut world, is_true_inc.xnor(is_false_inc), |c| {
1868            !(test_true(c) ^ test_false(c))
1869        });
1870        assert_system(&mut world, is_true_inc.and_then(is_false_inc), |c| {
1871            test_true(c) && test_false(c)
1872        });
1873        assert_system(&mut world, is_true_inc.nand_then(is_false_inc), |c| {
1874            !(test_true(c) && test_false(c))
1875        });
1876
1877        // and where one condition yields `false` and the other fails:
1878        assert_system(&mut world, is_false_inc.or_else(vacant), |c| {
1879            test_false(c) || false
1880        });
1881        assert_system(&mut world, is_false_inc.nor_else(vacant), |c| {
1882            !(test_false(c) || false)
1883        });
1884        assert_system(&mut world, is_false_inc.xor(vacant), |c| {
1885            test_false(c) ^ false
1886        });
1887        assert_system(&mut world, is_false_inc.xnor(vacant), |c| {
1888            !(test_false(c) ^ false)
1889        });
1890        assert_system(&mut world, is_false_inc.and_then(vacant), |c| {
1891            test_false(c) && false
1892        });
1893        assert_system(&mut world, is_false_inc.nand_then(vacant), |c| {
1894            !(test_false(c) && false)
1895        });
1896
1897        // and where both conditions yield `true`:
1898        assert_system(&mut world, is_true_inc.or_else(is_true_inc), |c| {
1899            test_true(c) || test_true(c)
1900        });
1901        assert_system(&mut world, is_true_inc.nor_else(is_true_inc), |c| {
1902            !(test_true(c) || test_true(c))
1903        });
1904        assert_system(&mut world, is_true_inc.xor(is_true_inc), |c| {
1905            test_true(c) ^ test_true(c)
1906        });
1907        assert_system(&mut world, is_true_inc.xnor(is_true_inc), |c| {
1908            !(test_true(c) ^ test_true(c))
1909        });
1910        assert_system(&mut world, is_true_inc.and_then(is_true_inc), |c| {
1911            test_true(c) && test_true(c)
1912        });
1913        assert_system(&mut world, is_true_inc.nand_then(is_true_inc), |c| {
1914            !(test_true(c) && test_true(c))
1915        });
1916
1917        // and where both conditions yield `false`:
1918        assert_system(&mut world, is_false_inc.or_else(is_false_inc), |c| {
1919            test_false(c) || test_false(c)
1920        });
1921        assert_system(&mut world, is_false_inc.nor_else(is_false_inc), |c| {
1922            !(test_false(c) || test_false(c))
1923        });
1924        assert_system(&mut world, is_false_inc.xor(is_false_inc), |c| {
1925            test_false(c) ^ test_false(c)
1926        });
1927        assert_system(&mut world, is_false_inc.xnor(is_false_inc), |c| {
1928            !(test_false(c) ^ test_false(c))
1929        });
1930        assert_system(&mut world, is_false_inc.and_then(is_false_inc), |c| {
1931            test_false(c) && test_false(c)
1932        });
1933        assert_system(&mut world, is_false_inc.nand_then(is_false_inc), |c| {
1934            !(test_false(c) && test_false(c))
1935        });
1936    }
1937
1938    #[test]
1939    fn run_condition_combinators() {
1940        let mut world = World::new();
1941        world.init_resource::<Counter>();
1942        let mut schedule = Schedule::default();
1943
1944        schedule.add_systems(
1945            (
1946                increment_counter.run_if(every_other_time.and_eager(|| true)), // Run every odd cycle.
1947                increment_counter.run_if(every_other_time.nand_eager(|| false)), // Always run.
1948                double_counter.run_if(every_other_time.nor_eager(|| false)), // Run every even cycle.
1949                increment_counter.run_if(every_other_time.or_eager(|| true)), // Always run.
1950                increment_counter.run_if(every_other_time.xnor(|| true)),    // Run every odd cycle.
1951                double_counter.run_if(every_other_time.xnor(|| false)), // Run every even cycle.
1952                increment_counter.run_if(every_other_time.xor(|| false)), // Run every odd cycle.
1953                double_counter.run_if(every_other_time.xor(|| true)),   // Run every even cycle.
1954            )
1955                .chain(),
1956        );
1957
1958        schedule.run(&mut world);
1959        assert_eq!(world.resource::<Counter>().0, 5);
1960        schedule.run(&mut world);
1961        assert_eq!(world.resource::<Counter>().0, 52);
1962    }
1963
1964    #[test]
1965    fn multiple_run_conditions() {
1966        let mut world = World::new();
1967        world.init_resource::<Counter>();
1968        let mut schedule = Schedule::default();
1969
1970        // Run every other cycle
1971        schedule.add_systems(increment_counter.run_if(every_other_time).run_if(|| true));
1972        // Never run
1973        schedule.add_systems(increment_counter.run_if(every_other_time).run_if(|| false));
1974
1975        schedule.run(&mut world);
1976        assert_eq!(world.resource::<Counter>().0, 1);
1977        schedule.run(&mut world);
1978        assert_eq!(world.resource::<Counter>().0, 1);
1979    }
1980
1981    #[test]
1982    fn multiple_run_conditions_is_and_operation() {
1983        let mut world = World::new();
1984        world.init_resource::<Counter>();
1985
1986        let mut schedule = Schedule::default();
1987
1988        // This should never run, if multiple run conditions worked
1989        // like an OR condition then it would always run
1990        schedule.add_systems(
1991            increment_counter
1992                .run_if(every_other_time)
1993                .run_if(not(every_other_time)),
1994        );
1995
1996        schedule.run(&mut world);
1997        assert_eq!(world.resource::<Counter>().0, 0);
1998        schedule.run(&mut world);
1999        assert_eq!(world.resource::<Counter>().0, 0);
2000    }
2001    #[derive(Component)]
2002    struct TestComponent;
2003
2004    #[derive(Message)]
2005    struct TestMessage;
2006
2007    #[derive(Resource)]
2008    struct TestResource(());
2009
2010    fn test_system() {}
2011
2012    // Ensure distributive_run_if compiles with the common conditions.
2013    #[test]
2014    fn distributive_run_if_compiles() {
2015        Schedule::default().add_systems(
2016            (test_system, test_system)
2017                .distributive_run_if(run_once)
2018                .distributive_run_if(resource_exists::<TestResource>)
2019                .distributive_run_if(resource_added::<TestResource>)
2020                .distributive_run_if(resource_changed::<TestResource>)
2021                .distributive_run_if(resource_exists_and_changed::<TestResource>)
2022                .distributive_run_if(resource_changed_or_removed::<TestResource>)
2023                .distributive_run_if(resource_removed::<TestResource>)
2024                .distributive_run_if(on_message::<TestMessage>)
2025                .distributive_run_if(any_with_component::<TestComponent>)
2026                .distributive_run_if(any_match_filter::<With<TestComponent>>)
2027                .distributive_run_if(not(run_once)),
2028        );
2029    }
2030
2031    #[test]
2032    fn run_if_error_contains_system() {
2033        let mut world = World::new();
2034        world.insert_resource(FallbackErrorHandler(my_error_handler));
2035
2036        #[derive(Resource)]
2037        struct MyResource;
2038
2039        fn condition(_res: Res<MyResource>) -> bool {
2040            true
2041        }
2042
2043        fn my_error_handler(_: BevyError, ctx: ErrorContext) {
2044            let a = IntoSystem::into_system(system_a);
2045            let b = IntoSystem::into_system(system_b);
2046            assert!(
2047                matches!(ctx, ErrorContext::RunCondition { system, on_set, .. } if (on_set && system == b.name()) || (!on_set && system == a.name()))
2048            );
2049        }
2050
2051        fn system_a() {}
2052        fn system_b() {}
2053
2054        let mut schedule = Schedule::default();
2055        schedule.add_systems(system_a.run_if(condition));
2056        schedule.run(&mut world);
2057
2058        #[derive(SystemSet, Debug, Hash, PartialEq, Eq, Clone)]
2059        struct Set;
2060
2061        let mut schedule = Schedule::default();
2062        schedule
2063            .add_systems((system_b,).in_set(Set))
2064            .configure_sets(Set.run_if(condition));
2065        schedule.run(&mut world);
2066    }
2067}