bevy_ecs/schedule/
condition.rs

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