Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_ecs/src/system/adapter_system.rs
6604 views
1
use alloc::vec::Vec;
2
use bevy_utils::prelude::DebugName;
3
4
use super::{IntoSystem, ReadOnlySystem, RunSystemError, System, SystemParamValidationError};
5
use 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
)]
52
pub 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)]
69
pub struct IntoAdapterSystem<Func, S> {
70
func: Func,
71
system: S,
72
}
73
74
impl<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)]
82
pub struct IsAdapterSystemMarker;
83
84
impl<Func, S, I, O, M> IntoSystem<Func::In, Func::Out, (IsAdapterSystemMarker, I, O, M)>
85
for IntoAdapterSystem<Func, S>
86
where
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)]
103
pub struct AdapterSystem<Func, S> {
104
func: Func,
105
system: S,
106
name: DebugName,
107
}
108
109
impl<Func, S> AdapterSystem<Func, S>
110
where
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
120
impl<Func, S> System for AdapterSystem<Func, S>
121
where
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.
196
unsafe impl<Func, S> ReadOnlySystem for AdapterSystem<Func, S>
197
where
198
Func: Adapt<S>,
199
S: ReadOnlySystem,
200
{
201
}
202
203
impl<F, S, Out> Adapt<S> for F
204
where
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
}
219
220