bevy_ecs/system/
adapter_system.rs

1use alloc::vec::Vec;
2use bevy_utils::prelude::DebugName;
3
4use super::{IntoSystem, ReadOnlySystem, RunSystemError, System, SystemParamValidationError};
5use crate::{
6    schedule::InternedSystemSet,
7    system::{input::SystemInput, SystemIn},
8    world::unsafe_world_cell::UnsafeWorldCell,
9};
10
11/// Customizes the behavior of an [`AdapterSystem`]
12///
13/// # Examples
14///
15/// ```
16/// # use bevy_ecs::prelude::*;
17/// use bevy_ecs::system::{Adapt, AdapterSystem, RunSystemError};
18///
19/// // A system adapter that inverts the result of a system.
20/// // NOTE: Instead of manually implementing this, you can just use `bevy_ecs::schedule::common_conditions::not`.
21/// pub type NotSystem<S> = AdapterSystem<NotMarker, S>;
22///
23/// // This struct is used to customize the behavior of our adapter.
24/// pub struct NotMarker;
25///
26/// impl<S> Adapt<S> for NotMarker
27/// where
28///     S: System,
29///     S::Out: std::ops::Not,
30/// {
31///     type In = S::In;
32///     type Out = <S::Out as std::ops::Not>::Output;
33///
34///     fn adapt(
35///         &mut self,
36///         input: <Self::In as SystemInput>::Inner<'_>,
37///         run_system: impl FnOnce(SystemIn<'_, S>) -> Result<S::Out, RunSystemError>,
38///     ) -> Result<Self::Out, RunSystemError> {
39///         let result = run_system(input)?;
40///         Ok(!result)
41///     }
42/// }
43/// # let mut world = World::new();
44/// # let mut system = NotSystem::new(NotMarker, IntoSystem::into_system(|| false), "".into());
45/// # system.initialize(&mut world);
46/// # assert!(system.run((), &mut world).unwrap());
47/// ```
48#[diagnostic::on_unimplemented(
49    message = "`{Self}` can not adapt a system of type `{S}`",
50    label = "invalid system adapter"
51)]
52pub trait Adapt<S: System>: Send + Sync + 'static {
53    /// The [input](System::In) type for an [`AdapterSystem`].
54    type In: SystemInput;
55    /// The [output](System::Out) type for an [`AdapterSystem`].
56    type Out;
57
58    /// When used in an [`AdapterSystem`], this function customizes how the system
59    /// is run and how its inputs/outputs are adapted.
60    fn adapt(
61        &mut self,
62        input: <Self::In as SystemInput>::Inner<'_>,
63        run_system: impl FnOnce(SystemIn<'_, S>) -> Result<S::Out, RunSystemError>,
64    ) -> Result<Self::Out, RunSystemError>;
65}
66
67/// An [`IntoSystem`] creating an instance of [`AdapterSystem`].
68#[derive(Clone)]
69pub struct IntoAdapterSystem<Func, S> {
70    func: Func,
71    system: S,
72}
73
74impl<Func, S> IntoAdapterSystem<Func, S> {
75    /// Creates a new [`IntoSystem`] that uses `func` to adapt `system`, via the [`Adapt`] trait.
76    pub const fn new(func: Func, system: S) -> Self {
77        Self { func, system }
78    }
79}
80
81#[doc(hidden)]
82pub struct IsAdapterSystemMarker;
83
84impl<Func, S, I, O, M> IntoSystem<Func::In, Func::Out, (IsAdapterSystemMarker, I, O, M)>
85    for IntoAdapterSystem<Func, S>
86where
87    Func: Adapt<S::System>,
88    I: SystemInput,
89    S: IntoSystem<I, O, M>,
90{
91    type System = AdapterSystem<Func, S::System>;
92
93    // Required method
94    fn into_system(this: Self) -> Self::System {
95        let system = IntoSystem::into_system(this.system);
96        let name = system.name();
97        AdapterSystem::new(this.func, system, name)
98    }
99}
100
101/// A [`System`] that takes the output of `S` and transforms it by applying `Func` to it.
102#[derive(Clone)]
103pub struct AdapterSystem<Func, S> {
104    func: Func,
105    system: S,
106    name: DebugName,
107}
108
109impl<Func, S> AdapterSystem<Func, S>
110where
111    Func: Adapt<S>,
112    S: System,
113{
114    /// Creates a new [`System`] that uses `func` to adapt `system`, via the [`Adapt`] trait.
115    pub const fn new(func: Func, system: S, name: DebugName) -> Self {
116        Self { func, system, name }
117    }
118}
119
120impl<Func, S> System for AdapterSystem<Func, S>
121where
122    Func: Adapt<S>,
123    S: System,
124{
125    type In = Func::In;
126    type Out = Func::Out;
127
128    fn name(&self) -> DebugName {
129        self.name.clone()
130    }
131
132    #[inline]
133    fn flags(&self) -> super::SystemStateFlags {
134        self.system.flags()
135    }
136
137    #[inline]
138    unsafe fn run_unsafe(
139        &mut self,
140        input: SystemIn<'_, Self>,
141        world: UnsafeWorldCell,
142    ) -> Result<Self::Out, RunSystemError> {
143        // SAFETY: `system.run_unsafe` has the same invariants as `self.run_unsafe`.
144        self.func.adapt(input, |input| unsafe {
145            self.system.run_unsafe(input, world)
146        })
147    }
148
149    #[cfg(feature = "hotpatching")]
150    #[inline]
151    fn refresh_hotpatch(&mut self) {
152        self.system.refresh_hotpatch();
153    }
154
155    #[inline]
156    fn apply_deferred(&mut self, world: &mut crate::prelude::World) {
157        self.system.apply_deferred(world);
158    }
159
160    #[inline]
161    fn queue_deferred(&mut self, world: crate::world::DeferredWorld) {
162        self.system.queue_deferred(world);
163    }
164
165    #[inline]
166    unsafe fn validate_param_unsafe(
167        &mut self,
168        world: UnsafeWorldCell,
169    ) -> Result<(), SystemParamValidationError> {
170        // SAFETY: Delegate to other `System` implementations.
171        unsafe { self.system.validate_param_unsafe(world) }
172    }
173
174    fn initialize(&mut self, world: &mut crate::prelude::World) -> crate::query::FilteredAccessSet {
175        self.system.initialize(world)
176    }
177
178    fn check_change_tick(&mut self, check: crate::component::CheckChangeTicks) {
179        self.system.check_change_tick(check);
180    }
181
182    fn default_system_sets(&self) -> Vec<InternedSystemSet> {
183        self.system.default_system_sets()
184    }
185
186    fn get_last_run(&self) -> crate::component::Tick {
187        self.system.get_last_run()
188    }
189
190    fn set_last_run(&mut self, last_run: crate::component::Tick) {
191        self.system.set_last_run(last_run);
192    }
193}
194
195// SAFETY: The inner system is read-only.
196unsafe impl<Func, S> ReadOnlySystem for AdapterSystem<Func, S>
197where
198    Func: Adapt<S>,
199    S: ReadOnlySystem,
200{
201}
202
203impl<F, S, Out> Adapt<S> for F
204where
205    F: Send + Sync + 'static + FnMut(S::Out) -> Out,
206    S: System,
207{
208    type In = S::In;
209    type Out = Out;
210
211    fn adapt(
212        &mut self,
213        input: <Self::In as SystemInput>::Inner<'_>,
214        run_system: impl FnOnce(SystemIn<'_, S>) -> Result<S::Out, RunSystemError>,
215    ) -> Result<Self::Out, RunSystemError> {
216        run_system(input).map(self)
217    }
218}