bevy_input_sequence/
cond_system.rs

1//! Extend [IntoSystem] for conditional execution
2use bevy::ecs::system::{CombinatorSystem, Combine, IntoSystem, System, SystemIn, SystemInput};
3use std::borrow::Cow;
4
5/// Extend [IntoSystem] to allow for some conditional execution. Probably only
6/// appropriate for one-shot systems. Prefer
7/// [`run_if()`](bevy::ecs::schedule::IntoScheduleConfigs::run_if()) when directly
8/// adding to the scheduler.
9pub trait IntoCondSystem<I, O, M>: IntoSystem<I, O, M>
10where
11    I: SystemInput,
12{
13    /// Only run self's system if the given `system` parameter returns true. No
14    /// output is provided. (This is convenient for running systems with
15    /// [bevy::prelude::Commands::run_system]).
16    fn only_if<B, MarkerB>(self, system: B) -> SilentCondSystem<Self::System, B::System>
17    where
18        B: IntoSystem<(), bool, MarkerB>,
19    {
20        let system_a = IntoSystem::into_system(self);
21        let system_b = IntoSystem::into_system(system);
22        let name = format!("SilentCond({}, {})", system_a.name(), system_b.name());
23        SilentCondSystem::new(system_a, system_b, Cow::Owned(name))
24    }
25
26    /// Only run self's system if the given `system` parameter returns true. The
27    /// output is an `Option<Self::Out>`. `None` is returned when the condition
28    /// returns false.
29    fn only_if_with_output<B, MarkerB>(self, system: B) -> CondSystem<Self::System, B::System>
30    where
31        B: IntoSystem<(), bool, MarkerB>,
32    {
33        let system_a = IntoSystem::into_system(self);
34        let system_b = IntoSystem::into_system(system);
35        let name = format!("Cond({}, {})", system_a.name(), system_b.name());
36        CondSystem::new(system_a, system_b, Cow::Owned(name))
37    }
38}
39
40impl<I, O, M, T> IntoCondSystem<I, O, M> for T
41where
42    T: IntoSystem<I, O, M>,
43    I: SystemInput,
44{
45}
46
47/// A one-shot conditional system comprised of consequent `SystemA` and
48/// conditional `SystemB`.
49pub type CondSystem<SystemA, SystemB> = CombinatorSystem<Cond, SystemA, SystemB>;
50
51#[doc(hidden)]
52pub struct Cond;
53
54impl<A, B> Combine<A, B> for Cond
55where
56    B: System<In = (), Out = bool>,
57    A: System,
58{
59    type In = A::In;
60    type Out = Option<A::Out>;
61
62    fn combine(
63        input: <Self::In as SystemInput>::Inner<'_>,
64        a: impl FnOnce(SystemIn<'_, A>) -> A::Out,
65        b: impl FnOnce(SystemIn<'_, B>) -> B::Out,
66    ) -> Self::Out {
67        b(()).then(|| a(input))
68    }
69}
70
71/// A one-shot conditional system comprised of consequent `SystemA` and
72/// conditional `SystemB` with no output.
73pub type SilentCondSystem<SystemA, SystemB> = CombinatorSystem<SilentCond, SystemA, SystemB>;
74
75#[doc(hidden)]
76pub struct SilentCond;
77
78impl<A, B> Combine<A, B> for SilentCond
79where
80    B: System<In = (), Out = bool>,
81    A: System,
82{
83    type In = A::In;
84    type Out = ();
85
86    fn combine(
87        input: <Self::In as SystemInput>::Inner<'_>,
88        a: impl FnOnce(SystemIn<'_, A>) -> A::Out,
89        b: impl FnOnce(SystemIn<'_, B>) -> B::Out,
90    ) -> Self::Out {
91        if b(()) {
92            a(input);
93        }
94    }
95}