bevy_input_sequence/
cond_system.rs

1//! Extend [IntoSystem] for conditional execution
2use bevy::ecs::system::{CombinatorSystem, Combine, IntoSystem, System, SystemIn, SystemInput};
3use bevy::prelude::DebugName;
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, DebugName::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, DebugName::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<T>(
63        input: <Self::In as SystemInput>::Inner<'_>,
64        data: &mut T,
65        a: impl FnOnce(SystemIn<'_, A>, &mut T) -> Result<A::Out, bevy::ecs::system::RunSystemError>,
66        b: impl FnOnce(SystemIn<'_, B>, &mut T) -> Result<B::Out, bevy::ecs::system::RunSystemError>,
67    ) -> Result<Self::Out, bevy::ecs::system::RunSystemError> {
68        let condition = b((), data)?;
69        if condition {
70            Ok(Some(a(input, data)?))
71        } else {
72            Ok(None)
73        }
74    }
75}
76
77/// A one-shot conditional system comprised of consequent `SystemA` and
78/// conditional `SystemB` with no output.
79pub type SilentCondSystem<SystemA, SystemB> = CombinatorSystem<SilentCond, SystemA, SystemB>;
80
81#[doc(hidden)]
82pub struct SilentCond;
83
84impl<A, B> Combine<A, B> for SilentCond
85where
86    B: System<In = (), Out = bool>,
87    A: System,
88{
89    type In = A::In;
90    type Out = ();
91
92    fn combine<T>(
93        input: <Self::In as SystemInput>::Inner<'_>,
94        data: &mut T,
95        a: impl FnOnce(SystemIn<'_, A>, &mut T) -> Result<A::Out, bevy::ecs::system::RunSystemError>,
96        b: impl FnOnce(SystemIn<'_, B>, &mut T) -> Result<B::Out, bevy::ecs::system::RunSystemError>,
97    ) -> Result<Self::Out, bevy::ecs::system::RunSystemError> {
98        let condition = b((), data)?;
99        if condition {
100            a(input, data)?;
101        }
102        Ok(())
103    }
104}