bevy_ecs/system/
adapter_system.rs

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