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