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