Thanks to visit codestin.com
Credit goes to docs.rs

bevy_ecs/system/
function_system.rs

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