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