Skip to main content

bevy_ecs/system/
function_system.rs

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