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