Skip to main content

bevy_ecs/system/
schedule_system.rs

1use bevy_utils::prelude::DebugName;
2
3use crate::{
4    change_detection::{CheckChangeTicks, Tick},
5    error::Result,
6    system::{input::SystemIn, BoxedSystem, RunSystemError, System, SystemAccess, SystemInput},
7    world::{unsafe_world_cell::UnsafeWorldCell, DeferredWorld, FromWorld, World},
8};
9
10use super::{IntoSystem, SystemStateFlags};
11
12/// See [`IntoSystem::with_input`] for details.
13pub struct WithInputWrapper<S, T>
14where
15    for<'i> S: System<In: SystemInput<Inner<'i> = &'i mut T>>,
16    T: Send + Sync + 'static,
17{
18    system: S,
19    value: T,
20}
21
22impl<S, T> WithInputWrapper<S, T>
23where
24    for<'i> S: System<In: SystemInput<Inner<'i> = &'i mut T>>,
25    T: Send + Sync + 'static,
26{
27    /// Wraps the given system with the given input value.
28    pub fn new<M>(system: impl IntoSystem<S::In, S::Out, M, System = S>, value: T) -> Self {
29        Self {
30            system: IntoSystem::into_system(system),
31            value,
32        }
33    }
34
35    /// Returns a reference to the input value.
36    pub fn value(&self) -> &T {
37        &self.value
38    }
39
40    /// Returns a mutable reference to the input value.
41    pub fn value_mut(&mut self) -> &mut T {
42        &mut self.value
43    }
44}
45
46impl<S, T> System for WithInputWrapper<S, T>
47where
48    for<'i> S: System<In: SystemInput<Inner<'i> = &'i mut T>>,
49    T: Send + Sync + 'static,
50{
51    type In = ();
52    type Out = S::Out;
53
54    fn name(&self) -> DebugName {
55        self.system.name()
56    }
57
58    #[inline]
59    fn flags(&self) -> SystemStateFlags {
60        self.system.flags()
61    }
62
63    unsafe fn run_unsafe(
64        &mut self,
65        _input: SystemIn<'_, Self>,
66        world: UnsafeWorldCell,
67    ) -> Result<Self::Out, RunSystemError> {
68        // SAFETY: Upheld by caller
69        unsafe { self.system.run_unsafe(&mut self.value, world) }
70    }
71
72    #[cfg(feature = "hotpatching")]
73    #[inline]
74    fn refresh_hotpatch(&mut self) {
75        self.system.refresh_hotpatch();
76    }
77
78    fn apply_deferred(&mut self, world: &mut World) {
79        self.system.apply_deferred(world);
80    }
81
82    fn queue_deferred(&mut self, world: DeferredWorld) {
83        self.system.queue_deferred(world);
84    }
85
86    fn initialize(&mut self, world: &mut World) -> SystemAccess {
87        self.system.initialize(world)
88    }
89
90    fn check_change_tick(&mut self, check: CheckChangeTicks) {
91        self.system.check_change_tick(check);
92    }
93
94    fn get_last_run(&self) -> Tick {
95        self.system.get_last_run()
96    }
97
98    fn set_last_run(&mut self, last_run: Tick) {
99        self.system.set_last_run(last_run);
100    }
101}
102
103/// Constructed in [`IntoSystem::with_input_from`].
104pub struct WithInputFromWrapper<S, T> {
105    system: S,
106    value: Option<T>,
107}
108
109impl<S, T> WithInputFromWrapper<S, T>
110where
111    for<'i> S: System<In: SystemInput<Inner<'i> = &'i mut T>>,
112    T: Send + Sync + 'static,
113{
114    /// Wraps the given system.
115    pub fn new<M>(system: impl IntoSystem<S::In, S::Out, M, System = S>) -> Self {
116        Self {
117            system: IntoSystem::into_system(system),
118            value: None,
119        }
120    }
121
122    /// Returns a reference to the input value, if it has been initialized.
123    pub fn value(&self) -> Option<&T> {
124        self.value.as_ref()
125    }
126
127    /// Returns a mutable reference to the input value, if it has been initialized.
128    pub fn value_mut(&mut self) -> Option<&mut T> {
129        self.value.as_mut()
130    }
131}
132
133impl<S, T> System for WithInputFromWrapper<S, T>
134where
135    for<'i> S: System<In: SystemInput<Inner<'i> = &'i mut T>>,
136    T: FromWorld + Send + Sync + 'static,
137{
138    type In = ();
139    type Out = S::Out;
140
141    fn name(&self) -> DebugName {
142        self.system.name()
143    }
144
145    #[inline]
146    fn flags(&self) -> SystemStateFlags {
147        self.system.flags()
148    }
149
150    unsafe fn run_unsafe(
151        &mut self,
152        _input: SystemIn<'_, Self>,
153        world: UnsafeWorldCell,
154    ) -> Result<Self::Out, RunSystemError> {
155        let value = self
156            .value
157            .as_mut()
158            .expect("System input value was not found. Did you forget to initialize the system before running it?");
159        // SAFETY: Upheld by caller
160        unsafe { self.system.run_unsafe(value, world) }
161    }
162
163    #[cfg(feature = "hotpatching")]
164    #[inline]
165    fn refresh_hotpatch(&mut self) {
166        self.system.refresh_hotpatch();
167    }
168
169    fn apply_deferred(&mut self, world: &mut World) {
170        self.system.apply_deferred(world);
171    }
172
173    fn queue_deferred(&mut self, world: DeferredWorld) {
174        self.system.queue_deferred(world);
175    }
176
177    fn initialize(&mut self, world: &mut World) -> SystemAccess {
178        if self.value.is_none() {
179            self.value = Some(T::from_world(world));
180        }
181        self.system.initialize(world)
182    }
183
184    fn check_change_tick(&mut self, check: CheckChangeTicks) {
185        self.system.check_change_tick(check);
186    }
187
188    fn get_last_run(&self) -> Tick {
189        self.system.get_last_run()
190    }
191
192    fn set_last_run(&mut self, last_run: Tick) {
193        self.system.set_last_run(last_run);
194    }
195}
196
197/// Type alias for a `BoxedSystem` that a `Schedule` can store.
198pub type ScheduleSystem = BoxedSystem<(), ()>;