Thanks to visit codestin.com
Credit goes to docs.rs

bevy_ecs/schedule/
condition.rs

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