Thanks to visit codestin.com
Credit goes to docs.rs

bevy_ecs/system/
system.rs

1#![expect(
2    clippy::module_inception,
3    reason = "This instance of module inception is being discussed; see #17353."
4)]
5use bevy_utils::prelude::DebugName;
6use bitflags::bitflags;
7use core::fmt::{Debug, Display};
8use log::warn;
9
10use crate::{
11    component::{CheckChangeTicks, Tick},
12    error::BevyError,
13    query::FilteredAccessSet,
14    schedule::InternedSystemSet,
15    system::{input::SystemInput, SystemIn},
16    world::{unsafe_world_cell::UnsafeWorldCell, DeferredWorld, World},
17};
18
19use alloc::{boxed::Box, vec::Vec};
20use core::any::{Any, TypeId};
21
22use super::{IntoSystem, SystemParamValidationError};
23
24bitflags! {
25    /// Bitflags representing system states and requirements.
26    #[derive(Clone, Copy, PartialEq, Eq, Hash)]
27    pub struct SystemStateFlags: u8 {
28        /// Set if system cannot be sent across threads
29        const NON_SEND       = 1 << 0;
30        /// Set if system requires exclusive World access
31        const EXCLUSIVE      = 1 << 1;
32        /// Set if system has deferred buffers.
33        const DEFERRED       = 1 << 2;
34    }
35}
36/// An ECS system that can be added to a [`Schedule`](crate::schedule::Schedule)
37///
38/// Systems are functions with all arguments implementing
39/// [`SystemParam`](crate::system::SystemParam).
40///
41/// Systems are added to an application using `App::add_systems(Update, my_system)`
42/// or similar methods, and will generally run once per pass of the main loop.
43///
44/// Systems are executed in parallel, in opportunistic order; data access is managed automatically.
45/// It's possible to specify explicit execution order between specific systems,
46/// see [`IntoScheduleConfigs`](crate::schedule::IntoScheduleConfigs).
47#[diagnostic::on_unimplemented(message = "`{Self}` is not a system", label = "invalid system")]
48pub trait System: Send + Sync + 'static {
49    /// The system's input.
50    type In: SystemInput;
51    /// The system's output.
52    type Out;
53
54    /// Returns the system's name.
55    fn name(&self) -> DebugName;
56    /// Returns the [`TypeId`] of the underlying system type.
57    #[inline]
58    fn type_id(&self) -> TypeId {
59        TypeId::of::<Self>()
60    }
61
62    /// Returns the [`SystemStateFlags`] of the system.
63    fn flags(&self) -> SystemStateFlags;
64
65    /// Returns true if the system is [`Send`].
66    #[inline]
67    fn is_send(&self) -> bool {
68        !self.flags().intersects(SystemStateFlags::NON_SEND)
69    }
70
71    /// Returns true if the system must be run exclusively.
72    #[inline]
73    fn is_exclusive(&self) -> bool {
74        self.flags().intersects(SystemStateFlags::EXCLUSIVE)
75    }
76
77    /// Returns true if system has deferred buffers.
78    #[inline]
79    fn has_deferred(&self) -> bool {
80        self.flags().intersects(SystemStateFlags::DEFERRED)
81    }
82
83    /// Runs the system with the given input in the world. Unlike [`System::run`], this function
84    /// can be called in parallel with other systems and may break Rust's aliasing rules
85    /// if used incorrectly, making it unsafe to call.
86    ///
87    /// Unlike [`System::run`], this will not apply deferred parameters, which must be independently
88    /// applied by calling [`System::apply_deferred`] at later point in time.
89    ///
90    /// # Safety
91    ///
92    /// - The caller must ensure that [`world`](UnsafeWorldCell) has permission to access any world data
93    ///   registered in the access returned from [`System::initialize`]. There must be no conflicting
94    ///   simultaneous accesses while the system is running.
95    /// - If [`System::is_exclusive`] returns `true`, then it must be valid to call
96    ///   [`UnsafeWorldCell::world_mut`] on `world`.
97    unsafe fn run_unsafe(
98        &mut self,
99        input: SystemIn<'_, Self>,
100        world: UnsafeWorldCell,
101    ) -> Result<Self::Out, RunSystemError>;
102
103    /// Refresh the inner pointer based on the latest hot patch jump table
104    #[cfg(feature = "hotpatching")]
105    fn refresh_hotpatch(&mut self);
106
107    /// Runs the system with the given input in the world.
108    ///
109    /// For [read-only](ReadOnlySystem) systems, see [`run_readonly`], which can be called using `&World`.
110    ///
111    /// Unlike [`System::run_unsafe`], this will apply deferred parameters *immediately*.
112    ///
113    /// [`run_readonly`]: ReadOnlySystem::run_readonly
114    fn run(
115        &mut self,
116        input: SystemIn<'_, Self>,
117        world: &mut World,
118    ) -> Result<Self::Out, RunSystemError> {
119        let ret = self.run_without_applying_deferred(input, world)?;
120        self.apply_deferred(world);
121        Ok(ret)
122    }
123
124    /// Runs the system with the given input in the world.
125    ///
126    /// [`run_readonly`]: ReadOnlySystem::run_readonly
127    fn run_without_applying_deferred(
128        &mut self,
129        input: SystemIn<'_, Self>,
130        world: &mut World,
131    ) -> Result<Self::Out, RunSystemError> {
132        let world_cell = world.as_unsafe_world_cell();
133        // SAFETY:
134        // - We have exclusive access to the entire world.
135        unsafe { self.validate_param_unsafe(world_cell) }?;
136        // SAFETY:
137        // - We have exclusive access to the entire world.
138        // - `update_archetype_component_access` has been called.
139        unsafe { self.run_unsafe(input, world_cell) }
140    }
141
142    /// Applies any [`Deferred`](crate::system::Deferred) system parameters (or other system buffers) of this system to the world.
143    ///
144    /// This is where [`Commands`](crate::system::Commands) get applied.
145    fn apply_deferred(&mut self, world: &mut World);
146
147    /// Enqueues any [`Deferred`](crate::system::Deferred) system parameters (or other system buffers)
148    /// of this system into the world's command buffer.
149    fn queue_deferred(&mut self, world: DeferredWorld);
150
151    /// Validates that all parameters can be acquired and that system can run without panic.
152    /// Built-in executors use this to prevent invalid systems from running.
153    ///
154    /// However calling and respecting [`System::validate_param_unsafe`] or its safe variant
155    /// is not a strict requirement, both [`System::run`] and [`System::run_unsafe`]
156    /// should provide their own safety mechanism to prevent undefined behavior.
157    ///
158    /// This method has to be called directly before [`System::run_unsafe`] with no other (relevant)
159    /// world mutations in between. Otherwise, while it won't lead to any undefined behavior,
160    /// the validity of the param may change.
161    ///
162    /// # Safety
163    ///
164    /// - The caller must ensure that [`world`](UnsafeWorldCell) has permission to access any world data
165    ///   registered in the access returned from [`System::initialize`]. There must be no conflicting
166    ///   simultaneous accesses while the system is running.
167    unsafe fn validate_param_unsafe(
168        &mut self,
169        world: UnsafeWorldCell,
170    ) -> Result<(), SystemParamValidationError>;
171
172    /// Safe version of [`System::validate_param_unsafe`].
173    /// that runs on exclusive, single-threaded `world` pointer.
174    fn validate_param(&mut self, world: &World) -> Result<(), SystemParamValidationError> {
175        let world_cell = world.as_unsafe_world_cell_readonly();
176        // SAFETY:
177        // - We have exclusive access to the entire world.
178        unsafe { self.validate_param_unsafe(world_cell) }
179    }
180
181    /// Initialize the system.
182    ///
183    /// Returns a [`FilteredAccessSet`] with the access required to run the system.
184    fn initialize(&mut self, _world: &mut World) -> FilteredAccessSet;
185
186    /// Checks any [`Tick`]s stored on this system and wraps their value if they get too old.
187    ///
188    /// This method must be called periodically to ensure that change detection behaves correctly.
189    /// When using bevy's default configuration, this will be called for you as needed.
190    fn check_change_tick(&mut self, check: CheckChangeTicks);
191
192    /// Returns the system's default [system sets](crate::schedule::SystemSet).
193    ///
194    /// Each system will create a default system set that contains the system.
195    fn default_system_sets(&self) -> Vec<InternedSystemSet> {
196        Vec::new()
197    }
198
199    /// Gets the tick indicating the last time this system ran.
200    fn get_last_run(&self) -> Tick;
201
202    /// Overwrites the tick indicating the last time this system ran.
203    ///
204    /// # Warning
205    /// This is a complex and error-prone operation, that can have unexpected consequences on any system relying on this code.
206    /// However, it can be an essential escape hatch when, for example,
207    /// you are trying to synchronize representations using change detection and need to avoid infinite recursion.
208    fn set_last_run(&mut self, last_run: Tick);
209}
210
211/// [`System`] types that do not modify the [`World`] when run.
212/// This is implemented for any systems whose parameters all implement [`ReadOnlySystemParam`].
213///
214/// Note that systems which perform [deferred](System::apply_deferred) mutations (such as with [`Commands`])
215/// may implement this trait.
216///
217/// [`ReadOnlySystemParam`]: crate::system::ReadOnlySystemParam
218/// [`Commands`]: crate::system::Commands
219///
220/// # Safety
221///
222/// This must only be implemented for system types which do not mutate the `World`
223/// when [`System::run_unsafe`] is called.
224#[diagnostic::on_unimplemented(
225    message = "`{Self}` is not a read-only system",
226    label = "invalid read-only system"
227)]
228pub unsafe trait ReadOnlySystem: System {
229    /// Runs this system with the given input in the world.
230    ///
231    /// Unlike [`System::run`], this can be called with a shared reference to the world,
232    /// since this system is known not to modify the world.
233    fn run_readonly(
234        &mut self,
235        input: SystemIn<'_, Self>,
236        world: &World,
237    ) -> Result<Self::Out, RunSystemError> {
238        let world = world.as_unsafe_world_cell_readonly();
239        // SAFETY:
240        // - We have read-only access to the entire world.
241        unsafe { self.validate_param_unsafe(world) }?;
242        // SAFETY:
243        // - We have read-only access to the entire world.
244        // - `update_archetype_component_access` has been called.
245        unsafe { self.run_unsafe(input, world) }
246    }
247}
248
249/// A convenience type alias for a boxed [`System`] trait object.
250pub type BoxedSystem<In = (), Out = ()> = Box<dyn System<In = In, Out = Out>>;
251
252/// A convenience type alias for a boxed [`ReadOnlySystem`] trait object.
253pub type BoxedReadOnlySystem<In = (), Out = ()> = Box<dyn ReadOnlySystem<In = In, Out = Out>>;
254
255pub(crate) fn check_system_change_tick(
256    last_run: &mut Tick,
257    check: CheckChangeTicks,
258    system_name: DebugName,
259) {
260    if last_run.check_tick(check) {
261        let age = check.present_tick().relative_to(*last_run).get();
262        warn!(
263            "System '{system_name}' has not run for {age} ticks. \
264            Changes older than {} ticks will not be detected.",
265            Tick::MAX.get() - 1,
266        );
267    }
268}
269
270impl<In, Out> Debug for dyn System<In = In, Out = Out>
271where
272    In: SystemInput + 'static,
273    Out: 'static,
274{
275    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
276        f.debug_struct("System")
277            .field("name", &self.name())
278            .field("is_exclusive", &self.is_exclusive())
279            .field("is_send", &self.is_send())
280            .finish_non_exhaustive()
281    }
282}
283
284/// Trait used to run a system immediately on a [`World`].
285///
286/// # Warning
287/// This function is not an efficient method of running systems and it's meant to be used as a utility
288/// for testing and/or diagnostics.
289///
290/// Systems called through [`run_system_once`](RunSystemOnce::run_system_once) do not hold onto any state,
291/// as they are created and destroyed every time [`run_system_once`](RunSystemOnce::run_system_once) is called.
292/// Practically, this means that [`Local`](crate::system::Local) variables are
293/// reset on every run and change detection does not work.
294///
295/// ```
296/// # use bevy_ecs::prelude::*;
297/// # use bevy_ecs::system::RunSystemOnce;
298/// #[derive(Resource, Default)]
299/// struct Counter(u8);
300///
301/// fn increment(mut counter: Local<Counter>) {
302///    counter.0 += 1;
303///    println!("{}", counter.0);
304/// }
305///
306/// let mut world = World::default();
307/// world.run_system_once(increment); // prints 1
308/// world.run_system_once(increment); // still prints 1
309/// ```
310///
311/// If you do need systems to hold onto state between runs, use [`World::run_system_cached`](World::run_system_cached)
312/// or [`World::run_system`](World::run_system).
313///
314/// # Usage
315/// Typically, to test a system, or to extract specific diagnostics information from a world,
316/// you'd need a [`Schedule`](crate::schedule::Schedule) to run the system. This can create redundant boilerplate code
317/// when writing tests or trying to quickly iterate on debug specific systems.
318///
319/// For these situations, this function can be useful because it allows you to execute a system
320/// immediately with some custom input and retrieve its output without requiring the necessary boilerplate.
321///
322/// # Examples
323///
324/// ## Immediate Command Execution
325///
326/// This usage is helpful when trying to test systems or functions that operate on [`Commands`](crate::system::Commands):
327/// ```
328/// # use bevy_ecs::prelude::*;
329/// # use bevy_ecs::system::RunSystemOnce;
330/// let mut world = World::default();
331/// let entity = world.run_system_once(|mut commands: Commands| {
332///     commands.spawn_empty().id()
333/// }).unwrap();
334/// # assert!(world.get_entity(entity).is_ok());
335/// ```
336///
337/// ## Immediate Queries
338///
339/// This usage is helpful when trying to run an arbitrary query on a world for testing or debugging purposes:
340/// ```
341/// # use bevy_ecs::prelude::*;
342/// # use bevy_ecs::system::RunSystemOnce;
343///
344/// #[derive(Component)]
345/// struct T(usize);
346///
347/// let mut world = World::default();
348/// world.spawn(T(0));
349/// world.spawn(T(1));
350/// world.spawn(T(1));
351/// let count = world.run_system_once(|query: Query<&T>| {
352///     query.iter().filter(|t| t.0 == 1).count()
353/// }).unwrap();
354///
355/// # assert_eq!(count, 2);
356/// ```
357///
358/// Note that instead of closures you can also pass in regular functions as systems:
359///
360/// ```
361/// # use bevy_ecs::prelude::*;
362/// # use bevy_ecs::system::RunSystemOnce;
363///
364/// #[derive(Component)]
365/// struct T(usize);
366///
367/// fn count(query: Query<&T>) -> usize {
368///     query.iter().filter(|t| t.0 == 1).count()
369/// }
370///
371/// let mut world = World::default();
372/// world.spawn(T(0));
373/// world.spawn(T(1));
374/// world.spawn(T(1));
375/// let count = world.run_system_once(count).unwrap();
376///
377/// # assert_eq!(count, 2);
378/// ```
379pub trait RunSystemOnce: Sized {
380    /// Tries to run a system and apply its deferred parameters.
381    fn run_system_once<T, Out, Marker>(self, system: T) -> Result<Out, RunSystemError>
382    where
383        T: IntoSystem<(), Out, Marker>,
384    {
385        self.run_system_once_with(system, ())
386    }
387
388    /// Tries to run a system with given input and apply deferred parameters.
389    fn run_system_once_with<T, In, Out, Marker>(
390        self,
391        system: T,
392        input: SystemIn<'_, T::System>,
393    ) -> Result<Out, RunSystemError>
394    where
395        T: IntoSystem<In, Out, Marker>,
396        In: SystemInput;
397}
398
399impl RunSystemOnce for &mut World {
400    fn run_system_once_with<T, In, Out, Marker>(
401        self,
402        system: T,
403        input: SystemIn<'_, T::System>,
404    ) -> Result<Out, RunSystemError>
405    where
406        T: IntoSystem<In, Out, Marker>,
407        In: SystemInput,
408    {
409        let mut system: T::System = IntoSystem::into_system(system);
410        system.initialize(self);
411        system.run(input, self)
412    }
413}
414
415/// Running system failed.
416#[derive(Debug)]
417pub enum RunSystemError {
418    /// System could not be run due to parameters that failed validation.
419    /// This is not considered an error.
420    Skipped(SystemParamValidationError),
421    /// System returned an error or failed required parameter validation.
422    Failed(BevyError),
423}
424
425impl Display for RunSystemError {
426    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
427        match self {
428            Self::Skipped(err) => write!(
429                f,
430                "System did not run due to failed parameter validation: {err}"
431            ),
432            Self::Failed(err) => write!(f, "{err}"),
433        }
434    }
435}
436
437impl<E: Any> From<E> for RunSystemError
438where
439    BevyError: From<E>,
440{
441    fn from(mut value: E) -> Self {
442        // Specialize the impl so that a skipped `SystemParamValidationError`
443        // is converted to `Skipped` instead of `Failed`.
444        // Note that the `downcast_mut` check is based on the static type,
445        // and can be optimized out after monomorphization.
446        let any: &mut dyn Any = &mut value;
447        if let Some(err) = any.downcast_mut::<SystemParamValidationError>() {
448            if err.skipped {
449                return Self::Skipped(core::mem::replace(err, SystemParamValidationError::EMPTY));
450            }
451        }
452        Self::Failed(From::from(value))
453    }
454}
455
456#[cfg(test)]
457mod tests {
458    use super::*;
459    use crate::prelude::*;
460    use alloc::string::ToString;
461
462    #[test]
463    fn run_system_once() {
464        struct T(usize);
465
466        impl Resource for T {}
467
468        fn system(In(n): In<usize>, mut commands: Commands) -> usize {
469            commands.insert_resource(T(n));
470            n + 1
471        }
472
473        let mut world = World::default();
474        let n = world.run_system_once_with(system, 1).unwrap();
475        assert_eq!(n, 2);
476        assert_eq!(world.resource::<T>().0, 1);
477    }
478
479    #[derive(Resource, Default, PartialEq, Debug)]
480    struct Counter(u8);
481
482    fn count_up(mut counter: ResMut<Counter>) {
483        counter.0 += 1;
484    }
485
486    #[test]
487    fn run_two_systems() {
488        let mut world = World::new();
489        world.init_resource::<Counter>();
490        assert_eq!(*world.resource::<Counter>(), Counter(0));
491        world.run_system_once(count_up).unwrap();
492        assert_eq!(*world.resource::<Counter>(), Counter(1));
493        world.run_system_once(count_up).unwrap();
494        assert_eq!(*world.resource::<Counter>(), Counter(2));
495    }
496
497    #[derive(Component)]
498    struct A;
499
500    fn spawn_entity(mut commands: Commands) {
501        commands.spawn(A);
502    }
503
504    #[test]
505    fn command_processing() {
506        let mut world = World::new();
507        assert_eq!(world.query::<&A>().query(&world).count(), 0);
508        world.run_system_once(spawn_entity).unwrap();
509        assert_eq!(world.query::<&A>().query(&world).count(), 1);
510    }
511
512    #[test]
513    fn non_send_resources() {
514        fn non_send_count_down(mut ns: NonSendMut<Counter>) {
515            ns.0 -= 1;
516        }
517
518        let mut world = World::new();
519        world.insert_non_send_resource(Counter(10));
520        assert_eq!(*world.non_send_resource::<Counter>(), Counter(10));
521        world.run_system_once(non_send_count_down).unwrap();
522        assert_eq!(*world.non_send_resource::<Counter>(), Counter(9));
523    }
524
525    #[test]
526    fn run_system_once_invalid_params() {
527        struct T;
528        impl Resource for T {}
529        fn system(_: Res<T>) {}
530
531        let mut world = World::default();
532        // This fails because `T` has not been added to the world yet.
533        let result = world.run_system_once(system);
534
535        assert!(matches!(result, Err(RunSystemError::Failed { .. })));
536
537        let expected = "Resource does not exist";
538        let actual = result.unwrap_err().to_string();
539
540        assert!(
541            actual.contains(expected),
542            "Expected error message to contain `{}` but got `{}`",
543            expected,
544            actual
545        );
546    }
547}