1use crate::{
2 change_detection::{CheckChangeTicks, Tick},
3 error::{BevyError, Result},
4never::Never,
5prelude::FromWorld,
6query::FilteredAccessSet,
7 schedule::{InternedSystemSet, SystemSet},
8 system::{
9check_system_change_tick, FromInput, ReadOnlySystemParam, System, SystemIn, SystemInput,
10SystemParam, SystemParamItem,
11 },
12 world::{unsafe_world_cell::UnsafeWorldCell, DeferredWorld, World, WorldId},
13};
1415use alloc::{borrow::Cow, vec, vec::Vec};
16use bevy_utils::prelude::DebugName;
17use core::marker::PhantomData;
18use variadics_please::all_tuples;
1920#[cfg(feature = "trace")]
21use tracing::{info_span, Span};
2223#[cfg(feature = "trace")]
24use alloc::string::ToStringas _;
2526use super::{
27IntoSystem, ReadOnlySystem, RunSystemError, SystemParamBuilder, SystemParamValidationError,
28SystemStateFlags,
29};
3031/// The metadata of a [`System`].
32#[derive(#[automatically_derived]
impl ::core::clone::Clone for SystemMeta {
#[inline]
fn clone(&self) -> SystemMeta {
SystemMeta {
name: ::core::clone::Clone::clone(&self.name),
flags: ::core::clone::Clone::clone(&self.flags),
last_run: ::core::clone::Clone::clone(&self.last_run),
system_span: ::core::clone::Clone::clone(&self.system_span),
commands_span: ::core::clone::Clone::clone(&self.commands_span),
}
}
}Clone)]
33pub struct SystemMeta {
34pub(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
37flags: SystemStateFlags,
38pub(crate) last_run: Tick,
39#[cfg(feature = "trace")]
40pub(crate) system_span: Span,
41#[cfg(feature = "trace")]
42pub(crate) commands_span: Span,
43}
4445impl SystemMeta {
46pub(crate) fn new<T>() -> Self {
47let name = DebugName::type_name::<T>();
48Self {
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: {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::__macro_support::MacroCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("system",
"bevy_ecs::system::function_system", ::tracing::Level::INFO,
::tracing_core::__macro_support::Option::Some("src/system/function_system.rs"),
::tracing_core::__macro_support::Option::Some(52u32),
::tracing_core::__macro_support::Option::Some("bevy_ecs::system::function_system"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("name")
}> =
::tracing::__macro_support::FieldName::new("name");
NAME.as_str()
}], ::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::INFO <= ::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::INFO <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() } &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::child_of(None, meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&name.clone().to_string()
as &dyn ::tracing::field::Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
}info_span!(parent: None, "system", name = name.clone().to_string()),
53#[cfg(feature = "trace")]
54 commands_span: {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::__macro_support::MacroCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("system_commands",
"bevy_ecs::system::function_system", ::tracing::Level::INFO,
::tracing_core::__macro_support::Option::Some("src/system/function_system.rs"),
::tracing_core::__macro_support::Option::Some(54u32),
::tracing_core::__macro_support::Option::Some("bevy_ecs::system::function_system"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("name")
}> =
::tracing::__macro_support::FieldName::new("name");
NAME.as_str()
}], ::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::INFO <= ::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::INFO <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() } &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::child_of(None, meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&name.clone().to_string()
as &dyn ::tracing::field::Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
}info_span!(parent: None, "system_commands", name = name.clone().to_string()),
55name,
56 flags: SystemStateFlags::empty(),
57 last_run: Tick::new(0),
58 }
59 }
6061/// Returns the system's name
62#[inline]
63pub fn name(&self) -> &DebugName {
64&self.name
65 }
6667/// Returns the system's state flags
68pub fn flags(&self) -> SystemStateFlags {
69self.flags
70 }
7172/// Sets the name of this system.
73 ///
74 /// Useful to give closure systems more readable and unique names for debugging and tracing.
75#[inline]
76pub fn set_name(&mut self, new_name: impl Into<Cow<'static, str>>) {
77let new_name: Cow<'static, str> = new_name.into();
78#[cfg(feature = "trace")]
79{
80let name = new_name.as_ref();
81self.system_span = {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::__macro_support::MacroCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("system",
"bevy_ecs::system::function_system", ::tracing::Level::INFO,
::tracing_core::__macro_support::Option::Some("src/system/function_system.rs"),
::tracing_core::__macro_support::Option::Some(81u32),
::tracing_core::__macro_support::Option::Some("bevy_ecs::system::function_system"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("name")
}> =
::tracing::__macro_support::FieldName::new("name");
NAME.as_str()
}], ::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::INFO <= ::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::INFO <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() } &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::child_of(None, meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&name
as &dyn ::tracing::field::Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
}info_span!(parent: None, "system", name = name);
82self.commands_span = {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::__macro_support::MacroCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("system_commands",
"bevy_ecs::system::function_system", ::tracing::Level::INFO,
::tracing_core::__macro_support::Option::Some("src/system/function_system.rs"),
::tracing_core::__macro_support::Option::Some(82u32),
::tracing_core::__macro_support::Option::Some("bevy_ecs::system::function_system"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("name")
}> =
::tracing::__macro_support::FieldName::new("name");
NAME.as_str()
}], ::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::INFO <= ::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::INFO <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() } &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::child_of(None, meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&name
as &dyn ::tracing::field::Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
}info_span!(parent: None, "system_commands", name = name);
83 }
84self.name = new_name.into();
85 }
8687/// Gets the last time this system was run.
88#[inline]
89pub fn get_last_run(&self) -> Tick {
90self.last_run
91 }
9293/// Sets the last time this system was run.
94#[inline]
95pub fn set_last_run(&mut self, last_run: Tick) {
96self.last_run = last_run;
97 }
9899/// Returns true if the system is [`Send`].
100#[inline]
101pub fn is_send(&self) -> bool {
102 !self.flags.intersects(SystemStateFlags::NON_SEND)
103 }
104105/// Sets the system to be not [`Send`].
106 ///
107 /// This is irreversible.
108#[inline]
109pub fn set_non_send(&mut self) {
110self.flags |= SystemStateFlags::NON_SEND;
111 }
112113/// Returns true if the system has deferred [`SystemParam`]'s
114#[inline]
115pub fn has_deferred(&self) -> bool {
116self.flags.intersects(SystemStateFlags::DEFERRED)
117 }
118119/// Marks the system as having deferred buffers like [`Commands`](`super::Commands`)
120 /// This lets the scheduler insert [`ApplyDeferred`](`crate::prelude::ApplyDeferred`) systems automatically.
121#[inline]
122pub fn set_has_deferred(&mut self) {
123self.flags |= SystemStateFlags::DEFERRED;
124 }
125126/// Mark the system to run exclusively. i.e. no other systems will run at the same time.
127pub fn set_exclusive(&mut self) {
128self.flags |= SystemStateFlags::EXCLUSIVE;
129 }
130}
131132// TODO: Actually use this in FunctionSystem. We should probably only do this once Systems are constructed using a World reference
133// (to avoid the need for unwrapping to retrieve SystemMeta)
134/// Holds on to persistent state required to drive [`SystemParam`] for a [`System`].
135///
136/// This is a powerful and convenient tool for working with exclusive world access,
137/// allowing you to fetch data from the [`World`] as if you were running a [`System`].
138/// However, simply calling `world::run_system(my_system)` using a [`World::run_system`](World::run_system)
139/// can be significantly simpler and ensures that change detection and command flushing work as expected.
140///
141/// Borrow-checking is handled for you, allowing you to mutably access multiple compatible system parameters at once,
142/// and arbitrary system parameters (like [`MessageWriter`](crate::message::MessageWriter)) can be conveniently fetched.
143///
144/// For an alternative approach to split mutable access to the world, see [`World::resource_scope`].
145///
146/// # Warning
147///
148/// [`SystemState`] values created can be cached to improve performance,
149/// and *must* be cached and reused in order for system parameters that rely on local state to work correctly.
150/// These include:
151/// - [`Added`](crate::query::Added), [`Changed`](crate::query::Changed) and [`Spawned`](crate::query::Spawned) query filters
152/// - [`Local`](crate::system::Local) variables that hold state
153/// - [`MessageReader`](crate::message::MessageReader) system parameters, which rely on a [`Local`](crate::system::Local) to track which messages have been seen
154///
155/// Note that this is automatically handled for you when using a [`World::run_system`](World::run_system).
156///
157/// # Example
158///
159/// Basic usage:
160/// ```
161/// # use bevy_ecs::prelude::*;
162/// # use bevy_ecs::system::SystemState;
163/// #
164/// # #[derive(Message)]
165/// # struct MyMessage;
166/// # #[derive(Resource)]
167/// # struct MyResource(u32);
168/// #
169/// # #[derive(Component)]
170/// # struct MyComponent;
171/// #
172/// // Work directly on the `World`
173/// let mut world = World::new();
174/// world.init_resource::<Messages<MyMessage>>();
175///
176/// // Construct a `SystemState` struct, passing in a tuple of `SystemParam`
177/// // as if you were writing an ordinary system.
178/// let mut system_state: SystemState<(
179/// MessageWriter<MyMessage>,
180/// Option<ResMut<MyResource>>,
181/// Query<&MyComponent>,
182/// )> = SystemState::new(&mut world);
183///
184/// // Use system_state.get_mut(&mut world) and unpack your system parameters into variables!
185/// // system_state.get(&world) provides read-only versions of your system parameters instead.
186/// let (message_writer, maybe_resource, query) = system_state.get_mut(&mut world).unwrap();
187///
188/// // If you are using `Commands`, you can choose when you want to apply them to the world.
189/// // You need to manually call `.apply(world)` on the `SystemState` to apply them.
190/// ```
191/// Caching:
192/// ```
193/// # use bevy_ecs::prelude::*;
194/// # use bevy_ecs::system::SystemState;
195/// # use bevy_ecs::message::Messages;
196/// #
197/// # #[derive(Message)]
198/// # struct MyMessage;
199/// #[derive(Resource)]
200/// struct CachedSystemState {
201/// message_state: SystemState<MessageReader<'static, 'static, MyMessage>>,
202/// }
203///
204/// // Create and store a system state once
205/// let mut world = World::new();
206/// world.init_resource::<Messages<MyMessage>>();
207/// let initial_state: SystemState<MessageReader<MyMessage>> = SystemState::new(&mut world);
208///
209/// // The system state is cached in a resource
210/// world.insert_resource(CachedSystemState {
211/// message_state: initial_state,
212/// });
213///
214/// // Later, fetch the cached system state, saving on overhead
215/// world.resource_scope(|world, mut cached_state: Mut<CachedSystemState>| {
216/// let mut message_reader = cached_state.message_state.get_mut(world).unwrap();
217///
218/// for message in message_reader.read() {
219/// println!("Hello World!");
220/// }
221/// });
222/// ```
223/// Exclusive System:
224/// ```
225/// # use bevy_ecs::prelude::*;
226/// # use bevy_ecs::system::SystemState;
227/// #
228/// # #[derive(Message)]
229/// # struct MyMessage;
230/// #
231/// fn exclusive_system(world: &mut World, system_state: &mut SystemState<MessageReader<MyMessage>>) {
232/// let mut message_reader = system_state.get_mut(world).unwrap();
233///
234/// for message in message_reader.read() {
235/// println!("Hello World!");
236/// }
237/// }
238/// ```
239pub struct SystemState<Param: SystemParam + 'static> {
240 meta: SystemMeta,
241 param_state: Param::State,
242 world_id: WorldId,
243}
244245// Allow closure arguments to be inferred.
246// For a closure to be used as a `SystemParamFunction`, it needs to be generic in any `'w` or `'s` lifetimes.
247// Rust will only infer a closure to be generic over lifetimes if it's passed to a function with a Fn constraint.
248// So, generate a function for each arity with an explicit `FnMut` constraint to enable higher-order lifetimes,
249// along with a regular `SystemParamFunction` constraint to allow the system to be built.
250macro_rules! impl_build_system {
251 ($(#[$meta:meta])* $($param: ident),*) => {
252 $(#[$meta])*
253impl<$($param: SystemParam),*> SystemState<($($param,)*)> {
254/// Create a [`FunctionSystem`] from a [`SystemState`].
255 /// This method signature allows type inference of closure parameters for a system with no input.
256 /// You can use [`SystemState::build_system_with_input()`] if you have input, or [`SystemState::build_any_system()`] if you don't need type inference.
257#[inline]
258pub fn build_system<
259 InnerOut: IntoResult<Out>,
260 Out,
261 Marker,
262 F: FnMut($(SystemParamItem<$param>),*) -> InnerOut
263 + SystemParamFunction<Marker, In = (), Out = InnerOut, Param = ($($param,)*)>
264 >
265 (
266self,
267 func: F,
268 ) -> FunctionSystem<Marker, (), Out, F>
269 {
270self.build_any_system(func)
271 }
272273/// Create a [`FunctionSystem`] from a [`SystemState`].
274 /// This method signature allows type inference of closure parameters for a system with input.
275 /// You can use [`SystemState::build_system()`] if you have no input, or [`SystemState::build_any_system()`] if you don't need type inference.
276#[inline]
277pub fn build_system_with_input<
278 InnerIn: SystemInput + FromInput<In>,
279 In: SystemInput,
280 InnerOut: IntoResult<Out>,
281 Out,
282 Marker,
283 F: FnMut(InnerIn, $(SystemParamItem<$param>),*) -> InnerOut
284 + SystemParamFunction<Marker, In = InnerIn, Out = InnerOut, Param = ($($param,)*)>
285 >
286 (
287self,
288 func: F,
289 ) -> FunctionSystem<Marker, In, Out, F> {
290self.build_any_system(func)
291 }
292 }
293 }
294}
295296#[doc(hidden)]
impl<P0: SystemParam, P1: SystemParam, P2: SystemParam, P3: SystemParam,
P4: SystemParam, P5: SystemParam, P6: SystemParam, P7: SystemParam,
P8: SystemParam, P9: SystemParam, P10: SystemParam, P11: SystemParam,
P12: SystemParam, P13: SystemParam, P14: SystemParam, P15: SystemParam>
SystemState<(P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13,
P14, P15)> {
/// Create a [`FunctionSystem`] from a [`SystemState`].
/// This method signature allows type inference of closure parameters for a system with no input.
/// You can use [`SystemState::build_system_with_input()`] if you have input, or [`SystemState::build_any_system()`] if you don't need type inference.
#[inline]
pub fn build_system<InnerOut: IntoResult<Out>, Out, Marker,
F: FnMut(SystemParamItem<P0>, SystemParamItem<P1>,
SystemParamItem<P2>, SystemParamItem<P3>, SystemParamItem<P4>,
SystemParamItem<P5>, SystemParamItem<P6>, SystemParamItem<P7>,
SystemParamItem<P8>, SystemParamItem<P9>, SystemParamItem<P10>,
SystemParamItem<P11>, SystemParamItem<P12>, SystemParamItem<P13>,
SystemParamItem<P14>, SystemParamItem<P15>) -> InnerOut +
SystemParamFunction<Marker, In = (), Out = InnerOut, Param =
(P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14,
P15)>>(self, func: F) -> FunctionSystem<Marker, (), Out, F> {
self.build_any_system(func)
}
/// Create a [`FunctionSystem`] from a [`SystemState`].
/// This method signature allows type inference of closure parameters for a system with input.
/// You can use [`SystemState::build_system()`] if you have no input, or [`SystemState::build_any_system()`] if you don't need type inference.
#[inline]
pub fn build_system_with_input<InnerIn: SystemInput + FromInput<In>,
In: SystemInput, InnerOut: IntoResult<Out>, Out, Marker,
F: FnMut(InnerIn, SystemParamItem<P0>, SystemParamItem<P1>,
SystemParamItem<P2>, SystemParamItem<P3>, SystemParamItem<P4>,
SystemParamItem<P5>, SystemParamItem<P6>, SystemParamItem<P7>,
SystemParamItem<P8>, SystemParamItem<P9>, SystemParamItem<P10>,
SystemParamItem<P11>, SystemParamItem<P12>, SystemParamItem<P13>,
SystemParamItem<P14>, SystemParamItem<P15>) -> InnerOut +
SystemParamFunction<Marker, In = InnerIn, Out = InnerOut, Param =
(P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14,
P15)>>(self, func: F) -> FunctionSystem<Marker, In, Out, F> {
self.build_any_system(func)
}
}all_tuples!(
297#[doc(fake_variadic)]
298impl_build_system,
2990,
30016,
301 P
302);
303304impl<Param: SystemParam> SystemState<Param> {
305/// Creates a new [`SystemState`] with default state.
306#[track_caller]
307pub fn new(world: &mut World) -> Self {
308let mut meta = SystemMeta::new::<Param>();
309meta.last_run = world.change_tick().relative_to(Tick::MAX);
310let param_state = Param::init_state(world);
311let mut component_access_set = FilteredAccessSet::new();
312// We need to call `init_access` to ensure there are no panics from conflicts within `Param`,
313 // even though we don't use the calculated access.
314Param::init_access(¶m_state, &mut meta, &mut component_access_set, world);
315Self {
316meta,
317param_state,
318 world_id: world.id(),
319 }
320 }
321322/// Create a [`SystemState`] from a [`SystemParamBuilder`]
323pub(crate) fn from_builder(world: &mut World, builder: impl SystemParamBuilder<Param>) -> Self {
324let mut meta = SystemMeta::new::<Param>();
325meta.last_run = world.change_tick().relative_to(Tick::MAX);
326let param_state = builder.build(world);
327let mut component_access_set = FilteredAccessSet::new();
328// We need to call `init_access` to ensure there are no panics from conflicts within `Param`,
329 // even though we don't use the calculated access.
330Param::init_access(¶m_state, &mut meta, &mut component_access_set, world);
331Self {
332meta,
333param_state,
334 world_id: world.id(),
335 }
336 }
337338/// Create a [`FunctionSystem`] from a [`SystemState`].
339 /// This method signature allows any system function, but the compiler will not perform type inference on closure parameters.
340 /// You can use [`SystemState::build_system()`] or [`SystemState::build_system_with_input()`] to get type inference on parameters.
341#[inline]
342pub fn build_any_system<Marker, In, Out, F>(self, func: F) -> FunctionSystem<Marker, In, Out, F>
343where
344In: SystemInput,
345 F: SystemParamFunction<Marker, In: FromInput<In>, Out: IntoResult<Out>, Param = Param>,
346 {
347FunctionSystem::new(
348func,
349self.meta,
350Some(FunctionSystemState {
351 param: self.param_state,
352 world_id: self.world_id,
353 }),
354 )
355 }
356357/// Gets the metadata for this instance.
358#[inline]
359pub fn meta(&self) -> &SystemMeta {
360&self.meta
361 }
362363/// Gets the metadata for this instance.
364#[inline]
365pub fn meta_mut(&mut self) -> &mut SystemMeta {
366&mut self.meta
367 }
368369/// Retrieve the [`SystemParam`] values. This can only be called when all parameters are read-only.
370 ///
371 /// Returns an error if system parameter validation fails.
372#[inline]
373pub fn get<'w, 's>(
374&'s mut self,
375 world: &'w World,
376 ) -> Result<SystemParamItem<'w, 's, Param>, SystemParamValidationError>
377where
378Param: ReadOnlySystemParam,
379 {
380self.validate_world(world.id());
381// SAFETY: Param is read-only and doesn't allow mutable access to World.
382 // It also matches the World this SystemState was created with.
383unsafe { self.get_unchecked(world.as_unsafe_world_cell_readonly()) }
384 }
385386/// Retrieve the mutable [`SystemParam`] values.
387 ///
388 /// Returns an error if system parameter validation fails.
389#[inline]
390 #[track_caller]
391pub fn get_mut<'w, 's>(
392&'s mut self,
393 world: &'w mut World,
394 ) -> Result<SystemParamItem<'w, 's, Param>, SystemParamValidationError> {
395self.validate_world(world.id());
396// SAFETY: World is uniquely borrowed and matches the World this SystemState was created with.
397unsafe { self.get_unchecked(world.as_unsafe_world_cell()) }
398 }
399400/// Applies all state queued up for [`SystemParam`] values. For example, this will apply commands queued up
401 /// by a [`Commands`](`super::Commands`) parameter to the given [`World`].
402 /// This function should be called manually after the values returned by [`SystemState::get`] and [`SystemState::get_mut`]
403 /// are finished being used.
404pub fn apply(&mut self, world: &mut World) {
405 Param::apply(&mut self.param_state, &self.meta, world);
406 }
407408/// Returns `true` if `world_id` matches the [`World`] that was used to call [`SystemState::new`].
409 /// Otherwise, this returns false.
410#[inline]
411pub fn matches_world(&self, world_id: WorldId) -> bool {
412self.world_id == world_id413 }
414415/// Asserts that the [`SystemState`] matches the provided world.
416#[inline]
417 #[track_caller]
418fn validate_world(&self, world_id: WorldId) {
419#[inline(never)]
420 #[track_caller]
421 #[cold]
422fn panic_mismatched(this: WorldId, other: WorldId) -> ! {
423{
::core::panicking::panic_fmt(format_args!("Encountered a mismatched World. This SystemState was created from {0:?}, but a method was called using {1:?}.",
this, other));
};panic!("Encountered a mismatched World. This SystemState was created from {this:?}, but a method was called using {other:?}.");
424 }
425426if !self.matches_world(world_id) {
427panic_mismatched(self.world_id, world_id);
428 }
429 }
430431/// Retrieve the [`SystemParam`] values.
432 ///
433 /// Returns an error if system parameter validation fails.
434 ///
435 /// # Safety
436 /// This call might access any of the input parameters in a way that violates Rust's mutability rules. Make sure the data
437 /// access is safe in the context of global [`World`] access. The passed-in [`World`] _must_ be the [`World`] the [`SystemState`] was
438 /// created with.
439#[inline]
440 #[track_caller]
441pub unsafe fn get_unchecked<'w, 's>(
442&'s mut self,
443 world: UnsafeWorldCell<'w>,
444 ) -> Result<SystemParamItem<'w, 's, Param>, SystemParamValidationError> {
445let change_tick = world.increment_change_tick();
446// SAFETY: The invariants are upheld by the caller.
447unsafe { self.fetch(world, change_tick) }
448 }
449450/// # Safety
451 /// This call might access any of the input parameters in a way that violates Rust's mutability rules. Make sure the data
452 /// access is safe in the context of global [`World`] access. The passed-in [`World`] _must_ be the [`World`] the [`SystemState`] was
453 /// created with.
454#[inline]
455 #[track_caller]
456unsafe fn fetch<'w, 's>(
457&'s mut self,
458 world: UnsafeWorldCell<'w>,
459 change_tick: Tick,
460 ) -> Result<SystemParamItem<'w, 's, Param>, SystemParamValidationError> {
461// SAFETY: The invariants are upheld by the caller.
462let param =
463unsafe { Param::get_param(&mut self.param_state, &self.meta, world, change_tick) }?;
464self.meta.last_run = change_tick;
465Ok(param)
466 }
467468/// Returns a reference to the current system param states.
469pub fn param_state(&self) -> &Param::State {
470&self.param_state
471 }
472473/// Returns a mutable reference to the current system param states.
474 /// Marked as unsafe because modifying the system states may result in violation to certain
475 /// assumptions made by the [`SystemParam`]. Use with care.
476 ///
477 /// # Safety
478 /// Modifying the system param states may have unintended consequences.
479 /// The param state is generally considered to be owned by the [`SystemParam`]. Modifications
480 /// should respect any invariants as required by the [`SystemParam`].
481 /// For example, modifying the system state of [`ResMut`](crate::system::ResMut) will obviously create issues.
482pub unsafe fn param_state_mut(&mut self) -> &mut Param::State {
483&mut self.param_state
484 }
485}
486487impl<Param: SystemParam> FromWorldfor SystemState<Param> {
488fn from_world(world: &mut World) -> Self {
489Self::new(world)
490 }
491}
492493/// The [`System`] counter part of an ordinary function.
494///
495/// You get this by calling [`IntoSystem::into_system`] on a function that only accepts
496/// [`SystemParam`]s. The output of the system becomes the functions return type, while the input
497/// becomes the functions first parameter or `()` if no such parameter exists.
498///
499/// [`FunctionSystem`] must be `.initialized` before they can be run.
500///
501/// The [`Clone`] implementation for [`FunctionSystem`] returns a new instance which
502/// is NOT initialized. The cloned system must also be `.initialized` before it can be run.
503pub struct FunctionSystem<Marker, In, Out, F>
504where
505F: SystemParamFunction<Marker>,
506{
507 func: F,
508#[cfg(feature = "hotpatching")]
509current_ptr: subsecond::HotFnPtr,
510 state: Option<FunctionSystemState<F::Param>>,
511 system_meta: SystemMeta,
512// NOTE: PhantomData<fn()-> T> gives this safe Send/Sync impls
513marker: PhantomData<fn(In) -> (Marker, Out)>,
514}
515516/// The state of a [`FunctionSystem`], which must be initialized with
517/// [`System::initialize`] before the system can be run. A panic will occur if
518/// the system is run without being initialized.
519struct FunctionSystemState<P: SystemParam> {
520/// The cached state of the system's [`SystemParam`]s.
521param: P::State,
522/// The id of the [`World`] this system was initialized with. If the world
523 /// passed to [`System::run_unsafe`] does not match
524 /// this id, a panic will occur.
525world_id: WorldId,
526}
527528impl<Marker, In, Out, F> FunctionSystem<Marker, In, Out, F>
529where
530F: SystemParamFunction<Marker>,
531{
532#[inline]
533fn new(func: F, system_meta: SystemMeta, state: Option<FunctionSystemState<F::Param>>) -> Self {
534Self {
535func,
536#[cfg(feature = "hotpatching")]
537current_ptr: subsecond::HotFn::current(<F as SystemParamFunction<Marker>>::run)
538 .ptr_address(),
539state,
540system_meta,
541 marker: PhantomData,
542 }
543 }
544545/// Return this system with a new name.
546 ///
547 /// Useful to give closure systems more readable and unique names for debugging and tracing.
548pub fn with_name(mut self, new_name: impl Into<Cow<'static, str>>) -> Self {
549self.system_meta.set_name(new_name.into());
550self551 }
552}
553554// De-initializes the cloned system.
555impl<Marker, In, Out, F> Clonefor FunctionSystem<Marker, In, Out, F>
556where
557F: SystemParamFunction<Marker> + Clone,
558{
559fn clone(&self) -> Self {
560Self {
561 func: self.func.clone(),
562#[cfg(feature = "hotpatching")]
563current_ptr: subsecond::HotFn::current(<F as SystemParamFunction<Marker>>::run)
564 .ptr_address(),
565 state: None,
566 system_meta: SystemMeta::new::<F>(),
567 marker: PhantomData,
568 }
569 }
570}
571572/// A marker type used to distinguish regular function systems from exclusive function systems.
573#[doc(hidden)]
574pub struct IsFunctionSystem;
575576impl<Marker, In, Out, F> IntoSystem<In, Out, (IsFunctionSystem, Marker)> for F
577where
578Marker: 'static,
579 In: SystemInput + 'static,
580 Out: 'static,
581 F: SystemParamFunction<Marker, In: FromInput<In>, Out: IntoResult<Out>>,
582{
583type System = FunctionSystem<Marker, In, Out, F>;
584fn into_system(func: Self) -> Self::System {
585FunctionSystem::new(func, SystemMeta::new::<F>(), None)
586 }
587}
588589/// A type that may be converted to the output of a [`System`].
590/// This is used to allow systems to return either a plain value or a [`Result`].
591pub trait IntoResult<Out>: Sized {
592/// Converts this type into the system output type.
593fn into_result(self) -> Result<Out, RunSystemError>;
594}
595596impl<T> IntoResult<T> for T {
597fn into_result(self) -> Result<T, RunSystemError> {
598Ok(self)
599 }
600}
601602impl<T> IntoResult<T> for Result<T, RunSystemError> {
603fn into_result(self) -> Result<T, RunSystemError> {
604self605 }
606}
607608impl<T> IntoResult<T> for Result<T, BevyError> {
609fn into_result(self) -> Result<T, RunSystemError> {
610Ok(self?)
611 }
612}
613614// The `!` impl can't be generic in `Out`, since that would overlap with
615// `impl<T> IntoResult<T> for T` when `T` = `!`.
616// Use explicit impls for `()` and `bool` so diverging functions
617// can be used for systems and conditions.
618impl IntoResult<()> for Never {
619fn into_result(self) -> Result<(), RunSystemError> {
620self621 }
622}
623624impl IntoResult<bool> for Never {
625fn into_result(self) -> Result<bool, RunSystemError> {
626self627 }
628}
629630impl<Marker, In, Out, F> FunctionSystem<Marker, In, Out, F>
631where
632F: SystemParamFunction<Marker>,
633{
634/// Message shown when a system isn't initialized
635// When lines get too long, rustfmt can sometimes refuse to format them.
636 // Work around this by storing the message separately.
637const ERROR_UNINITIALIZED: &'static str =
638"System's state was not found. Did you forget to initialize this system before running it?";
639}
640641impl<Marker, In, Out, F> Systemfor FunctionSystem<Marker, In, Out, F>
642where
643Marker: 'static,
644 In: SystemInput + 'static,
645 Out: 'static,
646 F: SystemParamFunction<Marker, In: FromInput<In>, Out: IntoResult<Out>>,
647{
648type In = In;
649type Out = Out;
650651#[inline]
652fn name(&self) -> DebugName {
653self.system_meta.name.clone()
654 }
655656#[inline]
657fn flags(&self) -> SystemStateFlags {
658self.system_meta.flags
659 }
660661#[inline]
662unsafe fn run_unsafe(
663&mut self,
664 input: SystemIn<'_, Self>,
665 world: UnsafeWorldCell,
666 ) -> Result<Self::Out, RunSystemError> {
667#[cfg(feature = "trace")]
668let _span_guard = self.system_meta.system_span.enter();
669670let change_tick = world.increment_change_tick();
671672let input = F::In::from_inner(input);
673674let state = self.state.as_mut().expect(Self::ERROR_UNINITIALIZED);
675match (&state.world_id, &world.id()) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val, &*right_val,
::core::option::Option::Some(format_args!("Encountered a mismatched World. A System cannot be used with Worlds other than the one it was initialized with.")));
}
}
};assert_eq!(state.world_id, world.id(), "Encountered a mismatched World. A System cannot be used with Worlds other than the one it was initialized with.");
676// SAFETY:
677 // - The above assert ensures the world matches.
678 // - All world accesses used by `F::Param` have been registered, so the caller
679 // will ensure that there are no data access conflicts.
680let params = unsafe {
681 F::Param::get_param(&mut state.param, &self.system_meta, world, change_tick)
682 }?;
683684#[cfg(feature = "hotpatching")]
685let out = {
686let mut hot_fn = subsecond::HotFn::current(<F as SystemParamFunction<Marker>>::run);
687// SAFETY:
688 // - pointer used to call is from the current jump table
689unsafe {
690hot_fn691 .try_call_with_ptr(self.current_ptr, (&mut self.func, input, params))
692 .expect("Error calling hotpatched system. Run a full rebuild")
693 }
694 };
695#[cfg(not(feature = "hotpatching"))]
696let out = self.func.run(input, params);
697698self.system_meta.last_run = change_tick;
699 IntoResult::into_result(out)
700 }
701702#[cfg(feature = "hotpatching")]
703 #[inline]
704fn refresh_hotpatch(&mut self) {
705let new = subsecond::HotFn::current(<F as SystemParamFunction<Marker>>::run).ptr_address();
706if new != self.current_ptr {
707{
{
let lvl = ::log::Level::Debug;
if lvl <= ::log::STATIC_MAX_LEVEL && lvl <= ::log::max_level() {
::log::__private_api::log({ ::log::__private_api::GlobalLogger },
format_args!("system {0} hotpatched", self.name()), lvl,
&("bevy_ecs::system::function_system",
"bevy_ecs::system::function_system",
::log::__private_api::loc()), ());
}
}
};log::debug!("system {} hotpatched", self.name());
708 }
709self.current_ptr = new;
710 }
711712#[inline]
713fn apply_deferred(&mut self, world: &mut World) {
714let param_state = &mut self.state.as_mut().expect(Self::ERROR_UNINITIALIZED).param;
715 F::Param::apply(param_state, &self.system_meta, world);
716 }
717718#[inline]
719fn queue_deferred(&mut self, world: DeferredWorld) {
720let param_state = &mut self.state.as_mut().expect(Self::ERROR_UNINITIALIZED).param;
721 F::Param::queue(param_state, &self.system_meta, world);
722 }
723724#[inline]
725fn initialize(&mut self, world: &mut World) -> FilteredAccessSet {
726if let Some(state) = &self.state {
727match (&state.world_id, &world.id()) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val, &*right_val,
::core::option::Option::Some(format_args!("System built with a different world than the one it was added to.")));
}
}
};assert_eq!(
728 state.world_id,
729 world.id(),
730"System built with a different world than the one it was added to.",
731 );
732 }
733let state = self.state.get_or_insert_with(|| FunctionSystemState {
734 param: F::Param::init_state(world),
735 world_id: world.id(),
736 });
737self.system_meta.last_run = world.change_tick().relative_to(Tick::MAX);
738let mut component_access_set = FilteredAccessSet::new();
739 F::Param::init_access(
740&state.param,
741&mut self.system_meta,
742&mut component_access_set,
743world,
744 );
745component_access_set746 }
747748#[inline]
749fn check_change_tick(&mut self, check: CheckChangeTicks) {
750check_system_change_tick(
751&mut self.system_meta.last_run,
752check,
753self.system_meta.name.clone(),
754 );
755 }
756757fn default_system_sets(&self) -> Vec<InternedSystemSet> {
758let set = crate::schedule::SystemTypeSet::<F>::new();
759::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
[set.intern()]))vec![set.intern()]760 }
761762fn get_last_run(&self) -> Tick {
763self.system_meta.last_run
764 }
765766fn set_last_run(&mut self, last_run: Tick) {
767self.system_meta.last_run = last_run;
768 }
769}
770771// SAFETY: `F`'s param is [`ReadOnlySystemParam`], so this system will only read from the world.
772unsafe impl<Marker, In, Out, F> ReadOnlySystemfor FunctionSystem<Marker, In, Out, F>
773where
774Marker: 'static,
775 In: SystemInput + 'static,
776 Out: 'static,
777 F: SystemParamFunction<
778 Marker,
779 In: FromInput<In>,
780 Out: IntoResult<Out>,
781 Param: ReadOnlySystemParam,
782 >,
783{
784}
785786/// A trait implemented for all functions that can be used as [`System`]s.
787///
788/// This trait can be useful for making your own systems which accept other systems,
789/// sometimes called higher order systems.
790///
791/// This should be used in combination with [`ParamSet`] when calling other systems
792/// within your system.
793/// Using [`ParamSet`] in this case avoids [`SystemParam`] collisions.
794///
795/// # Example
796///
797/// To create something like [`PipeSystem`], but in entirely safe code.
798///
799/// ```
800/// use std::num::ParseIntError;
801///
802/// use bevy_ecs::prelude::*;
803/// use bevy_ecs::system::StaticSystemInput;
804///
805/// /// Pipe creates a new system which calls `a`, then calls `b` with the output of `a`
806/// pub fn pipe<A, B, AMarker, BMarker>(
807/// mut a: A,
808/// mut b: B,
809/// ) -> impl FnMut(StaticSystemInput<A::In>, ParamSet<(A::Param, B::Param)>) -> B::Out
810/// where
811/// // We need A and B to be systems, add those bounds
812/// A: SystemParamFunction<AMarker>,
813/// B: SystemParamFunction<BMarker>,
814/// for<'a> B::In: SystemInput<Inner<'a> = A::Out>,
815/// {
816/// // The type of `params` is inferred based on the return of this function above
817/// move |StaticSystemInput(a_in), mut params| {
818/// let shared = a.run(a_in, params.p0());
819/// b.run(shared, params.p1())
820/// }
821/// }
822///
823/// // Usage example for `pipe`:
824/// fn main() {
825/// let mut world = World::default();
826/// world.insert_resource(Message("42".to_string()));
827///
828/// // pipe the `parse_message_system`'s output into the `filter_system`s input.
829/// // Type annotations should only needed when using `StaticSystemInput` as input
830/// // AND the input type isn't constrained by nearby code.
831/// let mut piped_system = IntoSystem::<(), Option<usize>, _>::into_system(pipe(parse_message, filter));
832/// piped_system.initialize(&mut world);
833/// assert_eq!(piped_system.run((), &mut world).unwrap(), Some(42));
834/// }
835///
836/// #[derive(Resource)]
837/// struct Message(String);
838///
839/// fn parse_message(message: Res<Message>) -> Result<usize, ParseIntError> {
840/// message.0.parse::<usize>()
841/// }
842///
843/// fn filter(In(result): In<Result<usize, ParseIntError>>) -> Option<usize> {
844/// result.ok().filter(|&n| n < 100)
845/// }
846/// ```
847/// [`PipeSystem`]: crate::system::PipeSystem
848/// [`ParamSet`]: crate::system::ParamSet
849#[diagnostic::on_unimplemented(
850 message = "`{Self}` is not a valid system",
851 label = "invalid system"
852)]
853pub trait SystemParamFunction<Marker>: Send + Sync + 'static {
854/// The input type of this system. See [`System::In`].
855type In: SystemInput;
856/// The return type of this system. See [`System::Out`].
857type Out;
858859/// The [`SystemParam`]/s used by this system to access the [`World`].
860type Param: SystemParam;
861862/// Executes this system once. See [`System::run`] or [`System::run_unsafe`].
863fn run(
864&mut self,
865 input: <Self::In as SystemInput>::Inner<'_>,
866 param_value: SystemParamItem<Self::Param>,
867 ) -> Self::Out;
868}
869870/// A marker type used to distinguish function systems with and without input.
871#[doc(hidden)]
872pub struct HasSystemInput;
873874macro_rules! impl_system_function {
875 ($($param: ident),*) => {
876#[expect(
877 clippy::allow_attributes,
878 reason = "This is within a macro, and as such, the below lints may not always apply."
879)]
880 #[allow(
881 non_snake_case,
882 reason = "Certain variable names are provided by the caller, not by us."
883)]
884impl<Out, Func, $($param: SystemParam),*> SystemParamFunction<fn($($param,)*) -> Out> for Func
885where
886Func: Send + Sync + 'static,
887for <'a> &'a mut Func:
888 FnMut($($param),*) -> Out +
889 FnMut($(SystemParamItem<$param>),*) -> Out,
890 Out: 'static
891{
892type In = ();
893type Out = Out;
894type Param = ($($param,)*);
895#[inline]
896fn run(&mut self, _input: (), param_value: SystemParamItem< ($($param,)*)>) -> Out {
897// Yes, this is strange, but `rustc` fails to compile this impl
898 // without using this function. It fails to recognize that `func`
899 // is a function, potentially because of the multiple impls of `FnMut`
900fn call_inner<Out, $($param,)*>(
901mut f: impl FnMut($($param,)*)->Out,
902 $($param: $param,)*
903 )->Out{
904 f($($param,)*)
905 }
906let ($($param,)*) = param_value;
907 call_inner(self, $($param),*)
908 }
909 }
910911#[expect(
912 clippy::allow_attributes,
913 reason = "This is within a macro, and as such, the below lints may not always apply."
914)]
915 #[allow(
916 non_snake_case,
917 reason = "Certain variable names are provided by the caller, not by us."
918)]
919impl<In, Out, Func, $($param: SystemParam),*> SystemParamFunction<(HasSystemInput, fn(In, $($param,)*) -> Out)> for Func
920where
921Func: Send + Sync + 'static,
922for <'a> &'a mut Func:
923 FnMut(In, $($param),*) -> Out +
924 FnMut(In::Param<'_>, $(SystemParamItem<$param>),*) -> Out,
925 In: SystemInput + 'static,
926 Out: 'static
927{
928type In = In;
929type Out = Out;
930type Param = ($($param,)*);
931#[inline]
932fn run(&mut self, input: In::Inner<'_>, param_value: SystemParamItem< ($($param,)*)>) -> Out {
933fn call_inner<In: SystemInput, Out, $($param,)*>(
934_: PhantomData<In>,
935mut f: impl FnMut(In::Param<'_>, $($param,)*)->Out,
936 input: In::Inner<'_>,
937 $($param: $param,)*
938 )->Out{
939 f(In::wrap(input), $($param,)*)
940 }
941let ($($param,)*) = param_value;
942 call_inner(PhantomData::<In>, self, input, $($param),*)
943 }
944 }
945 };
946}
947948// Note that we rely on the highest impl to be <= the highest order of the tuple impls
949// of `SystemParam` created.
950#[expect(clippy :: allow_attributes, reason =
"This is within a macro, and as such, the below lints may not always apply.")]
#[allow(non_snake_case, reason =
"Certain variable names are provided by the caller, not by us.")]
impl<Out, Func, F0: SystemParam, F1: SystemParam, F2: SystemParam,
F3: SystemParam, F4: SystemParam, F5: SystemParam, F6: SystemParam,
F7: SystemParam, F8: SystemParam, F9: SystemParam, F10: SystemParam,
F11: SystemParam, F12: SystemParam, F13: SystemParam, F14: SystemParam,
F15: SystemParam>
SystemParamFunction<fn(F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11,
F12, F13, F14, F15) -> Out> for Func where Func: Send + Sync +
'static,
for<'a> &'a mut Func: FnMut(F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10,
F11, F12, F13, F14, F15) -> Out +
FnMut(SystemParamItem<F0>, SystemParamItem<F1>, SystemParamItem<F2>,
SystemParamItem<F3>, SystemParamItem<F4>, SystemParamItem<F5>,
SystemParamItem<F6>, SystemParamItem<F7>, SystemParamItem<F8>,
SystemParamItem<F9>, SystemParamItem<F10>, SystemParamItem<F11>,
SystemParamItem<F12>, SystemParamItem<F13>, SystemParamItem<F14>,
SystemParamItem<F15>) -> Out, Out: 'static {
type In = ();
type Out = Out;
type Param =
(F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14,
F15);
#[inline]
fn run(&mut self, _input: (),
param_value:
SystemParamItem<(F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11,
F12, F13, F14, F15)>) -> Out {
fn call_inner<Out, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11,
F12, F13, F14,
F15>(mut f:
impl FnMut(F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11,
F12, F13, F14, F15) -> Out, F0: F0, F1: F1, F2: F2, F3: F3,
F4: F4, F5: F5, F6: F6, F7: F7, F8: F8, F9: F9, F10: F10,
F11: F11, F12: F12, F13: F13, F14: F14, F15: F15) -> Out {
f(F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14,
F15)
}
let (F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14,
F15) = param_value;
call_inner(self, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11,
F12, F13, F14, F15)
}
}
#[expect(clippy :: allow_attributes, reason =
"This is within a macro, and as such, the below lints may not always apply.")]
#[allow(non_snake_case, reason =
"Certain variable names are provided by the caller, not by us.")]
impl<In, Out, Func, F0: SystemParam, F1: SystemParam, F2: SystemParam,
F3: SystemParam, F4: SystemParam, F5: SystemParam, F6: SystemParam,
F7: SystemParam, F8: SystemParam, F9: SystemParam, F10: SystemParam,
F11: SystemParam, F12: SystemParam, F13: SystemParam, F14: SystemParam,
F15: SystemParam>
SystemParamFunction<(HasSystemInput,
fn(In, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14,
F15) -> Out)> for Func where Func: Send + Sync + 'static,
for<'a> &'a mut Func: FnMut(In, F0, F1, F2, F3, F4, F5, F6, F7, F8, F9,
F10, F11, F12, F13, F14, F15) -> Out +
FnMut(In::Param<'_>, SystemParamItem<F0>, SystemParamItem<F1>,
SystemParamItem<F2>, SystemParamItem<F3>, SystemParamItem<F4>,
SystemParamItem<F5>, SystemParamItem<F6>, SystemParamItem<F7>,
SystemParamItem<F8>, SystemParamItem<F9>, SystemParamItem<F10>,
SystemParamItem<F11>, SystemParamItem<F12>, SystemParamItem<F13>,
SystemParamItem<F14>, SystemParamItem<F15>) -> Out, In: SystemInput +
'static, Out: 'static {
type In = In;
type Out = Out;
type Param =
(F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14,
F15);
#[inline]
fn run(&mut self, input: In::Inner<'_>,
param_value:
SystemParamItem<(F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11,
F12, F13, F14, F15)>) -> Out {
fn call_inner<In: SystemInput, Out, F0, F1, F2, F3, F4, F5, F6, F7,
F8, F9, F10, F11, F12, F13, F14,
F15>(_: PhantomData<In>,
mut f:
impl FnMut(In::Param<'_>, F0, F1, F2, F3, F4, F5, F6, F7, F8,
F9, F10, F11, F12, F13, F14, F15) -> Out,
input: In::Inner<'_>, F0: F0, F1: F1, F2: F2, F3: F3, F4: F4,
F5: F5, F6: F6, F7: F7, F8: F8, F9: F9, F10: F10, F11: F11,
F12: F12, F13: F13, F14: F14, F15: F15) -> Out {
f(In::wrap(input), F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10,
F11, F12, F13, F14, F15)
}
let (F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14,
F15) = param_value;
call_inner(PhantomData::<In>, self, input, F0, F1, F2, F3, F4, F5, F6,
F7, F8, F9, F10, F11, F12, F13, F14, F15)
}
}all_tuples!(impl_system_function, 0, 16, F);
951952#[cfg(test)]
953mod tests {
954use super::*;
955956#[test]
957fn into_system_type_id_consistency() {
958fn test<T, In: SystemInput, Out, Marker>(function: T)
959where
960T: IntoSystem<In, Out, Marker> + Copy,
961 {
962fn reference_system() {}
963964use core::any::TypeId;
965966let system = IntoSystem::into_system(function);
967968assert_eq!(
969 system.system_type(),
970 function.system_type_id(),
971"System::system_type should be consistent with IntoSystem::system_type_id"
972);
973974assert_eq!(
975 system.system_type(),
976 TypeId::of::<T::System>(),
977"System::system_type should be consistent with TypeId::of::<T::System>()"
978);
979980assert_ne!(
981 system.system_type(),
982 IntoSystem::into_system(reference_system).system_type(),
983"Different systems should have different TypeIds"
984);
985 }
986987fn function_system() {}
988989 test(function_system);
990 }
991}