bevy_ecs/system/
adapter_system.rs

1use std::borrow::Cow;
2
3use super::{ReadOnlySystem, System};
4use crate::{schedule::InternedSystemSet, world::unsafe_world_cell::UnsafeWorldCell};
5
6/// Customizes the behavior of an [`AdapterSystem`]
7///
8/// # Examples
9///
10/// ```
11/// # use bevy_ecs::prelude::*;
12/// use bevy_ecs::system::{Adapt, AdapterSystem};
13///
14/// // A system adapter that inverts the result of a system.
15/// // NOTE: Instead of manually implementing this, you can just use `bevy_ecs::schedule::common_conditions::not`.
16/// pub type NotSystem<S> = AdapterSystem<NotMarker, S>;
17///
18/// // This struct is used to customize the behavior of our adapter.
19/// pub struct NotMarker;
20///
21/// impl<S> Adapt<S> for NotMarker
22/// where
23///     S: System,
24///     S::Out: std::ops::Not,
25/// {
26///     type In = S::In;
27///     type Out = <S::Out as std::ops::Not>::Output;
28///
29///     fn adapt(
30///         &mut self,
31///         input: Self::In,
32///         run_system: impl FnOnce(S::In) -> S::Out,
33///     ) -> Self::Out {
34///         !run_system(input)
35///     }
36/// }
37/// # let mut world = World::new();
38/// # let mut system = NotSystem::new(NotMarker, IntoSystem::into_system(|| false), "".into());
39/// # system.initialize(&mut world);
40/// # assert!(system.run((), &mut world));
41/// ```
42#[diagnostic::on_unimplemented(
43    message = "`{Self}` can not adapt a system of type `{S}`",
44    label = "invalid system adapter"
45)]
46pub trait Adapt<S: System>: Send + Sync + 'static {
47    /// The [input](System::In) type for an [`AdapterSystem`].
48    type In;
49    /// The [output](System::Out) type for an [`AdapterSystem`].
50    type Out;
51
52    /// When used in an [`AdapterSystem`], this function customizes how the system
53    /// is run and how its inputs/outputs are adapted.
54    fn adapt(&mut self, input: Self::In, run_system: impl FnOnce(S::In) -> S::Out) -> Self::Out;
55}
56
57/// A [`System`] that takes the output of `S` and transforms it by applying `Func` to it.
58#[derive(Clone)]
59pub struct AdapterSystem<Func, S> {
60    func: Func,
61    system: S,
62    name: Cow<'static, str>,
63}
64
65impl<Func, S> AdapterSystem<Func, S>
66where
67    Func: Adapt<S>,
68    S: System,
69{
70    /// Creates a new [`System`] that uses `func` to adapt `system`, via the [`Adapt`] trait.
71    pub const fn new(func: Func, system: S, name: Cow<'static, str>) -> Self {
72        Self { func, system, name }
73    }
74}
75
76impl<Func, S> System for AdapterSystem<Func, S>
77where
78    Func: Adapt<S>,
79    S: System,
80{
81    type In = Func::In;
82    type Out = Func::Out;
83
84    fn name(&self) -> Cow<'static, str> {
85        self.name.clone()
86    }
87
88    fn component_access(&self) -> &crate::query::Access<crate::component::ComponentId> {
89        self.system.component_access()
90    }
91
92    #[inline]
93    fn archetype_component_access(
94        &self,
95    ) -> &crate::query::Access<crate::archetype::ArchetypeComponentId> {
96        self.system.archetype_component_access()
97    }
98
99    fn is_send(&self) -> bool {
100        self.system.is_send()
101    }
102
103    fn is_exclusive(&self) -> bool {
104        self.system.is_exclusive()
105    }
106
107    fn has_deferred(&self) -> bool {
108        self.system.has_deferred()
109    }
110
111    #[inline]
112    unsafe fn run_unsafe(&mut self, input: Self::In, world: UnsafeWorldCell) -> Self::Out {
113        // SAFETY: `system.run_unsafe` has the same invariants as `self.run_unsafe`.
114        self.func.adapt(input, |input| unsafe {
115            self.system.run_unsafe(input, world)
116        })
117    }
118
119    #[inline]
120    fn run(&mut self, input: Self::In, world: &mut crate::prelude::World) -> Self::Out {
121        self.func
122            .adapt(input, |input| self.system.run(input, world))
123    }
124
125    #[inline]
126    fn apply_deferred(&mut self, world: &mut crate::prelude::World) {
127        self.system.apply_deferred(world);
128    }
129
130    #[inline]
131    fn queue_deferred(&mut self, world: crate::world::DeferredWorld) {
132        self.system.queue_deferred(world);
133    }
134
135    fn initialize(&mut self, world: &mut crate::prelude::World) {
136        self.system.initialize(world);
137    }
138
139    #[inline]
140    fn update_archetype_component_access(&mut self, world: UnsafeWorldCell) {
141        self.system.update_archetype_component_access(world);
142    }
143
144    fn check_change_tick(&mut self, change_tick: crate::component::Tick) {
145        self.system.check_change_tick(change_tick);
146    }
147
148    fn default_system_sets(&self) -> Vec<InternedSystemSet> {
149        self.system.default_system_sets()
150    }
151
152    fn get_last_run(&self) -> crate::component::Tick {
153        self.system.get_last_run()
154    }
155
156    fn set_last_run(&mut self, last_run: crate::component::Tick) {
157        self.system.set_last_run(last_run);
158    }
159}
160
161// SAFETY: The inner system is read-only.
162unsafe impl<Func, S> ReadOnlySystem for AdapterSystem<Func, S>
163where
164    Func: Adapt<S>,
165    S: ReadOnlySystem,
166{
167}
168
169impl<F, S, Out> Adapt<S> for F
170where
171    S: System,
172    F: Send + Sync + 'static + FnMut(S::Out) -> Out,
173{
174    type In = S::In;
175    type Out = Out;
176
177    fn adapt(&mut self, input: S::In, run_system: impl FnOnce(S::In) -> S::Out) -> Out {
178        self(run_system(input))
179    }
180}