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 pub fn new(world: &mut World) -> Self {
290 let mut meta = SystemMeta::new::<Param>();
291 meta.last_run = world.change_tick().relative_to(Tick::MAX);
292 let param_state = Param::init_state(world);
293 let mut component_access_set = FilteredAccessSet::new();
294 // We need to call `init_access` to ensure there are no panics from conflicts within `Param`,
295 // even though we don't use the calculated access.
296 Param::init_access(¶m_state, &mut meta, &mut component_access_set, world);
297 Self {
298 meta,
299 param_state,
300 world_id: world.id(),
301 }
302 }
303
304 /// Create a [`SystemState`] from a [`SystemParamBuilder`]
305 pub(crate) fn from_builder(world: &mut World, builder: impl SystemParamBuilder<Param>) -> Self {
306 let mut meta = SystemMeta::new::<Param>();
307 meta.last_run = world.change_tick().relative_to(Tick::MAX);
308 let param_state = builder.build(world);
309 let mut component_access_set = FilteredAccessSet::new();
310 // We need to call `init_access` to ensure there are no panics from conflicts within `Param`,
311 // even though we don't use the calculated access.
312 Param::init_access(¶m_state, &mut meta, &mut component_access_set, world);
313 Self {
314 meta,
315 param_state,
316 world_id: world.id(),
317 }
318 }
319
320 /// Create a [`FunctionSystem`] from a [`SystemState`].
321 /// This method signature allows any system function, but the compiler will not perform type inference on closure parameters.
322 /// You can use [`SystemState::build_system()`] or [`SystemState::build_system_with_input()`] to get type inference on parameters.
323 #[inline]
324 pub fn build_any_system<Marker, In, Out, F>(self, func: F) -> FunctionSystem<Marker, In, Out, F>
325 where
326 In: SystemInput,
327 F: SystemParamFunction<Marker, In: FromInput<In>, Out: IntoResult<Out>, Param = Param>,
328 {
329 FunctionSystem::new(
330 func,
331 self.meta,
332 Some(FunctionSystemState {
333 param: self.param_state,
334 world_id: self.world_id,
335 }),
336 )
337 }
338
339 /// Gets the metadata for this instance.
340 #[inline]
341 pub fn meta(&self) -> &SystemMeta {
342 &self.meta
343 }
344
345 /// Gets the metadata for this instance.
346 #[inline]
347 pub fn meta_mut(&mut self) -> &mut SystemMeta {
348 &mut self.meta
349 }
350
351 /// Retrieve the [`SystemParam`] values. This can only be called when all parameters are read-only.
352 #[inline]
353 pub fn get<'w, 's>(&'s mut self, world: &'w World) -> SystemParamItem<'w, 's, Param>
354 where
355 Param: ReadOnlySystemParam,
356 {
357 self.validate_world(world.id());
358 // SAFETY: Param is read-only and doesn't allow mutable access to World.
359 // It also matches the World this SystemState was created with.
360 unsafe { self.get_unchecked(world.as_unsafe_world_cell_readonly()) }
361 }
362
363 /// Retrieve the mutable [`SystemParam`] values.
364 #[inline]
365 pub fn get_mut<'w, 's>(&'s mut self, world: &'w mut World) -> SystemParamItem<'w, 's, Param> {
366 self.validate_world(world.id());
367 // SAFETY: World is uniquely borrowed and matches the World this SystemState was created with.
368 unsafe { self.get_unchecked(world.as_unsafe_world_cell()) }
369 }
370
371 /// Applies all state queued up for [`SystemParam`] values. For example, this will apply commands queued up
372 /// by a [`Commands`](`super::Commands`) parameter to the given [`World`].
373 /// This function should be called manually after the values returned by [`SystemState::get`] and [`SystemState::get_mut`]
374 /// are finished being used.
375 pub fn apply(&mut self, world: &mut World) {
376 Param::apply(&mut self.param_state, &self.meta, world);
377 }
378
379 /// Wrapper over [`SystemParam::validate_param`].
380 ///
381 /// # Safety
382 ///
383 /// - The passed [`UnsafeWorldCell`] must have read-only access to
384 /// world data in `component_access_set`.
385 /// - `world` must be the same [`World`] that was used to initialize [`state`](SystemParam::init_state).
386 pub unsafe fn validate_param(
387 state: &mut Self,
388 world: UnsafeWorldCell,
389 ) -> Result<(), SystemParamValidationError> {
390 // SAFETY: Delegated to existing `SystemParam` implementations.
391 unsafe { Param::validate_param(&mut state.param_state, &state.meta, world) }
392 }
393
394 /// Returns `true` if `world_id` matches the [`World`] that was used to call [`SystemState::new`].
395 /// Otherwise, this returns false.
396 #[inline]
397 pub fn matches_world(&self, world_id: WorldId) -> bool {
398 self.world_id == world_id
399 }
400
401 /// Asserts that the [`SystemState`] matches the provided world.
402 #[inline]
403 #[track_caller]
404 fn validate_world(&self, world_id: WorldId) {
405 #[inline(never)]
406 #[track_caller]
407 #[cold]
408 fn panic_mismatched(this: WorldId, other: WorldId) -> ! {
409 panic!("Encountered a mismatched World. This SystemState was created from {this:?}, but a method was called using {other:?}.");
410 }
411
412 if !self.matches_world(world_id) {
413 panic_mismatched(self.world_id, world_id);
414 }
415 }
416
417 /// Retrieve the [`SystemParam`] values.
418 ///
419 /// # Safety
420 /// This call might access any of the input parameters in a way that violates Rust's mutability rules. Make sure the data
421 /// access is safe in the context of global [`World`] access. The passed-in [`World`] _must_ be the [`World`] the [`SystemState`] was
422 /// created with.
423 #[inline]
424 pub unsafe fn get_unchecked<'w, 's>(
425 &'s mut self,
426 world: UnsafeWorldCell<'w>,
427 ) -> SystemParamItem<'w, 's, Param> {
428 let change_tick = world.increment_change_tick();
429 // SAFETY: The invariants are upheld by the caller.
430 unsafe { self.fetch(world, change_tick) }
431 }
432
433 /// # Safety
434 /// This call might access any of the input parameters in a way that violates Rust's mutability rules. Make sure the data
435 /// access is safe in the context of global [`World`] access. The passed-in [`World`] _must_ be the [`World`] the [`SystemState`] was
436 /// created with.
437 #[inline]
438 unsafe fn fetch<'w, 's>(
439 &'s mut self,
440 world: UnsafeWorldCell<'w>,
441 change_tick: Tick,
442 ) -> SystemParamItem<'w, 's, Param> {
443 // SAFETY: The invariants are upheld by the caller.
444 let param =
445 unsafe { Param::get_param(&mut self.param_state, &self.meta, world, change_tick) };
446 self.meta.last_run = change_tick;
447 param
448 }
449
450 /// Returns a reference to the current system param states.
451 pub fn param_state(&self) -> &Param::State {
452 &self.param_state
453 }
454
455 /// Returns a mutable reference to the current system param states.
456 /// Marked as unsafe because modifying the system states may result in violation to certain
457 /// assumptions made by the [`SystemParam`]. Use with care.
458 ///
459 /// # Safety
460 /// Modifying the system param states may have unintended consequences.
461 /// The param state is generally considered to be owned by the [`SystemParam`]. Modifications
462 /// should respect any invariants as required by the [`SystemParam`].
463 /// For example, modifying the system state of [`ResMut`](crate::system::ResMut) will obviously create issues.
464 pub unsafe fn param_state_mut(&mut self) -> &mut Param::State {
465 &mut self.param_state
466 }
467}
468
469impl<Param: SystemParam> FromWorld for SystemState<Param> {
470 fn from_world(world: &mut World) -> Self {
471 Self::new(world)
472 }
473}
474
475/// The [`System`] counter part of an ordinary function.
476///
477/// You get this by calling [`IntoSystem::into_system`] on a function that only accepts
478/// [`SystemParam`]s. The output of the system becomes the functions return type, while the input
479/// becomes the functions first parameter or `()` if no such parameter exists.
480///
481/// [`FunctionSystem`] must be `.initialized` before they can be run.
482///
483/// The [`Clone`] implementation for [`FunctionSystem`] returns a new instance which
484/// is NOT initialized. The cloned system must also be `.initialized` before it can be run.
485pub struct FunctionSystem<Marker, In, Out, F>
486where
487 F: SystemParamFunction<Marker>,
488{
489 func: F,
490 #[cfg(feature = "hotpatching")]
491 current_ptr: subsecond::HotFnPtr,
492 state: Option<FunctionSystemState<F::Param>>,
493 system_meta: SystemMeta,
494 // NOTE: PhantomData<fn()-> T> gives this safe Send/Sync impls
495 marker: PhantomData<fn(In) -> (Marker, Out)>,
496}
497
498/// The state of a [`FunctionSystem`], which must be initialized with
499/// [`System::initialize`] before the system can be run. A panic will occur if
500/// the system is run without being initialized.
501struct FunctionSystemState<P: SystemParam> {
502 /// The cached state of the system's [`SystemParam`]s.
503 param: P::State,
504 /// The id of the [`World`] this system was initialized with. If the world
505 /// passed to [`System::run_unsafe`] or [`System::validate_param_unsafe`] does not match
506 /// this id, a panic will occur.
507 world_id: WorldId,
508}
509
510impl<Marker, In, Out, F> FunctionSystem<Marker, In, Out, F>
511where
512 F: SystemParamFunction<Marker>,
513{
514 #[inline]
515 fn new(func: F, system_meta: SystemMeta, state: Option<FunctionSystemState<F::Param>>) -> Self {
516 Self {
517 func,
518 #[cfg(feature = "hotpatching")]
519 current_ptr: subsecond::HotFn::current(<F as SystemParamFunction<Marker>>::run)
520 .ptr_address(),
521 state,
522 system_meta,
523 marker: PhantomData,
524 }
525 }
526
527 /// Return this system with a new name.
528 ///
529 /// Useful to give closure systems more readable and unique names for debugging and tracing.
530 pub fn with_name(mut self, new_name: impl Into<Cow<'static, str>>) -> Self {
531 self.system_meta.set_name(new_name.into());
532 self
533 }
534}
535
536// De-initializes the cloned system.
537impl<Marker, In, Out, F> Clone for FunctionSystem<Marker, In, Out, F>
538where
539 F: SystemParamFunction<Marker> + Clone,
540{
541 fn clone(&self) -> Self {
542 Self {
543 func: self.func.clone(),
544 #[cfg(feature = "hotpatching")]
545 current_ptr: subsecond::HotFn::current(<F as SystemParamFunction<Marker>>::run)
546 .ptr_address(),
547 state: None,
548 system_meta: SystemMeta::new::<F>(),
549 marker: PhantomData,
550 }
551 }
552}
553
554/// A marker type used to distinguish regular function systems from exclusive function systems.
555#[doc(hidden)]
556pub struct IsFunctionSystem;
557
558impl<Marker, In, Out, F> IntoSystem<In, Out, (IsFunctionSystem, Marker)> for F
559where
560 Marker: 'static,
561 In: SystemInput + 'static,
562 Out: 'static,
563 F: SystemParamFunction<Marker, In: FromInput<In>, Out: IntoResult<Out>>,
564{
565 type System = FunctionSystem<Marker, In, Out, F>;
566 fn into_system(func: Self) -> Self::System {
567 FunctionSystem::new(func, SystemMeta::new::<F>(), None)
568 }
569}
570
571/// A type that may be converted to the output of a [`System`].
572/// This is used to allow systems to return either a plain value or a [`Result`].
573pub trait IntoResult<Out>: Sized {
574 /// Converts this type into the system output type.
575 fn into_result(self) -> Result<Out, RunSystemError>;
576}
577
578impl<T> IntoResult<T> for T {
579 fn into_result(self) -> Result<T, RunSystemError> {
580 Ok(self)
581 }
582}
583
584impl<T> IntoResult<T> for Result<T, RunSystemError> {
585 fn into_result(self) -> Result<T, RunSystemError> {
586 self
587 }
588}
589
590impl<T> IntoResult<T> for Result<T, BevyError> {
591 fn into_result(self) -> Result<T, RunSystemError> {
592 Ok(self?)
593 }
594}
595
596// The `!` impl can't be generic in `Out`, since that would overlap with
597// `impl<T> IntoResult<T> for T` when `T` = `!`.
598// Use explicit impls for `()` and `bool` so diverging functions
599// can be used for systems and conditions.
600impl IntoResult<()> for Never {
601 fn into_result(self) -> Result<(), RunSystemError> {
602 self
603 }
604}
605
606impl IntoResult<bool> for Never {
607 fn into_result(self) -> Result<bool, RunSystemError> {
608 self
609 }
610}
611
612impl<Marker, In, Out, F> FunctionSystem<Marker, In, Out, F>
613where
614 F: SystemParamFunction<Marker>,
615{
616 /// Message shown when a system isn't initialized
617 // When lines get too long, rustfmt can sometimes refuse to format them.
618 // Work around this by storing the message separately.
619 const ERROR_UNINITIALIZED: &'static str =
620 "System's state was not found. Did you forget to initialize this system before running it?";
621}
622
623impl<Marker, In, Out, F> System for FunctionSystem<Marker, In, Out, F>
624where
625 Marker: 'static,
626 In: SystemInput + 'static,
627 Out: 'static,
628 F: SystemParamFunction<Marker, In: FromInput<In>, Out: IntoResult<Out>>,
629{
630 type In = In;
631 type Out = Out;
632
633 #[inline]
634 fn name(&self) -> DebugName {
635 self.system_meta.name.clone()
636 }
637
638 #[inline]
639 fn flags(&self) -> SystemStateFlags {
640 self.system_meta.flags
641 }
642
643 #[inline]
644 unsafe fn run_unsafe(
645 &mut self,
646 input: SystemIn<'_, Self>,
647 world: UnsafeWorldCell,
648 ) -> Result<Self::Out, RunSystemError> {
649 #[cfg(feature = "trace")]
650 let _span_guard = self.system_meta.system_span.enter();
651
652 let change_tick = world.increment_change_tick();
653
654 let input = F::In::from_inner(input);
655
656 let state = self.state.as_mut().expect(Self::ERROR_UNINITIALIZED);
657 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.");
658 // SAFETY:
659 // - The above assert ensures the world matches.
660 // - All world accesses used by `F::Param` have been registered, so the caller
661 // will ensure that there are no data access conflicts.
662 let params =
663 unsafe { F::Param::get_param(&mut state.param, &self.system_meta, world, change_tick) };
664
665 #[cfg(feature = "hotpatching")]
666 let out = {
667 let mut hot_fn = subsecond::HotFn::current(<F as SystemParamFunction<Marker>>::run);
668 // SAFETY:
669 // - pointer used to call is from the current jump table
670 unsafe {
671 hot_fn
672 .try_call_with_ptr(self.current_ptr, (&mut self.func, input, params))
673 .expect("Error calling hotpatched system. Run a full rebuild")
674 }
675 };
676 #[cfg(not(feature = "hotpatching"))]
677 let out = self.func.run(input, params);
678
679 self.system_meta.last_run = change_tick;
680 IntoResult::into_result(out)
681 }
682
683 #[cfg(feature = "hotpatching")]
684 #[inline]
685 fn refresh_hotpatch(&mut self) {
686 let new = subsecond::HotFn::current(<F as SystemParamFunction<Marker>>::run).ptr_address();
687 if new != self.current_ptr {
688 log::debug!("system {} hotpatched", self.name());
689 }
690 self.current_ptr = new;
691 }
692
693 #[inline]
694 fn apply_deferred(&mut self, world: &mut World) {
695 let param_state = &mut self.state.as_mut().expect(Self::ERROR_UNINITIALIZED).param;
696 F::Param::apply(param_state, &self.system_meta, world);
697 }
698
699 #[inline]
700 fn queue_deferred(&mut self, world: DeferredWorld) {
701 let param_state = &mut self.state.as_mut().expect(Self::ERROR_UNINITIALIZED).param;
702 F::Param::queue(param_state, &self.system_meta, world);
703 }
704
705 #[inline]
706 unsafe fn validate_param_unsafe(
707 &mut self,
708 world: UnsafeWorldCell,
709 ) -> Result<(), SystemParamValidationError> {
710 let state = self.state.as_mut().expect(Self::ERROR_UNINITIALIZED);
711 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.");
712 // SAFETY:
713 // - The above assert ensures the world matches.
714 // - All world accesses used by `F::Param` have been registered, so the caller
715 // will ensure that there are no data access conflicts.
716 unsafe { F::Param::validate_param(&mut state.param, &self.system_meta, world) }
717 }
718
719 #[inline]
720 fn initialize(&mut self, world: &mut World) -> FilteredAccessSet {
721 if let Some(state) = &self.state {
722 assert_eq!(
723 state.world_id,
724 world.id(),
725 "System built with a different world than the one it was added to.",
726 );
727 }
728 let state = self.state.get_or_insert_with(|| FunctionSystemState {
729 param: F::Param::init_state(world),
730 world_id: world.id(),
731 });
732 self.system_meta.last_run = world.change_tick().relative_to(Tick::MAX);
733 let mut component_access_set = FilteredAccessSet::new();
734 F::Param::init_access(
735 &state.param,
736 &mut self.system_meta,
737 &mut component_access_set,
738 world,
739 );
740 component_access_set
741 }
742
743 #[inline]
744 fn check_change_tick(&mut self, check: CheckChangeTicks) {
745 check_system_change_tick(
746 &mut self.system_meta.last_run,
747 check,
748 self.system_meta.name.clone(),
749 );
750 }
751
752 fn default_system_sets(&self) -> Vec<InternedSystemSet> {
753 let set = crate::schedule::SystemTypeSet::<Self>::new();
754 vec![set.intern()]
755 }
756
757 fn get_last_run(&self) -> Tick {
758 self.system_meta.last_run
759 }
760
761 fn set_last_run(&mut self, last_run: Tick) {
762 self.system_meta.last_run = last_run;
763 }
764}
765
766/// SAFETY: `F`'s param is [`ReadOnlySystemParam`], so this system will only read from the world.
767unsafe impl<Marker, In, Out, F> ReadOnlySystem for FunctionSystem<Marker, In, Out, F>
768where
769 Marker: 'static,
770 In: SystemInput + 'static,
771 Out: 'static,
772 F: SystemParamFunction<
773 Marker,
774 In: FromInput<In>,
775 Out: IntoResult<Out>,
776 Param: ReadOnlySystemParam,
777 >,
778{
779}
780
781/// A trait implemented for all functions that can be used as [`System`]s.
782///
783/// This trait can be useful for making your own systems which accept other systems,
784/// sometimes called higher order systems.
785///
786/// This should be used in combination with [`ParamSet`] when calling other systems
787/// within your system.
788/// Using [`ParamSet`] in this case avoids [`SystemParam`] collisions.
789///
790/// # Example
791///
792/// To create something like [`PipeSystem`], but in entirely safe code.
793///
794/// ```
795/// use std::num::ParseIntError;
796///
797/// use bevy_ecs::prelude::*;
798/// use bevy_ecs::system::StaticSystemInput;
799///
800/// /// Pipe creates a new system which calls `a`, then calls `b` with the output of `a`
801/// pub fn pipe<A, B, AMarker, BMarker>(
802/// mut a: A,
803/// mut b: B,
804/// ) -> impl FnMut(StaticSystemInput<A::In>, ParamSet<(A::Param, B::Param)>) -> B::Out
805/// where
806/// // We need A and B to be systems, add those bounds
807/// A: SystemParamFunction<AMarker>,
808/// B: SystemParamFunction<BMarker>,
809/// for<'a> B::In: SystemInput<Inner<'a> = A::Out>,
810/// {
811/// // The type of `params` is inferred based on the return of this function above
812/// move |StaticSystemInput(a_in), mut params| {
813/// let shared = a.run(a_in, params.p0());
814/// b.run(shared, params.p1())
815/// }
816/// }
817///
818/// // Usage example for `pipe`:
819/// fn main() {
820/// let mut world = World::default();
821/// world.insert_resource(Message("42".to_string()));
822///
823/// // pipe the `parse_message_system`'s output into the `filter_system`s input.
824/// // Type annotations should only needed when using `StaticSystemInput` as input
825/// // AND the input type isn't constrained by nearby code.
826/// let mut piped_system = IntoSystem::<(), Option<usize>, _>::into_system(pipe(parse_message, filter));
827/// piped_system.initialize(&mut world);
828/// assert_eq!(piped_system.run((), &mut world).unwrap(), Some(42));
829/// }
830///
831/// #[derive(Resource)]
832/// struct Message(String);
833///
834/// fn parse_message(message: Res<Message>) -> Result<usize, ParseIntError> {
835/// message.0.parse::<usize>()
836/// }
837///
838/// fn filter(In(result): In<Result<usize, ParseIntError>>) -> Option<usize> {
839/// result.ok().filter(|&n| n < 100)
840/// }
841/// ```
842/// [`PipeSystem`]: crate::system::PipeSystem
843/// [`ParamSet`]: crate::system::ParamSet
844#[diagnostic::on_unimplemented(
845 message = "`{Self}` is not a valid system",
846 label = "invalid system"
847)]
848pub trait SystemParamFunction<Marker>: Send + Sync + 'static {
849 /// The input type of this system. See [`System::In`].
850 type In: SystemInput;
851 /// The return type of this system. See [`System::Out`].
852 type Out;
853
854 /// The [`SystemParam`]/s used by this system to access the [`World`].
855 type Param: SystemParam;
856
857 /// Executes this system once. See [`System::run`] or [`System::run_unsafe`].
858 fn run(
859 &mut self,
860 input: <Self::In as SystemInput>::Inner<'_>,
861 param_value: SystemParamItem<Self::Param>,
862 ) -> Self::Out;
863}
864
865/// A marker type used to distinguish function systems with and without input.
866#[doc(hidden)]
867pub struct HasSystemInput;
868
869macro_rules! impl_system_function {
870 ($($param: ident),*) => {
871 #[expect(
872 clippy::allow_attributes,
873 reason = "This is within a macro, and as such, the below lints may not always apply."
874 )]
875 #[allow(
876 non_snake_case,
877 reason = "Certain variable names are provided by the caller, not by us."
878 )]
879 impl<Out, Func, $($param: SystemParam),*> SystemParamFunction<fn($($param,)*) -> Out> for Func
880 where
881 Func: Send + Sync + 'static,
882 for <'a> &'a mut Func:
883 FnMut($($param),*) -> Out +
884 FnMut($(SystemParamItem<$param>),*) -> Out,
885 Out: 'static
886 {
887 type In = ();
888 type Out = Out;
889 type Param = ($($param,)*);
890 #[inline]
891 fn run(&mut self, _input: (), param_value: SystemParamItem< ($($param,)*)>) -> Out {
892 // Yes, this is strange, but `rustc` fails to compile this impl
893 // without using this function. It fails to recognize that `func`
894 // is a function, potentially because of the multiple impls of `FnMut`
895 fn call_inner<Out, $($param,)*>(
896 mut f: impl FnMut($($param,)*)->Out,
897 $($param: $param,)*
898 )->Out{
899 f($($param,)*)
900 }
901 let ($($param,)*) = param_value;
902 call_inner(self, $($param),*)
903 }
904 }
905
906 #[expect(
907 clippy::allow_attributes,
908 reason = "This is within a macro, and as such, the below lints may not always apply."
909 )]
910 #[allow(
911 non_snake_case,
912 reason = "Certain variable names are provided by the caller, not by us."
913 )]
914 impl<In, Out, Func, $($param: SystemParam),*> SystemParamFunction<(HasSystemInput, fn(In, $($param,)*) -> Out)> for Func
915 where
916 Func: Send + Sync + 'static,
917 for <'a> &'a mut Func:
918 FnMut(In, $($param),*) -> Out +
919 FnMut(In::Param<'_>, $(SystemParamItem<$param>),*) -> Out,
920 In: SystemInput + 'static,
921 Out: 'static
922 {
923 type In = In;
924 type Out = Out;
925 type Param = ($($param,)*);
926 #[inline]
927 fn run(&mut self, input: In::Inner<'_>, param_value: SystemParamItem< ($($param,)*)>) -> Out {
928 fn call_inner<In: SystemInput, Out, $($param,)*>(
929 _: PhantomData<In>,
930 mut f: impl FnMut(In::Param<'_>, $($param,)*)->Out,
931 input: In::Inner<'_>,
932 $($param: $param,)*
933 )->Out{
934 f(In::wrap(input), $($param,)*)
935 }
936 let ($($param,)*) = param_value;
937 call_inner(PhantomData::<In>, self, input, $($param),*)
938 }
939 }
940 };
941}
942
943// Note that we rely on the highest impl to be <= the highest order of the tuple impls
944// of `SystemParam` created.
945all_tuples!(impl_system_function, 0, 16, F);
946
947#[cfg(test)]
948mod tests {
949 use super::*;
950
951 #[test]
952 fn into_system_type_id_consistency() {
953 fn test<T, In: SystemInput, Out, Marker>(function: T)
954 where
955 T: IntoSystem<In, Out, Marker> + Copy,
956 {
957 fn reference_system() {}
958
959 use core::any::TypeId;
960
961 let system = IntoSystem::into_system(function);
962
963 assert_eq!(
964 system.type_id(),
965 function.system_type_id(),
966 "System::type_id should be consistent with IntoSystem::system_type_id"
967 );
968
969 assert_eq!(
970 system.type_id(),
971 TypeId::of::<T::System>(),
972 "System::type_id should be consistent with TypeId::of::<T::System>()"
973 );
974
975 assert_ne!(
976 system.type_id(),
977 IntoSystem::into_system(reference_system).type_id(),
978 "Different systems should have different TypeIds"
979 );
980 }
981
982 fn function_system() {}
983
984 test(function_system);
985 }
986}