bevy_ecs/system/function_system.rs
1use crate::{
2 archetype::{ArchetypeComponentId, ArchetypeGeneration},
3 component::{ComponentId, Tick},
4 prelude::FromWorld,
5 query::{Access, FilteredAccessSet},
6 schedule::{InternedSystemSet, SystemSet},
7 system::{
8 check_system_change_tick, ReadOnlySystemParam, System, SystemIn, SystemInput, SystemParam,
9 SystemParamItem,
10 },
11 world::{unsafe_world_cell::UnsafeWorldCell, DeferredWorld, World, WorldId},
12};
13
14use alloc::borrow::Cow;
15use bevy_utils::all_tuples;
16use core::marker::PhantomData;
17
18#[cfg(feature = "trace")]
19use bevy_utils::tracing::{info_span, Span};
20
21use super::{In, IntoSystem, ReadOnlySystem, SystemParamBuilder};
22
23/// The metadata of a [`System`].
24#[derive(Clone)]
25pub struct SystemMeta {
26 pub(crate) name: Cow<'static, str>,
27 /// The set of component accesses for this system. This is used to determine
28 /// - soundness issues (e.g. multiple [`SystemParam`]s mutably accessing the same component)
29 /// - ambiguities in the schedule (e.g. two systems that have some sort of conflicting access)
30 pub(crate) component_access_set: FilteredAccessSet<ComponentId>,
31 /// This [`Access`] is used to determine which systems can run in parallel with each other
32 /// in the multithreaded executor.
33 ///
34 /// We use a [`ArchetypeComponentId`] as it is more precise than just checking [`ComponentId`]:
35 /// for example if you have one system with `Query<&mut T, With<A>>` and one system with `Query<&mut T, With<B>>`
36 /// they conflict if you just look at the [`ComponentId`] of `T`; but if there are no archetypes with
37 /// both `A`, `B` and `T` then in practice there's no risk of conflict. By using [`ArchetypeComponentId`]
38 /// we can be more precise because we can check if the existing archetypes of the [`World`]
39 /// cause a conflict
40 pub(crate) archetype_component_access: Access<ArchetypeComponentId>,
41 // NOTE: this must be kept private. making a SystemMeta non-send is irreversible to prevent
42 // SystemParams from overriding each other
43 is_send: bool,
44 has_deferred: bool,
45 pub(crate) last_run: Tick,
46 param_warn_policy: ParamWarnPolicy,
47 #[cfg(feature = "trace")]
48 pub(crate) system_span: Span,
49 #[cfg(feature = "trace")]
50 pub(crate) commands_span: Span,
51}
52
53impl SystemMeta {
54 pub(crate) fn new<T>() -> Self {
55 let name = core::any::type_name::<T>();
56 Self {
57 name: name.into(),
58 archetype_component_access: Access::default(),
59 component_access_set: FilteredAccessSet::default(),
60 is_send: true,
61 has_deferred: false,
62 last_run: Tick::new(0),
63 param_warn_policy: ParamWarnPolicy::Panic,
64 #[cfg(feature = "trace")]
65 system_span: info_span!("system", name = name),
66 #[cfg(feature = "trace")]
67 commands_span: info_span!("system_commands", name = name),
68 }
69 }
70
71 /// Returns the system's name
72 #[inline]
73 pub fn name(&self) -> &str {
74 &self.name
75 }
76
77 /// Sets the name of this system.
78 ///
79 /// Useful to give closure systems more readable and unique names for debugging and tracing.
80 #[inline]
81 pub fn set_name(&mut self, new_name: impl Into<Cow<'static, str>>) {
82 let new_name: Cow<'static, str> = new_name.into();
83 #[cfg(feature = "trace")]
84 {
85 let name = new_name.as_ref();
86 self.system_span = info_span!("system", name = name);
87 self.commands_span = info_span!("system_commands", name = name);
88 }
89 self.name = new_name;
90 }
91
92 /// Returns true if the system is [`Send`].
93 #[inline]
94 pub fn is_send(&self) -> bool {
95 self.is_send
96 }
97
98 /// Sets the system to be not [`Send`].
99 ///
100 /// This is irreversible.
101 #[inline]
102 pub fn set_non_send(&mut self) {
103 self.is_send = false;
104 }
105
106 /// Returns true if the system has deferred [`SystemParam`]'s
107 #[inline]
108 pub fn has_deferred(&self) -> bool {
109 self.has_deferred
110 }
111
112 /// Marks the system as having deferred buffers like [`Commands`](`super::Commands`)
113 /// This lets the scheduler insert [`apply_deferred`](`crate::prelude::apply_deferred`) systems automatically.
114 #[inline]
115 pub fn set_has_deferred(&mut self) {
116 self.has_deferred = true;
117 }
118
119 /// Changes the warn policy.
120 #[inline]
121 pub(crate) fn set_param_warn_policy(&mut self, warn_policy: ParamWarnPolicy) {
122 self.param_warn_policy = warn_policy;
123 }
124
125 /// Advances the warn policy after validation failed.
126 #[inline]
127 pub(crate) fn advance_param_warn_policy(&mut self) {
128 self.param_warn_policy.advance();
129 }
130
131 /// Emits a warning about inaccessible system param if policy allows it.
132 #[inline]
133 pub fn try_warn_param<P>(&self)
134 where
135 P: SystemParam,
136 {
137 self.param_warn_policy.try_warn::<P>(&self.name);
138 }
139
140 /// Archetype component access that is used to determine which systems can run in parallel with each other
141 /// in the multithreaded executor.
142 ///
143 /// We use an [`ArchetypeComponentId`] as it is more precise than just checking [`ComponentId`]:
144 /// for example if you have one system with `Query<&mut A, With<B>`, and one system with `Query<&mut A, Without<B>`,
145 /// they conflict if you just look at the [`ComponentId`];
146 /// but no archetype that matches the first query will match the second and vice versa,
147 /// which means there's no risk of conflict.
148 #[inline]
149 pub fn archetype_component_access(&self) -> &Access<ArchetypeComponentId> {
150 &self.archetype_component_access
151 }
152
153 /// Returns a mutable reference to the [`Access`] for [`ArchetypeComponentId`].
154 /// This is used to determine which systems can run in parallel with each other
155 /// in the multithreaded executor.
156 ///
157 /// We use an [`ArchetypeComponentId`] as it is more precise than just checking [`ComponentId`]:
158 /// for example if you have one system with `Query<&mut A, With<B>`, and one system with `Query<&mut A, Without<B>`,
159 /// they conflict if you just look at the [`ComponentId`];
160 /// but no archetype that matches the first query will match the second and vice versa,
161 /// which means there's no risk of conflict.
162 ///
163 /// # Safety
164 ///
165 /// No access can be removed from the returned [`Access`].
166 #[inline]
167 pub unsafe fn archetype_component_access_mut(&mut self) -> &mut Access<ArchetypeComponentId> {
168 &mut self.archetype_component_access
169 }
170
171 /// Returns a reference to the [`FilteredAccessSet`] for [`ComponentId`].
172 /// Used to check if systems and/or system params have conflicting access.
173 #[inline]
174 pub fn component_access_set(&self) -> &FilteredAccessSet<ComponentId> {
175 &self.component_access_set
176 }
177
178 /// Returns a mutable reference to the [`FilteredAccessSet`] for [`ComponentId`].
179 /// Used internally to statically check if systems have conflicting access.
180 ///
181 /// # Safety
182 ///
183 /// No access can be removed from the returned [`FilteredAccessSet`].
184 #[inline]
185 pub unsafe fn component_access_set_mut(&mut self) -> &mut FilteredAccessSet<ComponentId> {
186 &mut self.component_access_set
187 }
188}
189
190/// State machine for emitting warnings when [system params are invalid](System::validate_param).
191#[derive(Clone, Copy)]
192pub enum ParamWarnPolicy {
193 /// Stop app with a panic.
194 Panic,
195 /// No warning should ever be emitted.
196 Never,
197 /// The warning will be emitted once and status will update to [`Self::Never`].
198 Once,
199}
200
201impl ParamWarnPolicy {
202 /// Advances the warn policy after validation failed.
203 #[inline]
204 fn advance(&mut self) {
205 // Ignore `Panic` case, because it stops execution before this function gets called.
206 *self = Self::Never;
207 }
208
209 /// Emits a warning about inaccessible system param if policy allows it.
210 #[inline]
211 fn try_warn<P>(&self, name: &str)
212 where
213 P: SystemParam,
214 {
215 match self {
216 Self::Panic => panic!(
217 "{0} could not access system parameter {1}",
218 name,
219 disqualified::ShortName::of::<P>()
220 ),
221 Self::Once => {
222 bevy_utils::tracing::warn!(
223 "{0} did not run because it requested inaccessible system parameter {1}",
224 name,
225 disqualified::ShortName::of::<P>()
226 );
227 }
228 Self::Never => {}
229 }
230 }
231}
232
233/// Trait for manipulating warn policy of systems.
234#[doc(hidden)]
235pub trait WithParamWarnPolicy<M, F>
236where
237 M: 'static,
238 F: SystemParamFunction<M>,
239 Self: Sized,
240{
241 /// Set warn policy.
242 fn with_param_warn_policy(self, warn_policy: ParamWarnPolicy) -> FunctionSystem<M, F>;
243
244 /// Warn only once about invalid system parameters.
245 fn param_warn_once(self) -> FunctionSystem<M, F> {
246 self.with_param_warn_policy(ParamWarnPolicy::Once)
247 }
248
249 /// Disable all param warnings.
250 fn never_param_warn(self) -> FunctionSystem<M, F> {
251 self.with_param_warn_policy(ParamWarnPolicy::Never)
252 }
253}
254
255impl<M, F> WithParamWarnPolicy<M, F> for F
256where
257 M: 'static,
258 F: SystemParamFunction<M>,
259{
260 fn with_param_warn_policy(self, param_warn_policy: ParamWarnPolicy) -> FunctionSystem<M, F> {
261 let mut system = IntoSystem::into_system(self);
262 system.system_meta.set_param_warn_policy(param_warn_policy);
263 system
264 }
265}
266
267// TODO: Actually use this in FunctionSystem. We should probably only do this once Systems are constructed using a World reference
268// (to avoid the need for unwrapping to retrieve SystemMeta)
269/// Holds on to persistent state required to drive [`SystemParam`] for a [`System`].
270///
271/// This is a powerful and convenient tool for working with exclusive world access,
272/// allowing you to fetch data from the [`World`] as if you were running a [`System`].
273/// However, simply calling `world::run_system(my_system)` using a [`World::run_system`](World::run_system)
274/// can be significantly simpler and ensures that change detection and command flushing work as expected.
275///
276/// Borrow-checking is handled for you, allowing you to mutably access multiple compatible system parameters at once,
277/// and arbitrary system parameters (like [`EventWriter`](crate::event::EventWriter)) can be conveniently fetched.
278///
279/// For an alternative approach to split mutable access to the world, see [`World::resource_scope`].
280///
281/// # Warning
282///
283/// [`SystemState`] values created can be cached to improve performance,
284/// and *must* be cached and reused in order for system parameters that rely on local state to work correctly.
285/// These include:
286/// - [`Added`](crate::query::Added) and [`Changed`](crate::query::Changed) query filters
287/// - [`Local`](crate::system::Local) variables that hold state
288/// - [`EventReader`](crate::event::EventReader) system parameters, which rely on a [`Local`](crate::system::Local) to track which events have been seen
289///
290/// Note that this is automatically handled for you when using a [`World::run_system`](World::run_system).
291///
292/// # Example
293///
294/// Basic usage:
295/// ```
296/// # use bevy_ecs::prelude::*;
297/// # use bevy_ecs::system::SystemState;
298/// # use bevy_ecs::event::Events;
299/// #
300/// # #[derive(Event)]
301/// # struct MyEvent;
302/// # #[derive(Resource)]
303/// # struct MyResource(u32);
304/// #
305/// # #[derive(Component)]
306/// # struct MyComponent;
307/// #
308/// // Work directly on the `World`
309/// let mut world = World::new();
310/// world.init_resource::<Events<MyEvent>>();
311///
312/// // Construct a `SystemState` struct, passing in a tuple of `SystemParam`
313/// // as if you were writing an ordinary system.
314/// let mut system_state: SystemState<(
315/// EventWriter<MyEvent>,
316/// Option<ResMut<MyResource>>,
317/// Query<&MyComponent>,
318/// )> = SystemState::new(&mut world);
319///
320/// // Use system_state.get_mut(&mut world) and unpack your system parameters into variables!
321/// // system_state.get(&world) provides read-only versions of your system parameters instead.
322/// let (event_writer, maybe_resource, query) = system_state.get_mut(&mut world);
323///
324/// // If you are using `Commands`, you can choose when you want to apply them to the world.
325/// // You need to manually call `.apply(world)` on the `SystemState` to apply them.
326/// ```
327/// Caching:
328/// ```
329/// # use bevy_ecs::prelude::*;
330/// # use bevy_ecs::system::SystemState;
331/// # use bevy_ecs::event::Events;
332/// #
333/// # #[derive(Event)]
334/// # struct MyEvent;
335/// #[derive(Resource)]
336/// struct CachedSystemState {
337/// event_state: SystemState<EventReader<'static, 'static, MyEvent>>,
338/// }
339///
340/// // Create and store a system state once
341/// let mut world = World::new();
342/// world.init_resource::<Events<MyEvent>>();
343/// let initial_state: SystemState<EventReader<MyEvent>> = SystemState::new(&mut world);
344///
345/// // The system state is cached in a resource
346/// world.insert_resource(CachedSystemState {
347/// event_state: initial_state,
348/// });
349///
350/// // Later, fetch the cached system state, saving on overhead
351/// world.resource_scope(|world, mut cached_state: Mut<CachedSystemState>| {
352/// let mut event_reader = cached_state.event_state.get_mut(world);
353///
354/// for events in event_reader.read() {
355/// println!("Hello World!");
356/// }
357/// });
358/// ```
359pub struct SystemState<Param: SystemParam + 'static> {
360 meta: SystemMeta,
361 param_state: Param::State,
362 world_id: WorldId,
363 archetype_generation: ArchetypeGeneration,
364}
365
366// Allow closure arguments to be inferred.
367// For a closure to be used as a `SystemParamFunction`, it needs to be generic in any `'w` or `'s` lifetimes.
368// Rust will only infer a closure to be generic over lifetimes if it's passed to a function with a Fn constraint.
369// So, generate a function for each arity with an explicit `FnMut` constraint to enable higher-order lifetimes,
370// along with a regular `SystemParamFunction` constraint to allow the system to be built.
371macro_rules! impl_build_system {
372 ($(#[$meta:meta])* $($param: ident),*) => {
373 $(#[$meta])*
374 impl<$($param: SystemParam),*> SystemState<($($param,)*)> {
375 /// Create a [`FunctionSystem`] from a [`SystemState`].
376 /// This method signature allows type inference of closure parameters for a system with no input.
377 /// You can use [`SystemState::build_system_with_input()`] if you have input, or [`SystemState::build_any_system()`] if you don't need type inference.
378 pub fn build_system<
379 Out: 'static,
380 Marker,
381 F: FnMut($(SystemParamItem<$param>),*) -> Out
382 + SystemParamFunction<Marker, Param = ($($param,)*), In = (), Out = Out>
383 >
384 (
385 self,
386 func: F,
387 ) -> FunctionSystem<Marker, F>
388 {
389 self.build_any_system(func)
390 }
391
392 /// Create a [`FunctionSystem`] from a [`SystemState`].
393 /// This method signature allows type inference of closure parameters for a system with input.
394 /// You can use [`SystemState::build_system()`] if you have no input, or [`SystemState::build_any_system()`] if you don't need type inference.
395 pub fn build_system_with_input<
396 Input: SystemInput,
397 Out: 'static,
398 Marker,
399 F: FnMut(In<Input>, $(SystemParamItem<$param>),*) -> Out
400 + SystemParamFunction<Marker, Param = ($($param,)*), In = Input, Out = Out>,
401 >(
402 self,
403 func: F,
404 ) -> FunctionSystem<Marker, F> {
405 self.build_any_system(func)
406 }
407 }
408 }
409}
410
411all_tuples!(
412 #[doc(fake_variadic)]
413 impl_build_system,
414 0,
415 16,
416 P
417);
418
419impl<Param: SystemParam> SystemState<Param> {
420 /// Creates a new [`SystemState`] with default state.
421 ///
422 /// ## Note
423 /// For users of [`SystemState::get_manual`] or [`get_manual_mut`](SystemState::get_manual_mut):
424 ///
425 /// `new` does not cache any of the world's archetypes, so you must call [`SystemState::update_archetypes`]
426 /// manually before calling `get_manual{_mut}`.
427 pub fn new(world: &mut World) -> Self {
428 let mut meta = SystemMeta::new::<Param>();
429 meta.last_run = world.change_tick().relative_to(Tick::MAX);
430 let param_state = Param::init_state(world, &mut meta);
431 Self {
432 meta,
433 param_state,
434 world_id: world.id(),
435 archetype_generation: ArchetypeGeneration::initial(),
436 }
437 }
438
439 /// Create a [`SystemState`] from a [`SystemParamBuilder`]
440 pub(crate) fn from_builder(world: &mut World, builder: impl SystemParamBuilder<Param>) -> Self {
441 let mut meta = SystemMeta::new::<Param>();
442 meta.last_run = world.change_tick().relative_to(Tick::MAX);
443 let param_state = builder.build(world, &mut meta);
444 Self {
445 meta,
446 param_state,
447 world_id: world.id(),
448 archetype_generation: ArchetypeGeneration::initial(),
449 }
450 }
451
452 /// Create a [`FunctionSystem`] from a [`SystemState`].
453 /// This method signature allows any system function, but the compiler will not perform type inference on closure parameters.
454 /// You can use [`SystemState::build_system()`] or [`SystemState::build_system_with_input()`] to get type inference on parameters.
455 pub fn build_any_system<Marker, F: SystemParamFunction<Marker, Param = Param>>(
456 self,
457 func: F,
458 ) -> FunctionSystem<Marker, F> {
459 FunctionSystem {
460 func,
461 param_state: Some(self.param_state),
462 system_meta: self.meta,
463 world_id: Some(self.world_id),
464 archetype_generation: self.archetype_generation,
465 marker: PhantomData,
466 }
467 }
468
469 /// Gets the metadata for this instance.
470 #[inline]
471 pub fn meta(&self) -> &SystemMeta {
472 &self.meta
473 }
474
475 /// Retrieve the [`SystemParam`] values. This can only be called when all parameters are read-only.
476 #[inline]
477 pub fn get<'w, 's>(&'s mut self, world: &'w World) -> SystemParamItem<'w, 's, Param>
478 where
479 Param: ReadOnlySystemParam,
480 {
481 self.validate_world(world.id());
482 self.update_archetypes(world);
483 // SAFETY: Param is read-only and doesn't allow mutable access to World.
484 // It also matches the World this SystemState was created with.
485 unsafe { self.get_unchecked_manual(world.as_unsafe_world_cell_readonly()) }
486 }
487
488 /// Retrieve the mutable [`SystemParam`] values.
489 #[inline]
490 pub fn get_mut<'w, 's>(&'s mut self, world: &'w mut World) -> SystemParamItem<'w, 's, Param> {
491 self.validate_world(world.id());
492 self.update_archetypes(world);
493 // SAFETY: World is uniquely borrowed and matches the World this SystemState was created with.
494 unsafe { self.get_unchecked_manual(world.as_unsafe_world_cell()) }
495 }
496
497 /// Applies all state queued up for [`SystemParam`] values. For example, this will apply commands queued up
498 /// by a [`Commands`](`super::Commands`) parameter to the given [`World`].
499 /// This function should be called manually after the values returned by [`SystemState::get`] and [`SystemState::get_mut`]
500 /// are finished being used.
501 pub fn apply(&mut self, world: &mut World) {
502 Param::apply(&mut self.param_state, &self.meta, world);
503 }
504
505 /// Wrapper over [`SystemParam::validate_param`].
506 ///
507 /// # Safety
508 ///
509 /// - The passed [`UnsafeWorldCell`] must have read-only access to
510 /// world data in `archetype_component_access`.
511 /// - `world` must be the same [`World`] that was used to initialize [`state`](SystemParam::init_state).
512 pub unsafe fn validate_param(state: &Self, world: UnsafeWorldCell) -> bool {
513 // SAFETY: Delegated to existing `SystemParam` implementations.
514 unsafe { Param::validate_param(&state.param_state, &state.meta, world) }
515 }
516
517 /// Returns `true` if `world_id` matches the [`World`] that was used to call [`SystemState::new`].
518 /// Otherwise, this returns false.
519 #[inline]
520 pub fn matches_world(&self, world_id: WorldId) -> bool {
521 self.world_id == world_id
522 }
523
524 /// Asserts that the [`SystemState`] matches the provided world.
525 #[inline]
526 #[track_caller]
527 fn validate_world(&self, world_id: WorldId) {
528 #[inline(never)]
529 #[track_caller]
530 #[cold]
531 fn panic_mismatched(this: WorldId, other: WorldId) -> ! {
532 panic!("Encountered a mismatched World. This SystemState was created from {this:?}, but a method was called using {other:?}.");
533 }
534
535 if !self.matches_world(world_id) {
536 panic_mismatched(self.world_id, world_id);
537 }
538 }
539
540 /// Updates the state's internal view of the [`World`]'s archetypes. If this is not called before fetching the parameters,
541 /// the results may not accurately reflect what is in the `world`.
542 ///
543 /// This is only required if [`SystemState::get_manual`] or [`SystemState::get_manual_mut`] is being called, and it only needs to
544 /// be called if the `world` has been structurally mutated (i.e. added/removed a component or resource). Users using
545 /// [`SystemState::get`] or [`SystemState::get_mut`] do not need to call this as it will be automatically called for them.
546 #[inline]
547 pub fn update_archetypes(&mut self, world: &World) {
548 self.update_archetypes_unsafe_world_cell(world.as_unsafe_world_cell_readonly());
549 }
550
551 /// Updates the state's internal view of the `world`'s archetypes. If this is not called before fetching the parameters,
552 /// the results may not accurately reflect what is in the `world`.
553 ///
554 /// This is only required if [`SystemState::get_manual`] or [`SystemState::get_manual_mut`] is being called, and it only needs to
555 /// be called if the `world` has been structurally mutated (i.e. added/removed a component or resource). Users using
556 /// [`SystemState::get`] or [`SystemState::get_mut`] do not need to call this as it will be automatically called for them.
557 ///
558 /// # Note
559 ///
560 /// This method only accesses world metadata.
561 #[inline]
562 pub fn update_archetypes_unsafe_world_cell(&mut self, world: UnsafeWorldCell) {
563 assert_eq!(self.world_id, world.id(), "Encountered a mismatched World. A System cannot be used with Worlds other than the one it was initialized with.");
564
565 let archetypes = world.archetypes();
566 let old_generation =
567 core::mem::replace(&mut self.archetype_generation, archetypes.generation());
568
569 for archetype in &archetypes[old_generation..] {
570 // SAFETY: The assertion above ensures that the param_state was initialized from `world`.
571 unsafe { Param::new_archetype(&mut self.param_state, archetype, &mut self.meta) };
572 }
573 }
574
575 /// Retrieve the [`SystemParam`] values. This can only be called when all parameters are read-only.
576 /// This will not update the state's view of the world's archetypes automatically nor increment the
577 /// world's change tick.
578 ///
579 /// For this to return accurate results, ensure [`SystemState::update_archetypes`] is called before this
580 /// function.
581 ///
582 /// Users should strongly prefer to use [`SystemState::get`] over this function.
583 #[inline]
584 pub fn get_manual<'w, 's>(&'s mut self, world: &'w World) -> SystemParamItem<'w, 's, Param>
585 where
586 Param: ReadOnlySystemParam,
587 {
588 self.validate_world(world.id());
589 let change_tick = world.read_change_tick();
590 // SAFETY: Param is read-only and doesn't allow mutable access to World.
591 // It also matches the World this SystemState was created with.
592 unsafe { self.fetch(world.as_unsafe_world_cell_readonly(), change_tick) }
593 }
594
595 /// Retrieve the mutable [`SystemParam`] values. This will not update the state's view of the world's archetypes
596 /// automatically nor increment the world's change tick.
597 ///
598 /// For this to return accurate results, ensure [`SystemState::update_archetypes`] is called before this
599 /// function.
600 ///
601 /// Users should strongly prefer to use [`SystemState::get_mut`] over this function.
602 #[inline]
603 pub fn get_manual_mut<'w, 's>(
604 &'s mut self,
605 world: &'w mut World,
606 ) -> SystemParamItem<'w, 's, Param> {
607 self.validate_world(world.id());
608 let change_tick = world.change_tick();
609 // SAFETY: World is uniquely borrowed and matches the World this SystemState was created with.
610 unsafe { self.fetch(world.as_unsafe_world_cell(), change_tick) }
611 }
612
613 /// Retrieve the [`SystemParam`] values. This will not update archetypes automatically.
614 ///
615 /// # Safety
616 /// This call might access any of the input parameters in a way that violates Rust's mutability rules. Make sure the data
617 /// access is safe in the context of global [`World`] access. The passed-in [`World`] _must_ be the [`World`] the [`SystemState`] was
618 /// created with.
619 #[inline]
620 pub unsafe fn get_unchecked_manual<'w, 's>(
621 &'s mut self,
622 world: UnsafeWorldCell<'w>,
623 ) -> SystemParamItem<'w, 's, Param> {
624 let change_tick = world.increment_change_tick();
625 // SAFETY: The invariants are uphold by the caller.
626 unsafe { self.fetch(world, change_tick) }
627 }
628
629 /// # Safety
630 /// This call might access any of the input parameters in a way that violates Rust's mutability rules. Make sure the data
631 /// access is safe in the context of global [`World`] access. The passed-in [`World`] _must_ be the [`World`] the [`SystemState`] was
632 /// created with.
633 #[inline]
634 unsafe fn fetch<'w, 's>(
635 &'s mut self,
636 world: UnsafeWorldCell<'w>,
637 change_tick: Tick,
638 ) -> SystemParamItem<'w, 's, Param> {
639 // SAFETY: The invariants are uphold by the caller.
640 let param =
641 unsafe { Param::get_param(&mut self.param_state, &self.meta, world, change_tick) };
642 self.meta.last_run = change_tick;
643 param
644 }
645}
646
647impl<Param: SystemParam> FromWorld for SystemState<Param> {
648 fn from_world(world: &mut World) -> Self {
649 Self::new(world)
650 }
651}
652
653/// The [`System`] counter part of an ordinary function.
654///
655/// You get this by calling [`IntoSystem::into_system`] on a function that only accepts
656/// [`SystemParam`]s. The output of the system becomes the functions return type, while the input
657/// becomes the functions [`In`] tagged parameter or `()` if no such parameter exists.
658///
659/// [`FunctionSystem`] must be `.initialized` before they can be run.
660///
661/// The [`Clone`] implementation for [`FunctionSystem`] returns a new instance which
662/// is NOT initialized. The cloned system must also be `.initialized` before it can be run.
663pub struct FunctionSystem<Marker, F>
664where
665 F: SystemParamFunction<Marker>,
666{
667 func: F,
668 pub(crate) param_state: Option<<F::Param as SystemParam>::State>,
669 pub(crate) system_meta: SystemMeta,
670 world_id: Option<WorldId>,
671 archetype_generation: ArchetypeGeneration,
672 // NOTE: PhantomData<fn()-> T> gives this safe Send/Sync impls
673 marker: PhantomData<fn() -> Marker>,
674}
675
676impl<Marker, F> FunctionSystem<Marker, F>
677where
678 F: SystemParamFunction<Marker>,
679{
680 /// Return this system with a new name.
681 ///
682 /// Useful to give closure systems more readable and unique names for debugging and tracing.
683 pub fn with_name(mut self, new_name: impl Into<Cow<'static, str>>) -> Self {
684 self.system_meta.set_name(new_name.into());
685 self
686 }
687}
688
689// De-initializes the cloned system.
690impl<Marker, F> Clone for FunctionSystem<Marker, F>
691where
692 F: SystemParamFunction<Marker> + Clone,
693{
694 fn clone(&self) -> Self {
695 Self {
696 func: self.func.clone(),
697 param_state: None,
698 system_meta: SystemMeta::new::<F>(),
699 world_id: None,
700 archetype_generation: ArchetypeGeneration::initial(),
701 marker: PhantomData,
702 }
703 }
704}
705
706/// A marker type used to distinguish regular function systems from exclusive function systems.
707#[doc(hidden)]
708pub struct IsFunctionSystem;
709
710impl<Marker, F> IntoSystem<F::In, F::Out, (IsFunctionSystem, Marker)> for F
711where
712 Marker: 'static,
713 F: SystemParamFunction<Marker>,
714{
715 type System = FunctionSystem<Marker, F>;
716 fn into_system(func: Self) -> Self::System {
717 FunctionSystem {
718 func,
719 param_state: None,
720 system_meta: SystemMeta::new::<F>(),
721 world_id: None,
722 archetype_generation: ArchetypeGeneration::initial(),
723 marker: PhantomData,
724 }
725 }
726}
727
728impl<Marker, F> FunctionSystem<Marker, F>
729where
730 F: SystemParamFunction<Marker>,
731{
732 /// Message shown when a system isn't initialized
733 // When lines get too long, rustfmt can sometimes refuse to format them.
734 // Work around this by storing the message separately.
735 const PARAM_MESSAGE: &'static str = "System's param_state was not found. Did you forget to initialize this system before running it?";
736}
737
738impl<Marker, F> System for FunctionSystem<Marker, F>
739where
740 Marker: 'static,
741 F: SystemParamFunction<Marker>,
742{
743 type In = F::In;
744 type Out = F::Out;
745
746 #[inline]
747 fn name(&self) -> Cow<'static, str> {
748 self.system_meta.name.clone()
749 }
750
751 #[inline]
752 fn component_access(&self) -> &Access<ComponentId> {
753 self.system_meta.component_access_set.combined_access()
754 }
755
756 #[inline]
757 fn archetype_component_access(&self) -> &Access<ArchetypeComponentId> {
758 &self.system_meta.archetype_component_access
759 }
760
761 #[inline]
762 fn is_send(&self) -> bool {
763 self.system_meta.is_send
764 }
765
766 #[inline]
767 fn is_exclusive(&self) -> bool {
768 false
769 }
770
771 #[inline]
772 fn has_deferred(&self) -> bool {
773 self.system_meta.has_deferred
774 }
775
776 #[inline]
777 unsafe fn run_unsafe(
778 &mut self,
779 input: SystemIn<'_, Self>,
780 world: UnsafeWorldCell,
781 ) -> Self::Out {
782 #[cfg(feature = "trace")]
783 let _span_guard = self.system_meta.system_span.enter();
784
785 let change_tick = world.increment_change_tick();
786
787 // SAFETY:
788 // - The caller has invoked `update_archetype_component_access`, which will panic
789 // if the world does not match.
790 // - All world accesses used by `F::Param` have been registered, so the caller
791 // will ensure that there are no data access conflicts.
792 let params = unsafe {
793 F::Param::get_param(
794 self.param_state.as_mut().expect(Self::PARAM_MESSAGE),
795 &self.system_meta,
796 world,
797 change_tick,
798 )
799 };
800 let out = self.func.run(input, params);
801 self.system_meta.last_run = change_tick;
802 out
803 }
804
805 #[inline]
806 fn apply_deferred(&mut self, world: &mut World) {
807 let param_state = self.param_state.as_mut().expect(Self::PARAM_MESSAGE);
808 F::Param::apply(param_state, &self.system_meta, world);
809 }
810
811 #[inline]
812 fn queue_deferred(&mut self, world: DeferredWorld) {
813 let param_state = self.param_state.as_mut().expect(Self::PARAM_MESSAGE);
814 F::Param::queue(param_state, &self.system_meta, world);
815 }
816
817 #[inline]
818 unsafe fn validate_param_unsafe(&mut self, world: UnsafeWorldCell) -> bool {
819 let param_state = self.param_state.as_ref().expect(Self::PARAM_MESSAGE);
820 // SAFETY:
821 // - The caller has invoked `update_archetype_component_access`, which will panic
822 // if the world does not match.
823 // - All world accesses used by `F::Param` have been registered, so the caller
824 // will ensure that there are no data access conflicts.
825 let is_valid = unsafe { F::Param::validate_param(param_state, &self.system_meta, world) };
826 if !is_valid {
827 self.system_meta.advance_param_warn_policy();
828 }
829 is_valid
830 }
831
832 #[inline]
833 fn initialize(&mut self, world: &mut World) {
834 if let Some(id) = self.world_id {
835 assert_eq!(
836 id,
837 world.id(),
838 "System built with a different world than the one it was added to.",
839 );
840 } else {
841 self.world_id = Some(world.id());
842 self.param_state = Some(F::Param::init_state(world, &mut self.system_meta));
843 }
844 self.system_meta.last_run = world.change_tick().relative_to(Tick::MAX);
845 }
846
847 fn update_archetype_component_access(&mut self, world: UnsafeWorldCell) {
848 assert_eq!(self.world_id, Some(world.id()), "Encountered a mismatched World. A System cannot be used with Worlds other than the one it was initialized with.");
849 let archetypes = world.archetypes();
850 let old_generation =
851 core::mem::replace(&mut self.archetype_generation, archetypes.generation());
852
853 for archetype in &archetypes[old_generation..] {
854 let param_state = self.param_state.as_mut().unwrap();
855 // SAFETY: The assertion above ensures that the param_state was initialized from `world`.
856 unsafe { F::Param::new_archetype(param_state, archetype, &mut self.system_meta) };
857 }
858 }
859
860 #[inline]
861 fn check_change_tick(&mut self, change_tick: Tick) {
862 check_system_change_tick(
863 &mut self.system_meta.last_run,
864 change_tick,
865 self.system_meta.name.as_ref(),
866 );
867 }
868
869 fn default_system_sets(&self) -> Vec<InternedSystemSet> {
870 let set = crate::schedule::SystemTypeSet::<Self>::new();
871 vec![set.intern()]
872 }
873
874 fn get_last_run(&self) -> Tick {
875 self.system_meta.last_run
876 }
877
878 fn set_last_run(&mut self, last_run: Tick) {
879 self.system_meta.last_run = last_run;
880 }
881}
882
883/// SAFETY: `F`'s param is [`ReadOnlySystemParam`], so this system will only read from the world.
884unsafe impl<Marker, F> ReadOnlySystem for FunctionSystem<Marker, F>
885where
886 Marker: 'static,
887 F: SystemParamFunction<Marker>,
888 F::Param: ReadOnlySystemParam,
889{
890}
891
892/// A trait implemented for all functions that can be used as [`System`]s.
893///
894/// This trait can be useful for making your own systems which accept other systems,
895/// sometimes called higher order systems.
896///
897/// This should be used in combination with [`ParamSet`] when calling other systems
898/// within your system.
899/// Using [`ParamSet`] in this case avoids [`SystemParam`] collisions.
900///
901/// # Example
902///
903/// To create something like [`PipeSystem`], but in entirely safe code.
904///
905/// ```
906/// use std::num::ParseIntError;
907///
908/// use bevy_ecs::prelude::*;
909/// use bevy_ecs::system::StaticSystemInput;
910///
911/// /// Pipe creates a new system which calls `a`, then calls `b` with the output of `a`
912/// pub fn pipe<A, B, AMarker, BMarker>(
913/// mut a: A,
914/// mut b: B,
915/// ) -> impl FnMut(StaticSystemInput<A::In>, ParamSet<(A::Param, B::Param)>) -> B::Out
916/// where
917/// // We need A and B to be systems, add those bounds
918/// A: SystemParamFunction<AMarker>,
919/// B: SystemParamFunction<BMarker>,
920/// for<'a> B::In: SystemInput<Inner<'a> = A::Out>,
921/// {
922/// // The type of `params` is inferred based on the return of this function above
923/// move |StaticSystemInput(a_in), mut params| {
924/// let shared = a.run(a_in, params.p0());
925/// b.run(shared, params.p1())
926/// }
927/// }
928///
929/// // Usage example for `pipe`:
930/// fn main() {
931/// let mut world = World::default();
932/// world.insert_resource(Message("42".to_string()));
933///
934/// // pipe the `parse_message_system`'s output into the `filter_system`s input
935/// let mut piped_system = IntoSystem::into_system(pipe(parse_message, filter));
936/// piped_system.initialize(&mut world);
937/// assert_eq!(piped_system.run((), &mut world), Some(42));
938/// }
939///
940/// #[derive(Resource)]
941/// struct Message(String);
942///
943/// fn parse_message(message: Res<Message>) -> Result<usize, ParseIntError> {
944/// message.0.parse::<usize>()
945/// }
946///
947/// fn filter(In(result): In<Result<usize, ParseIntError>>) -> Option<usize> {
948/// result.ok().filter(|&n| n < 100)
949/// }
950/// ```
951/// [`PipeSystem`]: crate::system::PipeSystem
952/// [`ParamSet`]: crate::system::ParamSet
953#[diagnostic::on_unimplemented(
954 message = "`{Self}` is not a valid system",
955 label = "invalid system"
956)]
957pub trait SystemParamFunction<Marker>: Send + Sync + 'static {
958 /// The input type of this system. See [`System::In`].
959 type In: SystemInput;
960 /// The return type of this system. See [`System::Out`].
961 type Out;
962
963 /// The [`SystemParam`]/s used by this system to access the [`World`].
964 type Param: SystemParam;
965
966 /// Executes this system once. See [`System::run`] or [`System::run_unsafe`].
967 fn run(
968 &mut self,
969 input: <Self::In as SystemInput>::Inner<'_>,
970 param_value: SystemParamItem<Self::Param>,
971 ) -> Self::Out;
972}
973
974/// A marker type used to distinguish function systems with and without input.
975#[doc(hidden)]
976pub struct HasSystemInput;
977
978macro_rules! impl_system_function {
979 ($($param: ident),*) => {
980 #[allow(non_snake_case)]
981 impl<Out, Func, $($param: SystemParam),*> SystemParamFunction<fn($($param,)*) -> Out> for Func
982 where
983 Func: Send + Sync + 'static,
984 for <'a> &'a mut Func:
985 FnMut($($param),*) -> Out +
986 FnMut($(SystemParamItem<$param>),*) -> Out,
987 Out: 'static
988 {
989 type In = ();
990 type Out = Out;
991 type Param = ($($param,)*);
992 #[inline]
993 fn run(&mut self, _input: (), param_value: SystemParamItem< ($($param,)*)>) -> Out {
994 // Yes, this is strange, but `rustc` fails to compile this impl
995 // without using this function. It fails to recognize that `func`
996 // is a function, potentially because of the multiple impls of `FnMut`
997 #[allow(clippy::too_many_arguments)]
998 fn call_inner<Out, $($param,)*>(
999 mut f: impl FnMut($($param,)*)->Out,
1000 $($param: $param,)*
1001 )->Out{
1002 f($($param,)*)
1003 }
1004 let ($($param,)*) = param_value;
1005 call_inner(self, $($param),*)
1006 }
1007 }
1008
1009 #[allow(non_snake_case)]
1010 impl<In, Out, Func, $($param: SystemParam),*> SystemParamFunction<(HasSystemInput, fn(In, $($param,)*) -> Out)> for Func
1011 where
1012 Func: Send + Sync + 'static,
1013 for <'a> &'a mut Func:
1014 FnMut(In, $($param),*) -> Out +
1015 FnMut(In::Param<'_>, $(SystemParamItem<$param>),*) -> Out,
1016 In: SystemInput + 'static,
1017 Out: 'static
1018 {
1019 type In = In;
1020 type Out = Out;
1021 type Param = ($($param,)*);
1022 #[inline]
1023 fn run(&mut self, input: In::Inner<'_>, param_value: SystemParamItem< ($($param,)*)>) -> Out {
1024 #[allow(clippy::too_many_arguments)]
1025 fn call_inner<In: SystemInput, Out, $($param,)*>(
1026 mut f: impl FnMut(In::Param<'_>, $($param,)*)->Out,
1027 input: In::Inner<'_>,
1028 $($param: $param,)*
1029 )->Out{
1030 f(In::wrap(input), $($param,)*)
1031 }
1032 let ($($param,)*) = param_value;
1033 call_inner(self, input, $($param),*)
1034 }
1035 }
1036 };
1037}
1038
1039// Note that we rely on the highest impl to be <= the highest order of the tuple impls
1040// of `SystemParam` created.
1041all_tuples!(impl_system_function, 0, 16, F);
1042
1043#[cfg(test)]
1044mod tests {
1045 use super::*;
1046
1047 #[test]
1048 fn into_system_type_id_consistency() {
1049 fn test<T, In: SystemInput, Out, Marker>(function: T)
1050 where
1051 T: IntoSystem<In, Out, Marker> + Copy,
1052 {
1053 fn reference_system() {}
1054
1055 use core::any::TypeId;
1056
1057 let system = IntoSystem::into_system(function);
1058
1059 assert_eq!(
1060 system.type_id(),
1061 function.system_type_id(),
1062 "System::type_id should be consistent with IntoSystem::system_type_id"
1063 );
1064
1065 assert_eq!(
1066 system.type_id(),
1067 TypeId::of::<T::System>(),
1068 "System::type_id should be consistent with TypeId::of::<T::System>()"
1069 );
1070
1071 assert_ne!(
1072 system.type_id(),
1073 IntoSystem::into_system(reference_system).type_id(),
1074 "Different systems should have different TypeIds"
1075 );
1076 }
1077
1078 fn function_system() {}
1079
1080 test(function_system);
1081 }
1082}