bevy_ecs/system/
function_system.rs

1use crate::{
2    archetype::{ArchetypeComponentId, ArchetypeGeneration},
3    component::{ComponentId, Tick},
4    prelude::FromWorld,
5    query::{Access, FilteredAccessSet},
6    schedule::{InternedSystemSet, SystemSet},
7    system::{check_system_change_tick, ReadOnlySystemParam, System, SystemParam, SystemParamItem},
8    world::{unsafe_world_cell::UnsafeWorldCell, DeferredWorld, World, WorldId},
9};
10
11use bevy_utils::all_tuples;
12use std::{borrow::Cow, marker::PhantomData};
13
14#[cfg(feature = "trace")]
15use bevy_utils::tracing::{info_span, Span};
16
17use super::{In, IntoSystem, ReadOnlySystem, SystemBuilder};
18
19/// The metadata of a [`System`].
20#[derive(Clone)]
21pub struct SystemMeta {
22    pub(crate) name: Cow<'static, str>,
23    pub(crate) component_access_set: FilteredAccessSet<ComponentId>,
24    pub(crate) archetype_component_access: Access<ArchetypeComponentId>,
25    // NOTE: this must be kept private. making a SystemMeta non-send is irreversible to prevent
26    // SystemParams from overriding each other
27    is_send: bool,
28    has_deferred: bool,
29    pub(crate) last_run: Tick,
30    #[cfg(feature = "trace")]
31    pub(crate) system_span: Span,
32    #[cfg(feature = "trace")]
33    pub(crate) commands_span: Span,
34}
35
36impl SystemMeta {
37    pub(crate) fn new<T>() -> Self {
38        let name = std::any::type_name::<T>();
39        Self {
40            name: name.into(),
41            archetype_component_access: Access::default(),
42            component_access_set: FilteredAccessSet::default(),
43            is_send: true,
44            has_deferred: false,
45            last_run: Tick::new(0),
46            #[cfg(feature = "trace")]
47            system_span: info_span!("system", name = name),
48            #[cfg(feature = "trace")]
49            commands_span: info_span!("system_commands", name = name),
50        }
51    }
52
53    /// Returns the system's name
54    #[inline]
55    pub fn name(&self) -> &str {
56        &self.name
57    }
58
59    /// Returns true if the system is [`Send`].
60    #[inline]
61    pub fn is_send(&self) -> bool {
62        self.is_send
63    }
64
65    /// Sets the system to be not [`Send`].
66    ///
67    /// This is irreversible.
68    #[inline]
69    pub fn set_non_send(&mut self) {
70        self.is_send = false;
71    }
72
73    /// Returns true if the system has deferred [`SystemParam`]'s
74    #[inline]
75    pub fn has_deferred(&self) -> bool {
76        self.has_deferred
77    }
78
79    /// Marks the system as having deferred buffers like [`Commands`](`super::Commands`)
80    /// This lets the scheduler insert [`apply_deferred`](`crate::prelude::apply_deferred`) systems automatically.
81    pub fn set_has_deferred(&mut self) {
82        self.has_deferred = true;
83    }
84}
85
86// TODO: Actually use this in FunctionSystem. We should probably only do this once Systems are constructed using a World reference
87// (to avoid the need for unwrapping to retrieve SystemMeta)
88/// Holds on to persistent state required to drive [`SystemParam`] for a [`System`].
89///
90/// This is a powerful and convenient tool for working with exclusive world access,
91/// allowing you to fetch data from the [`World`] as if you were running a [`System`].
92/// However, simply calling `world::run_system(my_system)` using a [`World::run_system`](World::run_system)
93/// can be significantly simpler and ensures that change detection and command flushing work as expected.
94///
95/// Borrow-checking is handled for you, allowing you to mutably access multiple compatible system parameters at once,
96/// and arbitrary system parameters (like [`EventWriter`](crate::event::EventWriter)) can be conveniently fetched.
97///
98/// For an alternative approach to split mutable access to the world, see [`World::resource_scope`].
99///
100/// # Warning
101///
102/// [`SystemState`] values created can be cached to improve performance,
103/// and *must* be cached and reused in order for system parameters that rely on local state to work correctly.
104/// These include:
105/// - [`Added`](crate::query::Added) and [`Changed`](crate::query::Changed) query filters
106/// - [`Local`](crate::system::Local) variables that hold state
107/// - [`EventReader`](crate::event::EventReader) system parameters, which rely on a [`Local`](crate::system::Local) to track which events have been seen
108///
109/// Note that this is automatically handled for you when using a [`World::run_system`](World::run_system).
110///
111/// # Example
112///
113/// Basic usage:
114/// ```
115/// # use bevy_ecs::prelude::*;
116/// # use bevy_ecs::system::SystemState;
117/// # use bevy_ecs::event::Events;
118/// #
119/// # #[derive(Event)]
120/// # struct MyEvent;
121/// # #[derive(Resource)]
122/// # struct MyResource(u32);
123/// #
124/// # #[derive(Component)]
125/// # struct MyComponent;
126/// #
127/// // Work directly on the `World`
128/// let mut world = World::new();
129/// world.init_resource::<Events<MyEvent>>();
130///
131/// // Construct a `SystemState` struct, passing in a tuple of `SystemParam`
132/// // as if you were writing an ordinary system.
133/// let mut system_state: SystemState<(
134///     EventWriter<MyEvent>,
135///     Option<ResMut<MyResource>>,
136///     Query<&MyComponent>,
137/// )> = SystemState::new(&mut world);
138///
139/// // Use system_state.get_mut(&mut world) and unpack your system parameters into variables!
140/// // system_state.get(&world) provides read-only versions of your system parameters instead.
141/// let (event_writer, maybe_resource, query) = system_state.get_mut(&mut world);
142///
143/// // If you are using `Commands`, you can choose when you want to apply them to the world.
144/// // You need to manually call `.apply(world)` on the `SystemState` to apply them.
145/// ```
146/// Caching:
147/// ```
148/// # use bevy_ecs::prelude::*;
149/// # use bevy_ecs::system::SystemState;
150/// # use bevy_ecs::event::Events;
151/// #
152/// # #[derive(Event)]
153/// # struct MyEvent;
154/// #[derive(Resource)]
155/// struct CachedSystemState {
156///     event_state: SystemState<EventReader<'static, 'static, MyEvent>>,
157/// }
158///
159/// // Create and store a system state once
160/// let mut world = World::new();
161/// world.init_resource::<Events<MyEvent>>();
162/// let initial_state: SystemState<EventReader<MyEvent>> = SystemState::new(&mut world);
163///
164/// // The system state is cached in a resource
165/// world.insert_resource(CachedSystemState {
166///     event_state: initial_state,
167/// });
168///
169/// // Later, fetch the cached system state, saving on overhead
170/// world.resource_scope(|world, mut cached_state: Mut<CachedSystemState>| {
171///     let mut event_reader = cached_state.event_state.get_mut(world);
172///
173///     for events in event_reader.read() {
174///         println!("Hello World!");
175///     }
176/// });
177/// ```
178pub struct SystemState<Param: SystemParam + 'static> {
179    meta: SystemMeta,
180    param_state: Param::State,
181    world_id: WorldId,
182    archetype_generation: ArchetypeGeneration,
183}
184
185impl<Param: SystemParam> SystemState<Param> {
186    /// Creates a new [`SystemState`] with default state.
187    ///
188    /// ## Note
189    /// For users of [`SystemState::get_manual`] or [`get_manual_mut`](SystemState::get_manual_mut):
190    ///
191    /// `new` does not cache any of the world's archetypes, so you must call [`SystemState::update_archetypes`]
192    /// manually before calling `get_manual{_mut}`.
193    pub fn new(world: &mut World) -> Self {
194        let mut meta = SystemMeta::new::<Param>();
195        meta.last_run = world.change_tick().relative_to(Tick::MAX);
196        let param_state = Param::init_state(world, &mut meta);
197        Self {
198            meta,
199            param_state,
200            world_id: world.id(),
201            archetype_generation: ArchetypeGeneration::initial(),
202        }
203    }
204
205    // Create a [`SystemState`] from a [`SystemBuilder`]
206    pub(crate) fn from_builder(builder: SystemBuilder<Param>) -> Self {
207        Self {
208            meta: builder.meta,
209            param_state: builder.state,
210            world_id: builder.world.id(),
211            archetype_generation: ArchetypeGeneration::initial(),
212        }
213    }
214
215    /// Gets the metadata for this instance.
216    #[inline]
217    pub fn meta(&self) -> &SystemMeta {
218        &self.meta
219    }
220
221    /// Retrieve the [`SystemParam`] values. This can only be called when all parameters are read-only.
222    #[inline]
223    pub fn get<'w, 's>(&'s mut self, world: &'w World) -> SystemParamItem<'w, 's, Param>
224    where
225        Param: ReadOnlySystemParam,
226    {
227        self.validate_world(world.id());
228        self.update_archetypes(world);
229        // SAFETY: Param is read-only and doesn't allow mutable access to World.
230        // It also matches the World this SystemState was created with.
231        unsafe { self.get_unchecked_manual(world.as_unsafe_world_cell_readonly()) }
232    }
233
234    /// Retrieve the mutable [`SystemParam`] values.
235    #[inline]
236    pub fn get_mut<'w, 's>(&'s mut self, world: &'w mut World) -> SystemParamItem<'w, 's, Param> {
237        self.validate_world(world.id());
238        self.update_archetypes(world);
239        // SAFETY: World is uniquely borrowed and matches the World this SystemState was created with.
240        unsafe { self.get_unchecked_manual(world.as_unsafe_world_cell()) }
241    }
242
243    /// Applies all state queued up for [`SystemParam`] values. For example, this will apply commands queued up
244    /// by a [`Commands`](`super::Commands`) parameter to the given [`World`].
245    /// This function should be called manually after the values returned by [`SystemState::get`] and [`SystemState::get_mut`]
246    /// are finished being used.
247    pub fn apply(&mut self, world: &mut World) {
248        Param::apply(&mut self.param_state, &self.meta, world);
249    }
250
251    /// Returns `true` if `world_id` matches the [`World`] that was used to call [`SystemState::new`].
252    /// Otherwise, this returns false.
253    #[inline]
254    pub fn matches_world(&self, world_id: WorldId) -> bool {
255        self.world_id == world_id
256    }
257
258    /// Asserts that the [`SystemState`] matches the provided world.
259    #[inline]
260    #[track_caller]
261    fn validate_world(&self, world_id: WorldId) {
262        #[inline(never)]
263        #[track_caller]
264        #[cold]
265        fn panic_mismatched(this: WorldId, other: WorldId) -> ! {
266            panic!("Encountered a mismatched World. This SystemState was created from {this:?}, but a method was called using {other:?}.");
267        }
268
269        if !self.matches_world(world_id) {
270            panic_mismatched(self.world_id, world_id);
271        }
272    }
273
274    /// Updates the state's internal view of the [`World`]'s archetypes. If this is not called before fetching the parameters,
275    /// the results may not accurately reflect what is in the `world`.
276    ///
277    /// This is only required if [`SystemState::get_manual`] or [`SystemState::get_manual_mut`] is being called, and it only needs to
278    /// be called if the `world` has been structurally mutated (i.e. added/removed a component or resource). Users using
279    /// [`SystemState::get`] or [`SystemState::get_mut`] do not need to call this as it will be automatically called for them.
280    #[inline]
281    pub fn update_archetypes(&mut self, world: &World) {
282        self.update_archetypes_unsafe_world_cell(world.as_unsafe_world_cell_readonly());
283    }
284
285    /// Updates the state's internal view of the `world`'s archetypes. If this is not called before fetching the parameters,
286    /// the results may not accurately reflect what is in the `world`.
287    ///
288    /// This is only required if [`SystemState::get_manual`] or [`SystemState::get_manual_mut`] is being called, and it only needs to
289    /// be called if the `world` has been structurally mutated (i.e. added/removed a component or resource). Users using
290    /// [`SystemState::get`] or [`SystemState::get_mut`] do not need to call this as it will be automatically called for them.
291    ///
292    /// # Note
293    ///
294    /// This method only accesses world metadata.
295    #[inline]
296    pub fn update_archetypes_unsafe_world_cell(&mut self, world: UnsafeWorldCell) {
297        assert_eq!(self.world_id, world.id(), "Encountered a mismatched World. A System cannot be used with Worlds other than the one it was initialized with.");
298
299        let archetypes = world.archetypes();
300        let old_generation =
301            std::mem::replace(&mut self.archetype_generation, archetypes.generation());
302
303        for archetype in &archetypes[old_generation..] {
304            // SAFETY: The assertion above ensures that the param_state was initialized from `world`.
305            unsafe { Param::new_archetype(&mut self.param_state, archetype, &mut self.meta) };
306        }
307    }
308
309    /// Retrieve the [`SystemParam`] values. This can only be called when all parameters are read-only.
310    /// This will not update the state's view of the world's archetypes automatically nor increment the
311    /// world's change tick.
312    ///
313    /// For this to return accurate results, ensure [`SystemState::update_archetypes`] is called before this
314    /// function.
315    ///
316    /// Users should strongly prefer to use [`SystemState::get`] over this function.
317    #[inline]
318    pub fn get_manual<'w, 's>(&'s mut self, world: &'w World) -> SystemParamItem<'w, 's, Param>
319    where
320        Param: ReadOnlySystemParam,
321    {
322        self.validate_world(world.id());
323        let change_tick = world.read_change_tick();
324        // SAFETY: Param is read-only and doesn't allow mutable access to World.
325        // It also matches the World this SystemState was created with.
326        unsafe { self.fetch(world.as_unsafe_world_cell_readonly(), change_tick) }
327    }
328
329    /// Retrieve the mutable [`SystemParam`] values.  This will not update the state's view of the world's archetypes
330    /// automatically nor increment the world's change tick.
331    ///
332    /// For this to return accurate results, ensure [`SystemState::update_archetypes`] is called before this
333    /// function.
334    ///
335    /// Users should strongly prefer to use [`SystemState::get_mut`] over this function.
336    #[inline]
337    pub fn get_manual_mut<'w, 's>(
338        &'s mut self,
339        world: &'w mut World,
340    ) -> SystemParamItem<'w, 's, Param> {
341        self.validate_world(world.id());
342        let change_tick = world.change_tick();
343        // SAFETY: World is uniquely borrowed and matches the World this SystemState was created with.
344        unsafe { self.fetch(world.as_unsafe_world_cell(), change_tick) }
345    }
346
347    /// Retrieve the [`SystemParam`] values. This will not update archetypes automatically.
348    ///
349    /// # Safety
350    /// This call might access any of the input parameters in a way that violates Rust's mutability rules. Make sure the data
351    /// access is safe in the context of global [`World`] access. The passed-in [`World`] _must_ be the [`World`] the [`SystemState`] was
352    /// created with.
353    #[inline]
354    pub unsafe fn get_unchecked_manual<'w, 's>(
355        &'s mut self,
356        world: UnsafeWorldCell<'w>,
357    ) -> SystemParamItem<'w, 's, Param> {
358        let change_tick = world.increment_change_tick();
359        // SAFETY: The invariants are uphold by the caller.
360        unsafe { self.fetch(world, change_tick) }
361    }
362
363    /// # Safety
364    /// This call might access any of the input parameters in a way that violates Rust's mutability rules. Make sure the data
365    /// access is safe in the context of global [`World`] access. The passed-in [`World`] _must_ be the [`World`] the [`SystemState`] was
366    /// created with.
367    #[inline]
368    unsafe fn fetch<'w, 's>(
369        &'s mut self,
370        world: UnsafeWorldCell<'w>,
371        change_tick: Tick,
372    ) -> SystemParamItem<'w, 's, Param> {
373        // SAFETY: The invariants are uphold by the caller.
374        let param =
375            unsafe { Param::get_param(&mut self.param_state, &self.meta, world, change_tick) };
376        self.meta.last_run = change_tick;
377        param
378    }
379}
380
381impl<Param: SystemParam> FromWorld for SystemState<Param> {
382    fn from_world(world: &mut World) -> Self {
383        Self::new(world)
384    }
385}
386
387/// The [`System`] counter part of an ordinary function.
388///
389/// You get this by calling [`IntoSystem::into_system`]  on a function that only accepts
390/// [`SystemParam`]s. The output of the system becomes the functions return type, while the input
391/// becomes the functions [`In`] tagged parameter or `()` if no such parameter exists.
392///
393/// [`FunctionSystem`] must be `.initialized` before they can be run.
394///
395/// The [`Clone`] implementation for [`FunctionSystem`] returns a new instance which
396/// is NOT initialized. The cloned system must also be `.initialized` before it can be run.
397pub struct FunctionSystem<Marker, F>
398where
399    F: SystemParamFunction<Marker>,
400{
401    func: F,
402    pub(crate) param_state: Option<<F::Param as SystemParam>::State>,
403    pub(crate) system_meta: SystemMeta,
404    world_id: Option<WorldId>,
405    archetype_generation: ArchetypeGeneration,
406    // NOTE: PhantomData<fn()-> T> gives this safe Send/Sync impls
407    marker: PhantomData<fn() -> Marker>,
408}
409
410impl<Marker, F> FunctionSystem<Marker, F>
411where
412    F: SystemParamFunction<Marker>,
413{
414    // Create a [`FunctionSystem`] from a [`SystemBuilder`]
415    pub(crate) fn from_builder(builder: SystemBuilder<F::Param>, func: F) -> Self {
416        Self {
417            func,
418            param_state: Some(builder.state),
419            system_meta: builder.meta,
420            world_id: Some(builder.world.id()),
421            archetype_generation: ArchetypeGeneration::initial(),
422            marker: PhantomData,
423        }
424    }
425}
426
427// De-initializes the cloned system.
428impl<Marker, F> Clone for FunctionSystem<Marker, F>
429where
430    F: SystemParamFunction<Marker> + Clone,
431{
432    fn clone(&self) -> Self {
433        Self {
434            func: self.func.clone(),
435            param_state: None,
436            system_meta: SystemMeta::new::<F>(),
437            world_id: None,
438            archetype_generation: ArchetypeGeneration::initial(),
439            marker: PhantomData,
440        }
441    }
442}
443
444/// A marker type used to distinguish regular function systems from exclusive function systems.
445#[doc(hidden)]
446pub struct IsFunctionSystem;
447
448impl<Marker, F> IntoSystem<F::In, F::Out, (IsFunctionSystem, Marker)> for F
449where
450    Marker: 'static,
451    F: SystemParamFunction<Marker>,
452{
453    type System = FunctionSystem<Marker, F>;
454    fn into_system(func: Self) -> Self::System {
455        FunctionSystem {
456            func,
457            param_state: None,
458            system_meta: SystemMeta::new::<F>(),
459            world_id: None,
460            archetype_generation: ArchetypeGeneration::initial(),
461            marker: PhantomData,
462        }
463    }
464}
465
466impl<Marker, F> FunctionSystem<Marker, F>
467where
468    F: SystemParamFunction<Marker>,
469{
470    /// Message shown when a system isn't initialised
471    // When lines get too long, rustfmt can sometimes refuse to format them.
472    // Work around this by storing the message separately.
473    const PARAM_MESSAGE: &'static str = "System's param_state was not found. Did you forget to initialize this system before running it?";
474}
475
476impl<Marker, F> System for FunctionSystem<Marker, F>
477where
478    Marker: 'static,
479    F: SystemParamFunction<Marker>,
480{
481    type In = F::In;
482    type Out = F::Out;
483
484    #[inline]
485    fn name(&self) -> Cow<'static, str> {
486        self.system_meta.name.clone()
487    }
488
489    #[inline]
490    fn component_access(&self) -> &Access<ComponentId> {
491        self.system_meta.component_access_set.combined_access()
492    }
493
494    #[inline]
495    fn archetype_component_access(&self) -> &Access<ArchetypeComponentId> {
496        &self.system_meta.archetype_component_access
497    }
498
499    #[inline]
500    fn is_send(&self) -> bool {
501        self.system_meta.is_send
502    }
503
504    #[inline]
505    fn is_exclusive(&self) -> bool {
506        false
507    }
508
509    #[inline]
510    fn has_deferred(&self) -> bool {
511        self.system_meta.has_deferred
512    }
513
514    #[inline]
515    unsafe fn run_unsafe(&mut self, input: Self::In, world: UnsafeWorldCell) -> Self::Out {
516        #[cfg(feature = "trace")]
517        let _span_guard = self.system_meta.system_span.enter();
518
519        let change_tick = world.increment_change_tick();
520
521        // SAFETY:
522        // - The caller has invoked `update_archetype_component_access`, which will panic
523        //   if the world does not match.
524        // - All world accesses used by `F::Param` have been registered, so the caller
525        //   will ensure that there are no data access conflicts.
526        let params = unsafe {
527            F::Param::get_param(
528                self.param_state.as_mut().expect(Self::PARAM_MESSAGE),
529                &self.system_meta,
530                world,
531                change_tick,
532            )
533        };
534        let out = self.func.run(input, params);
535        self.system_meta.last_run = change_tick;
536        out
537    }
538
539    #[inline]
540    fn apply_deferred(&mut self, world: &mut World) {
541        let param_state = self.param_state.as_mut().expect(Self::PARAM_MESSAGE);
542        F::Param::apply(param_state, &self.system_meta, world);
543    }
544
545    #[inline]
546    fn queue_deferred(&mut self, world: DeferredWorld) {
547        let param_state = self.param_state.as_mut().expect(Self::PARAM_MESSAGE);
548        F::Param::queue(param_state, &self.system_meta, world);
549    }
550
551    #[inline]
552    fn initialize(&mut self, world: &mut World) {
553        if let Some(id) = self.world_id {
554            assert_eq!(
555                id,
556                world.id(),
557                "System built with a different world than the one it was added to.",
558            );
559        } else {
560            self.world_id = Some(world.id());
561            self.param_state = Some(F::Param::init_state(world, &mut self.system_meta));
562        }
563        self.system_meta.last_run = world.change_tick().relative_to(Tick::MAX);
564    }
565
566    fn update_archetype_component_access(&mut self, world: UnsafeWorldCell) {
567        assert_eq!(self.world_id, Some(world.id()), "Encountered a mismatched World. A System cannot be used with Worlds other than the one it was initialized with.");
568        let archetypes = world.archetypes();
569        let old_generation =
570            std::mem::replace(&mut self.archetype_generation, archetypes.generation());
571
572        for archetype in &archetypes[old_generation..] {
573            let param_state = self.param_state.as_mut().unwrap();
574            // SAFETY: The assertion above ensures that the param_state was initialized from `world`.
575            unsafe { F::Param::new_archetype(param_state, archetype, &mut self.system_meta) };
576        }
577    }
578
579    #[inline]
580    fn check_change_tick(&mut self, change_tick: Tick) {
581        check_system_change_tick(
582            &mut self.system_meta.last_run,
583            change_tick,
584            self.system_meta.name.as_ref(),
585        );
586    }
587
588    fn default_system_sets(&self) -> Vec<InternedSystemSet> {
589        let set = crate::schedule::SystemTypeSet::<Self>::new();
590        vec![set.intern()]
591    }
592
593    fn get_last_run(&self) -> Tick {
594        self.system_meta.last_run
595    }
596
597    fn set_last_run(&mut self, last_run: Tick) {
598        self.system_meta.last_run = last_run;
599    }
600}
601
602/// SAFETY: `F`'s param is [`ReadOnlySystemParam`], so this system will only read from the world.
603unsafe impl<Marker, F> ReadOnlySystem for FunctionSystem<Marker, F>
604where
605    Marker: 'static,
606    F: SystemParamFunction<Marker>,
607    F::Param: ReadOnlySystemParam,
608{
609}
610
611/// A trait implemented for all functions that can be used as [`System`]s.
612///
613/// This trait can be useful for making your own systems which accept other systems,
614/// sometimes called higher order systems.
615///
616/// This should be used in combination with [`ParamSet`] when calling other systems
617/// within your system.
618/// Using [`ParamSet`] in this case avoids [`SystemParam`] collisions.
619///
620/// # Example
621///
622/// To create something like [`PipeSystem`], but in entirely safe code.
623///
624/// ```
625/// use std::num::ParseIntError;
626///
627/// use bevy_ecs::prelude::*;
628///
629/// /// Pipe creates a new system which calls `a`, then calls `b` with the output of `a`
630/// pub fn pipe<A, B, AMarker, BMarker>(
631///     mut a: A,
632///     mut b: B,
633/// ) -> impl FnMut(In<A::In>, ParamSet<(A::Param, B::Param)>) -> B::Out
634/// where
635///     // We need A and B to be systems, add those bounds
636///     A: SystemParamFunction<AMarker>,
637///     B: SystemParamFunction<BMarker, In = A::Out>,
638/// {
639///     // The type of `params` is inferred based on the return of this function above
640///     move |In(a_in), mut params| {
641///         let shared = a.run(a_in, params.p0());
642///         b.run(shared, params.p1())
643///     }
644/// }
645///
646/// // Usage example for `pipe`:
647/// fn main() {
648///     let mut world = World::default();
649///     world.insert_resource(Message("42".to_string()));
650///
651///     // pipe the `parse_message_system`'s output into the `filter_system`s input
652///     let mut piped_system = IntoSystem::into_system(pipe(parse_message, filter));
653///     piped_system.initialize(&mut world);
654///     assert_eq!(piped_system.run((), &mut world), Some(42));
655/// }
656///
657/// #[derive(Resource)]
658/// struct Message(String);
659///
660/// fn parse_message(message: Res<Message>) -> Result<usize, ParseIntError> {
661///     message.0.parse::<usize>()
662/// }
663///
664/// fn filter(In(result): In<Result<usize, ParseIntError>>) -> Option<usize> {
665///     result.ok().filter(|&n| n < 100)
666/// }
667/// ```
668/// [`PipeSystem`]: crate::system::PipeSystem
669/// [`ParamSet`]: crate::system::ParamSet
670#[diagnostic::on_unimplemented(
671    message = "`{Self}` is not a valid system",
672    label = "invalid system"
673)]
674pub trait SystemParamFunction<Marker>: Send + Sync + 'static {
675    /// The input type to this system. See [`System::In`].
676    type In;
677
678    /// The return type of this system. See [`System::Out`].
679    type Out;
680
681    /// The [`SystemParam`]/s used by this system to access the [`World`].
682    type Param: SystemParam;
683
684    /// Executes this system once. See [`System::run`] or [`System::run_unsafe`].
685    fn run(&mut self, input: Self::In, param_value: SystemParamItem<Self::Param>) -> Self::Out;
686}
687
688macro_rules! impl_system_function {
689    ($($param: ident),*) => {
690        #[allow(non_snake_case)]
691        impl<Out, Func: Send + Sync + 'static, $($param: SystemParam),*> SystemParamFunction<fn($($param,)*) -> Out> for Func
692        where
693        for <'a> &'a mut Func:
694                FnMut($($param),*) -> Out +
695                FnMut($(SystemParamItem<$param>),*) -> Out, Out: 'static
696        {
697            type In = ();
698            type Out = Out;
699            type Param = ($($param,)*);
700            #[inline]
701            fn run(&mut self, _input: (), param_value: SystemParamItem< ($($param,)*)>) -> Out {
702                // Yes, this is strange, but `rustc` fails to compile this impl
703                // without using this function. It fails to recognize that `func`
704                // is a function, potentially because of the multiple impls of `FnMut`
705                #[allow(clippy::too_many_arguments)]
706                fn call_inner<Out, $($param,)*>(
707                    mut f: impl FnMut($($param,)*)->Out,
708                    $($param: $param,)*
709                )->Out{
710                    f($($param,)*)
711                }
712                let ($($param,)*) = param_value;
713                call_inner(self, $($param),*)
714            }
715        }
716
717        #[allow(non_snake_case)]
718        impl<Input, Out, Func: Send + Sync + 'static, $($param: SystemParam),*> SystemParamFunction<fn(In<Input>, $($param,)*) -> Out> for Func
719        where
720        for <'a> &'a mut Func:
721                FnMut(In<Input>, $($param),*) -> Out +
722                FnMut(In<Input>, $(SystemParamItem<$param>),*) -> Out, Out: 'static
723        {
724            type In = Input;
725            type Out = Out;
726            type Param = ($($param,)*);
727            #[inline]
728            fn run(&mut self, input: Input, param_value: SystemParamItem< ($($param,)*)>) -> Out {
729                #[allow(clippy::too_many_arguments)]
730                fn call_inner<Input, Out, $($param,)*>(
731                    mut f: impl FnMut(In<Input>, $($param,)*)->Out,
732                    input: In<Input>,
733                    $($param: $param,)*
734                )->Out{
735                    f(input, $($param,)*)
736                }
737                let ($($param,)*) = param_value;
738                call_inner(self, In(input), $($param),*)
739            }
740        }
741    };
742}
743
744// Note that we rely on the highest impl to be <= the highest order of the tuple impls
745// of `SystemParam` created.
746all_tuples!(impl_system_function, 0, 16, F);
747
748#[cfg(test)]
749mod tests {
750    use super::*;
751
752    #[test]
753    fn into_system_type_id_consistency() {
754        fn test<T, In, Out, Marker>(function: T)
755        where
756            T: IntoSystem<In, Out, Marker> + Copy,
757        {
758            fn reference_system() {}
759
760            use std::any::TypeId;
761
762            let system = IntoSystem::into_system(function);
763
764            assert_eq!(
765                system.type_id(),
766                function.system_type_id(),
767                "System::type_id should be consistent with IntoSystem::system_type_id"
768            );
769
770            assert_eq!(
771                system.type_id(),
772                TypeId::of::<T::System>(),
773                "System::type_id should be consistent with TypeId::of::<T::System>()"
774            );
775
776            assert_ne!(
777                system.type_id(),
778                IntoSystem::into_system(reference_system).type_id(),
779                "Different systems should have different TypeIds"
780            );
781        }
782
783        fn function_system() {}
784
785        test(function_system);
786    }
787}