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