Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_ecs/src/system/system_param.rs
9550 views
1
#![expect(
2
unsafe_op_in_unsafe_fn,
3
reason = "See #11590. To be removed once all applicable unsafe code has an unsafe block with a safety comment."
4
)]
5
6
pub use crate::change_detection::{NonSend, NonSendMut, Res, ResMut};
7
use crate::{
8
archetype::Archetypes,
9
bundle::Bundles,
10
change_detection::{ComponentTicksMut, ComponentTicksRef, Tick},
11
component::{ComponentId, Components},
12
entity::{Entities, EntityAllocator},
13
query::{
14
Access, FilteredAccess, FilteredAccessSet, QueryData, QueryFilter, QuerySingleError,
15
QueryState, ReadOnlyQueryData,
16
},
17
resource::{Resource, IS_RESOURCE},
18
storage::NonSendData,
19
system::{Query, Single, SystemMeta},
20
world::{
21
unsafe_world_cell::UnsafeWorldCell, DeferredWorld, FilteredResources, FilteredResourcesMut,
22
FromWorld, World,
23
},
24
};
25
use alloc::{borrow::Cow, boxed::Box, vec::Vec};
26
pub use bevy_ecs_macros::SystemParam;
27
use bevy_platform::cell::SyncCell;
28
use bevy_ptr::UnsafeCellDeref;
29
use bevy_utils::prelude::DebugName;
30
use core::{
31
any::Any,
32
fmt::{Debug, Display},
33
marker::PhantomData,
34
ops::{Deref, DerefMut},
35
};
36
use thiserror::Error;
37
38
use super::Populated;
39
use variadics_please::{all_tuples, all_tuples_enumerated};
40
41
/// A parameter that can be used in a [`System`](super::System).
42
///
43
/// # Derive
44
///
45
/// This trait can be derived with the [`derive@super::SystemParam`] macro.
46
/// This macro only works if each field on the derived struct implements [`SystemParam`].
47
/// Note: There are additional requirements on the field types.
48
/// See the *Generic `SystemParam`s* section for details and workarounds of the probable
49
/// cause if this derive causes an error to be emitted.
50
///
51
/// Derived `SystemParam` structs may have two lifetimes: `'w` for data stored in the [`World`],
52
/// and `'s` for data stored in the parameter's state.
53
///
54
/// The following list shows the most common [`SystemParam`]s and which lifetime they require
55
///
56
/// ```
57
/// # use bevy_ecs::prelude::*;
58
/// # #[derive(Component)]
59
/// # struct SomeComponent;
60
/// # #[derive(Resource)]
61
/// # struct SomeResource;
62
/// # #[derive(Message)]
63
/// # struct SomeMessage;
64
/// # #[derive(Resource)]
65
/// # struct SomeOtherResource;
66
/// # use bevy_ecs::system::SystemParam;
67
/// # #[derive(SystemParam)]
68
/// # struct ParamsExample<'w, 's> {
69
/// # query:
70
/// Query<'w, 's, Entity>,
71
/// # query2:
72
/// Query<'w, 's, &'static SomeComponent>,
73
/// # res:
74
/// Res<'w, SomeResource>,
75
/// # res_mut:
76
/// ResMut<'w, SomeOtherResource>,
77
/// # local:
78
/// Local<'s, u8>,
79
/// # commands:
80
/// Commands<'w, 's>,
81
/// # message_reader:
82
/// MessageReader<'w, 's, SomeMessage>,
83
/// # message_writer:
84
/// MessageWriter<'w, SomeMessage>
85
/// # }
86
/// ```
87
/// ## `PhantomData`
88
///
89
/// [`PhantomData`] is a special type of `SystemParam` that does nothing.
90
/// This is useful for constraining generic types or lifetimes.
91
///
92
/// # Example
93
///
94
/// ```
95
/// # use bevy_ecs::prelude::*;
96
/// # #[derive(Resource)]
97
/// # struct SomeResource;
98
/// use std::marker::PhantomData;
99
/// use bevy_ecs::system::SystemParam;
100
///
101
/// #[derive(SystemParam)]
102
/// struct MyParam<'w, Marker: 'static> {
103
/// foo: Res<'w, SomeResource>,
104
/// marker: PhantomData<Marker>,
105
/// }
106
///
107
/// fn my_system<T: 'static>(param: MyParam<T>) {
108
/// // Access the resource through `param.foo`
109
/// }
110
///
111
/// # bevy_ecs::system::assert_is_system(my_system::<()>);
112
/// ```
113
///
114
/// # Generic `SystemParam`s
115
///
116
/// When using the derive macro, you may see an error in the form of:
117
///
118
/// ```text
119
/// expected ... [ParamType]
120
/// found associated type `<[ParamType] as SystemParam>::Item<'_, '_>`
121
/// ```
122
/// where `[ParamType]` is the type of one of your fields.
123
/// To solve this error, you can wrap the field of type `[ParamType]` with [`StaticSystemParam`]
124
/// (i.e. `StaticSystemParam<[ParamType]>`).
125
///
126
/// ## Details
127
///
128
/// The derive macro requires that the [`SystemParam`] implementation of
129
/// each field `F`'s [`Item`](`SystemParam::Item`)'s is itself `F`
130
/// (ignoring lifetimes for simplicity).
131
/// This assumption is due to type inference reasons, so that the derived [`SystemParam`] can be
132
/// used as an argument to a function system.
133
/// If the compiler cannot validate this property for `[ParamType]`, it will error in the form shown above.
134
///
135
/// This will most commonly occur when working with `SystemParam`s generically, as the requirement
136
/// has not been proven to the compiler.
137
///
138
/// ## Custom Validation Messages
139
///
140
/// When using the derive macro, any [`SystemParamValidationError`]s will be propagated from the sub-parameters.
141
/// If you want to override the error message, add a `#[system_param(validation_message = "New message")]` attribute to the parameter.
142
///
143
/// ```
144
/// # use bevy_ecs::prelude::*;
145
/// # #[derive(Resource)]
146
/// # struct SomeResource;
147
/// # use bevy_ecs::system::SystemParam;
148
/// #
149
/// #[derive(SystemParam)]
150
/// struct MyParam<'w> {
151
/// #[system_param(validation_message = "Custom Message")]
152
/// foo: Res<'w, SomeResource>,
153
/// }
154
///
155
/// let mut world = World::new();
156
/// let err = world.run_system_cached(|param: MyParam| {}).unwrap_err();
157
/// let expected = "Parameter `MyParam::foo` failed validation: Custom Message";
158
/// # #[cfg(feature="Trace")] // Without debug_utils/debug enabled MyParam::foo is stripped and breaks the assert
159
/// assert!(err.to_string().contains(expected));
160
/// ```
161
///
162
/// ## Builders
163
///
164
/// If you want to use a [`SystemParamBuilder`](crate::system::SystemParamBuilder) with a derived [`SystemParam`] implementation,
165
/// add a `#[system_param(builder)]` attribute to the struct.
166
/// This will generate a builder struct whose name is the param struct suffixed with `Builder`.
167
/// The builder will not be `pub`, so you may want to expose a method that returns an `impl SystemParamBuilder<T>`.
168
///
169
/// ```
170
/// mod custom_param {
171
/// # use bevy_ecs::{
172
/// # prelude::*,
173
/// # system::{LocalBuilder, QueryParamBuilder, SystemParam},
174
/// # };
175
/// #
176
/// #[derive(SystemParam)]
177
/// #[system_param(builder)]
178
/// pub struct CustomParam<'w, 's> {
179
/// query: Query<'w, 's, ()>,
180
/// local: Local<'s, usize>,
181
/// }
182
///
183
/// impl<'w, 's> CustomParam<'w, 's> {
184
/// pub fn builder(
185
/// local: usize,
186
/// query: impl FnOnce(&mut QueryBuilder<()>),
187
/// ) -> impl SystemParamBuilder<Self> {
188
/// CustomParamBuilder {
189
/// local: LocalBuilder(local),
190
/// query: QueryParamBuilder::new(query),
191
/// }
192
/// }
193
/// }
194
/// }
195
///
196
/// use custom_param::CustomParam;
197
///
198
/// # use bevy_ecs::prelude::*;
199
/// # #[derive(Component)]
200
/// # struct A;
201
/// #
202
/// # let mut world = World::new();
203
/// #
204
/// let system = (CustomParam::builder(100, |builder| {
205
/// builder.with::<A>();
206
/// }),)
207
/// .build_state(&mut world)
208
/// .build_system(|param: CustomParam| {});
209
/// ```
210
///
211
/// # Safety
212
///
213
/// The implementor must ensure the following is true.
214
/// - [`SystemParam::init_access`] correctly registers all [`World`] accesses used
215
/// by [`SystemParam::get_param`] with the provided [`system_meta`](SystemMeta).
216
/// - None of the world accesses may conflict with any prior accesses registered
217
/// on `system_meta`.
218
pub unsafe trait SystemParam: Sized {
219
/// Used to store data which persists across invocations of a system.
220
type State: Send + Sync + 'static;
221
222
/// The item type returned when constructing this system param.
223
/// The value of this associated type should be `Self`, instantiated with new lifetimes.
224
///
225
/// You could think of [`SystemParam::Item<'w, 's>`] as being an *operation* that changes the lifetimes bound to `Self`.
226
type Item<'world, 'state>: SystemParam<State = Self::State>;
227
228
/// Creates a new instance of this param's [`State`](SystemParam::State).
229
fn init_state(world: &mut World) -> Self::State;
230
231
/// Registers any [`World`] access used by this [`SystemParam`]
232
fn init_access(
233
state: &Self::State,
234
system_meta: &mut SystemMeta,
235
component_access_set: &mut FilteredAccessSet,
236
world: &mut World,
237
);
238
239
/// Applies any deferred mutations stored in this [`SystemParam`]'s state.
240
/// This is used to apply [`Commands`] during [`ApplyDeferred`](crate::prelude::ApplyDeferred).
241
///
242
/// [`Commands`]: crate::prelude::Commands
243
#[inline]
244
#[expect(
245
unused_variables,
246
reason = "The parameters here are intentionally unused by the default implementation; however, putting underscores here will result in the underscores being copied by rust-analyzer's tab completion."
247
)]
248
fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) {}
249
250
/// Queues any deferred mutations to be applied at the next [`ApplyDeferred`](crate::prelude::ApplyDeferred).
251
#[inline]
252
#[expect(
253
unused_variables,
254
reason = "The parameters here are intentionally unused by the default implementation; however, putting underscores here will result in the underscores being copied by rust-analyzer's tab completion."
255
)]
256
fn queue(state: &mut Self::State, system_meta: &SystemMeta, world: DeferredWorld) {}
257
258
/// Validates that the param can be acquired by the [`get_param`](SystemParam::get_param).
259
///
260
/// Built-in executors use this to prevent systems with invalid params from running,
261
/// and any failures here will be bubbled up to the default error handler defined in [`bevy_ecs::error`],
262
/// with a value of type [`SystemParamValidationError`].
263
///
264
/// For nested [`SystemParam`]s validation will fail if any
265
/// delegated validation fails.
266
///
267
/// However calling and respecting [`SystemParam::validate_param`]
268
/// is not a strict requirement, [`SystemParam::get_param`] should
269
/// provide it's own safety mechanism to prevent undefined behavior.
270
///
271
/// The [`world`](UnsafeWorldCell) can only be used to read param's data
272
/// and world metadata. No data can be written.
273
///
274
/// When using system parameters that require `change_tick` you can use
275
/// [`UnsafeWorldCell::change_tick()`]. Even if this isn't the exact
276
/// same tick used for [`SystemParam::get_param`], the world access
277
/// ensures that the queried data will be the same in both calls.
278
///
279
/// This method has to be called directly before [`SystemParam::get_param`] with no other (relevant)
280
/// world mutations inbetween. Otherwise, while it won't lead to any undefined behavior,
281
/// the validity of the param may change.
282
///
283
/// [`System::validate_param`](super::system::System::validate_param),
284
/// calls this method for each supplied system param.
285
///
286
/// # Safety
287
///
288
/// - The passed [`UnsafeWorldCell`] must have read-only access to world data
289
/// registered in [`init_access`](SystemParam::init_access).
290
/// - `world` must be the same [`World`] that was used to initialize [`state`](SystemParam::init_state).
291
#[expect(
292
unused_variables,
293
reason = "The parameters here are intentionally unused by the default implementation; however, putting underscores here will result in the underscores being copied by rust-analyzer's tab completion."
294
)]
295
unsafe fn validate_param(
296
state: &mut Self::State,
297
system_meta: &SystemMeta,
298
world: UnsafeWorldCell,
299
) -> Result<(), SystemParamValidationError> {
300
Ok(())
301
}
302
303
/// Creates a parameter to be passed into a [`SystemParamFunction`](super::SystemParamFunction).
304
///
305
/// # Safety
306
///
307
/// - The passed [`UnsafeWorldCell`] must have access to any world data registered
308
/// in [`init_access`](SystemParam::init_access).
309
/// - `world` must be the same [`World`] that was used to initialize [`state`](SystemParam::init_state).
310
unsafe fn get_param<'world, 'state>(
311
state: &'state mut Self::State,
312
system_meta: &SystemMeta,
313
world: UnsafeWorldCell<'world>,
314
change_tick: Tick,
315
) -> Self::Item<'world, 'state>;
316
}
317
318
/// A [`SystemParam`] that only reads a given [`World`].
319
///
320
/// # Safety
321
/// This must only be implemented for [`SystemParam`] impls that exclusively read the World passed in to [`SystemParam::get_param`]
322
pub unsafe trait ReadOnlySystemParam: SystemParam {}
323
324
/// Shorthand way of accessing the associated type [`SystemParam::Item`] for a given [`SystemParam`].
325
pub type SystemParamItem<'w, 's, P> = <P as SystemParam>::Item<'w, 's>;
326
327
// SAFETY: QueryState is constrained to read-only fetches, so it only reads World.
328
unsafe impl<'w, 's, D: ReadOnlyQueryData + 'static, F: QueryFilter + 'static> ReadOnlySystemParam
329
for Query<'w, 's, D, F>
330
{
331
}
332
333
// SAFETY: Relevant query ComponentId access is applied to SystemMeta. If
334
// this Query conflicts with any prior access, a panic will occur.
335
unsafe impl<D: QueryData + 'static, F: QueryFilter + 'static> SystemParam for Query<'_, '_, D, F> {
336
type State = QueryState<D, F>;
337
type Item<'w, 's> = Query<'w, 's, D, F>;
338
339
fn init_state(world: &mut World) -> Self::State {
340
QueryState::new(world)
341
}
342
343
fn init_access(
344
state: &Self::State,
345
system_meta: &mut SystemMeta,
346
component_access_set: &mut FilteredAccessSet,
347
world: &mut World,
348
) {
349
assert_component_access_compatibility(
350
&system_meta.name,
351
DebugName::type_name::<D>(),
352
DebugName::type_name::<F>(),
353
component_access_set,
354
&state.component_access,
355
world,
356
);
357
component_access_set.add(state.component_access.clone());
358
}
359
360
#[inline]
361
unsafe fn get_param<'w, 's>(
362
state: &'s mut Self::State,
363
system_meta: &SystemMeta,
364
world: UnsafeWorldCell<'w>,
365
change_tick: Tick,
366
) -> Self::Item<'w, 's> {
367
// SAFETY: We have registered all of the query's world accesses,
368
// so the caller ensures that `world` has permission to access any
369
// world data that the query needs.
370
// The caller ensures the world matches the one used in init_state.
371
unsafe { state.query_unchecked_with_ticks(world, system_meta.last_run, change_tick) }
372
}
373
}
374
375
fn assert_component_access_compatibility(
376
system_name: &DebugName,
377
query_type: DebugName,
378
filter_type: DebugName,
379
system_access: &FilteredAccessSet,
380
current: &FilteredAccess,
381
world: &World,
382
) {
383
let conflicts = system_access.get_conflicts_single(current);
384
if conflicts.is_empty() {
385
return;
386
}
387
let mut accesses = conflicts.format_conflict_list(world);
388
// Access list may be empty (if access to all components requested)
389
if !accesses.is_empty() {
390
accesses.push(' ');
391
}
392
panic!("error[B0001]: Query<{}, {}> in system {system_name} accesses component(s) {accesses}in a way that conflicts with a previous system parameter. Consider using `Without<T>` to create disjoint Queries or merging conflicting Queries into a `ParamSet`. See: https://bevy.org/learn/errors/b0001", query_type.shortname(), filter_type.shortname());
393
}
394
395
// SAFETY: Relevant query ComponentId access is applied to SystemMeta. If
396
// this Query conflicts with any prior access, a panic will occur.
397
unsafe impl<'a, 'b, D: QueryData + 'static, F: QueryFilter + 'static> SystemParam
398
for Single<'a, 'b, D, F>
399
{
400
type State = QueryState<D, F>;
401
type Item<'w, 's> = Single<'w, 's, D, F>;
402
403
fn init_state(world: &mut World) -> Self::State {
404
Query::init_state(world)
405
}
406
407
fn init_access(
408
state: &Self::State,
409
system_meta: &mut SystemMeta,
410
component_access_set: &mut FilteredAccessSet,
411
world: &mut World,
412
) {
413
Query::init_access(state, system_meta, component_access_set, world);
414
}
415
416
#[inline]
417
unsafe fn get_param<'w, 's>(
418
state: &'s mut Self::State,
419
system_meta: &SystemMeta,
420
world: UnsafeWorldCell<'w>,
421
change_tick: Tick,
422
) -> Self::Item<'w, 's> {
423
// SAFETY: State ensures that the components it accesses are not accessible somewhere elsewhere.
424
// The caller ensures the world matches the one used in init_state.
425
let query =
426
unsafe { state.query_unchecked_with_ticks(world, system_meta.last_run, change_tick) };
427
let single = query
428
.single_inner()
429
.expect("The query was expected to contain exactly one matching entity.");
430
Single {
431
item: single,
432
_filter: PhantomData,
433
}
434
}
435
436
#[inline]
437
unsafe fn validate_param(
438
state: &mut Self::State,
439
system_meta: &SystemMeta,
440
world: UnsafeWorldCell,
441
) -> Result<(), SystemParamValidationError> {
442
// SAFETY: State ensures that the components it accesses are not mutably accessible elsewhere
443
// and the query is read only.
444
// The caller ensures the world matches the one used in init_state.
445
let query = unsafe {
446
state.query_unchecked_with_ticks(world, system_meta.last_run, world.change_tick())
447
};
448
match query.single_inner() {
449
Ok(_) => Ok(()),
450
Err(QuerySingleError::NoEntities(_)) => Err(
451
SystemParamValidationError::skipped::<Self>("No matching entities"),
452
),
453
Err(QuerySingleError::MultipleEntities(_)) => Err(
454
SystemParamValidationError::skipped::<Self>("Multiple matching entities"),
455
),
456
}
457
}
458
}
459
460
// SAFETY: QueryState is constrained to read-only fetches, so it only reads World.
461
unsafe impl<'a, 'b, D: ReadOnlyQueryData + 'static, F: QueryFilter + 'static> ReadOnlySystemParam
462
for Single<'a, 'b, D, F>
463
{
464
}
465
466
// SAFETY: Relevant query ComponentId access is applied to SystemMeta. If
467
// this Query conflicts with any prior access, a panic will occur.
468
unsafe impl<D: QueryData + 'static, F: QueryFilter + 'static> SystemParam
469
for Populated<'_, '_, D, F>
470
{
471
type State = QueryState<D, F>;
472
type Item<'w, 's> = Populated<'w, 's, D, F>;
473
474
fn init_state(world: &mut World) -> Self::State {
475
Query::init_state(world)
476
}
477
478
fn init_access(
479
state: &Self::State,
480
system_meta: &mut SystemMeta,
481
component_access_set: &mut FilteredAccessSet,
482
world: &mut World,
483
) {
484
Query::init_access(state, system_meta, component_access_set, world);
485
}
486
487
#[inline]
488
unsafe fn get_param<'w, 's>(
489
state: &'s mut Self::State,
490
system_meta: &SystemMeta,
491
world: UnsafeWorldCell<'w>,
492
change_tick: Tick,
493
) -> Self::Item<'w, 's> {
494
// SAFETY: Delegate to existing `SystemParam` implementations.
495
let query = unsafe { Query::get_param(state, system_meta, world, change_tick) };
496
Populated(query)
497
}
498
499
#[inline]
500
unsafe fn validate_param(
501
state: &mut Self::State,
502
system_meta: &SystemMeta,
503
world: UnsafeWorldCell,
504
) -> Result<(), SystemParamValidationError> {
505
// SAFETY:
506
// - We have read-only access to the components accessed by query.
507
// - The caller ensures the world matches the one used in init_state.
508
let query = unsafe {
509
state.query_unchecked_with_ticks(world, system_meta.last_run, world.change_tick())
510
};
511
if query.is_empty() {
512
Err(SystemParamValidationError::skipped::<Self>(
513
"No matching entities",
514
))
515
} else {
516
Ok(())
517
}
518
}
519
}
520
521
// SAFETY: QueryState is constrained to read-only fetches, so it only reads World.
522
unsafe impl<'w, 's, D: ReadOnlyQueryData + 'static, F: QueryFilter + 'static> ReadOnlySystemParam
523
for Populated<'w, 's, D, F>
524
{
525
}
526
527
/// A collection of potentially conflicting [`SystemParam`]s allowed by disjoint access.
528
///
529
/// Allows systems to safely access and interact with up to 8 mutually exclusive [`SystemParam`]s, such as
530
/// two queries that reference the same mutable data or an event reader and writer of the same type.
531
///
532
/// Each individual [`SystemParam`] can be accessed by using the functions `p0()`, `p1()`, ..., `p7()`,
533
/// according to the order they are defined in the `ParamSet`. This ensures that there's either
534
/// only one mutable reference to a parameter at a time or any number of immutable references.
535
///
536
/// # Examples
537
///
538
/// The following system mutably accesses the same component two times,
539
/// which is not allowed due to rust's mutability rules.
540
///
541
/// ```should_panic
542
/// # use bevy_ecs::prelude::*;
543
/// #
544
/// # #[derive(Component)]
545
/// # struct Health;
546
/// #
547
/// # #[derive(Component)]
548
/// # struct Enemy;
549
/// #
550
/// # #[derive(Component)]
551
/// # struct Ally;
552
/// #
553
/// // This will panic at runtime when the system gets initialized.
554
/// fn bad_system(
555
/// mut enemies: Query<&mut Health, With<Enemy>>,
556
/// mut allies: Query<&mut Health, With<Ally>>,
557
/// ) {
558
/// // ...
559
/// }
560
/// #
561
/// # let mut bad_system_system = IntoSystem::into_system(bad_system);
562
/// # let mut world = World::new();
563
/// # bad_system_system.initialize(&mut world);
564
/// # bad_system_system.run((), &mut world);
565
/// ```
566
///
567
/// Conflicting `SystemParam`s like these can be placed in a `ParamSet`,
568
/// which leverages the borrow checker to ensure that only one of the contained parameters are accessed at a given time.
569
///
570
/// ```
571
/// # use bevy_ecs::prelude::*;
572
/// #
573
/// # #[derive(Component)]
574
/// # struct Health;
575
/// #
576
/// # #[derive(Component)]
577
/// # struct Enemy;
578
/// #
579
/// # #[derive(Component)]
580
/// # struct Ally;
581
/// #
582
/// // Given the following system
583
/// fn fancy_system(
584
/// mut set: ParamSet<(
585
/// Query<&mut Health, With<Enemy>>,
586
/// Query<&mut Health, With<Ally>>,
587
/// )>
588
/// ) {
589
/// // This will access the first `SystemParam`.
590
/// for mut health in set.p0().iter_mut() {
591
/// // Do your fancy stuff here...
592
/// }
593
///
594
/// // The second `SystemParam`.
595
/// // This would fail to compile if the previous parameter was still borrowed.
596
/// for mut health in set.p1().iter_mut() {
597
/// // Do even fancier stuff here...
598
/// }
599
/// }
600
/// # bevy_ecs::system::assert_is_system(fancy_system);
601
/// ```
602
///
603
/// Of course, `ParamSet`s can be used with any kind of `SystemParam`, not just [queries](Query).
604
///
605
/// ```
606
/// # use bevy_ecs::prelude::*;
607
/// #
608
/// # #[derive(Message)]
609
/// # struct MyMessage;
610
/// # impl MyMessage {
611
/// # pub fn new() -> Self { Self }
612
/// # }
613
/// fn message_system(
614
/// mut set: ParamSet<(
615
/// // PROBLEM: `MessageReader` and `MessageWriter` cannot be used together normally,
616
/// // because they both need access to the same message queue.
617
/// // SOLUTION: `ParamSet` allows these conflicting parameters to be used safely
618
/// // by ensuring only one is accessed at a time.
619
/// MessageReader<MyMessage>,
620
/// MessageWriter<MyMessage>,
621
/// // PROBLEM: `&World` needs read access to everything, which conflicts with
622
/// // any mutable access in the same system.
623
/// // SOLUTION: `ParamSet` ensures `&World` is only accessed when we're not
624
/// // using the other mutable parameters.
625
/// &World,
626
/// )>,
627
/// ) {
628
/// for message in set.p0().read() {
629
/// // ...
630
/// # let _message = message;
631
/// }
632
/// set.p1().write(MyMessage::new());
633
///
634
/// let entities = set.p2().entities();
635
/// // ...
636
/// # let _entities = entities;
637
/// }
638
/// # bevy_ecs::system::assert_is_system(message_system);
639
/// ```
640
pub struct ParamSet<'w, 's, T: SystemParam> {
641
param_states: &'s mut T::State,
642
world: UnsafeWorldCell<'w>,
643
system_meta: SystemMeta,
644
change_tick: Tick,
645
}
646
647
macro_rules! impl_param_set {
648
($(($index: tt, $param: ident, $fn_name: ident)),*) => {
649
// SAFETY: All parameters are constrained to ReadOnlySystemParam, so World is only read
650
unsafe impl<'w, 's, $($param,)*> ReadOnlySystemParam for ParamSet<'w, 's, ($($param,)*)>
651
where $($param: ReadOnlySystemParam,)*
652
{ }
653
654
// SAFETY: Relevant parameter ComponentId access is applied to SystemMeta. If any ParamState conflicts
655
// with any prior access, a panic will occur.
656
unsafe impl<'_w, '_s, $($param: SystemParam,)*> SystemParam for ParamSet<'_w, '_s, ($($param,)*)>
657
{
658
type State = ($($param::State,)*);
659
type Item<'w, 's> = ParamSet<'w, 's, ($($param,)*)>;
660
661
#[expect(
662
clippy::allow_attributes,
663
reason = "This is inside a macro meant for tuples; as such, `non_snake_case` won't always lint."
664
)]
665
#[allow(
666
non_snake_case,
667
reason = "Certain variable names are provided by the caller, not by us."
668
)]
669
fn init_state(world: &mut World) -> Self::State {
670
($($param::init_state(world),)*)
671
}
672
673
#[expect(
674
clippy::allow_attributes,
675
reason = "This is inside a macro meant for tuples; as such, `non_snake_case` won't always lint."
676
)]
677
#[allow(
678
non_snake_case,
679
reason = "Certain variable names are provided by the caller, not by us."
680
)]
681
fn init_access(state: &Self::State, system_meta: &mut SystemMeta, component_access_set: &mut FilteredAccessSet, world: &mut World) {
682
let ($($param,)*) = state;
683
$(
684
// Call `init_access` on a clone of the original access set to check for conflicts
685
let component_access_set_clone = &mut component_access_set.clone();
686
$param::init_access($param, system_meta, component_access_set_clone, world);
687
)*
688
$(
689
// Pretend to add the param to the system alone to gather the new access,
690
// then merge its access into the system.
691
let mut access_set = FilteredAccessSet::new();
692
$param::init_access($param, system_meta, &mut access_set, world);
693
component_access_set.extend(access_set);
694
)*
695
}
696
697
fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) {
698
<($($param,)*) as SystemParam>::apply(state, system_meta, world);
699
}
700
701
fn queue(state: &mut Self::State, system_meta: &SystemMeta, mut world: DeferredWorld) {
702
<($($param,)*) as SystemParam>::queue(state, system_meta, world.reborrow());
703
}
704
705
#[inline]
706
unsafe fn validate_param<'w, 's>(
707
state: &'s mut Self::State,
708
system_meta: &SystemMeta,
709
world: UnsafeWorldCell<'w>,
710
) -> Result<(), SystemParamValidationError> {
711
// SAFETY: Upheld by caller
712
unsafe {
713
<($($param,)*) as SystemParam>::validate_param(state, system_meta, world)
714
}
715
}
716
717
#[inline]
718
unsafe fn get_param<'w, 's>(
719
state: &'s mut Self::State,
720
system_meta: &SystemMeta,
721
world: UnsafeWorldCell<'w>,
722
change_tick: Tick,
723
) -> Self::Item<'w, 's> {
724
ParamSet {
725
param_states: state,
726
system_meta: system_meta.clone(),
727
world,
728
change_tick,
729
}
730
}
731
}
732
733
impl<'w, 's, $($param: SystemParam,)*> ParamSet<'w, 's, ($($param,)*)>
734
{
735
$(
736
/// Gets exclusive access to the parameter at index
737
#[doc = stringify!($index)]
738
/// in this [`ParamSet`].
739
/// No other parameters may be accessed while this one is active.
740
pub fn $fn_name<'a>(&'a mut self) -> SystemParamItem<'a, 'a, $param> {
741
// SAFETY: systems run without conflicts with other systems.
742
// Conflicting params in ParamSet are not accessible at the same time
743
// ParamSets are guaranteed to not conflict with other SystemParams
744
unsafe {
745
$param::get_param(&mut self.param_states.$index, &self.system_meta, self.world, self.change_tick)
746
}
747
}
748
)*
749
}
750
}
751
}
752
753
all_tuples_enumerated!(impl_param_set, 1, 8, P, p);
754
755
// SAFETY: Res only reads a single World resource
756
unsafe impl<'a, T: Resource> ReadOnlySystemParam for Res<'a, T> {}
757
758
// SAFETY: Res ComponentId access is applied to SystemMeta. If this Res
759
// conflicts with any prior access, a panic will occur.
760
unsafe impl<'a, T: Resource> SystemParam for Res<'a, T> {
761
type State = ComponentId;
762
type Item<'w, 's> = Res<'w, T>;
763
764
fn init_state(world: &mut World) -> Self::State {
765
world.components_registrator().register_component::<T>()
766
}
767
768
fn init_access(
769
&component_id: &Self::State,
770
system_meta: &mut SystemMeta,
771
component_access_set: &mut FilteredAccessSet,
772
_world: &mut World,
773
) {
774
let combined_access = component_access_set.combined_access();
775
assert!(
776
!combined_access.has_resource_write(component_id),
777
"error[B0002]: Res<{}> in system {} conflicts with a previous ResMut<{0}> access. Consider removing the duplicate access. See: https://bevy.org/learn/errors/b0002",
778
DebugName::type_name::<T>(),
779
system_meta.name,
780
);
781
782
let mut filter = FilteredAccess::default();
783
filter.add_component_read(component_id);
784
filter.add_resource_read(component_id);
785
filter.and_with(IS_RESOURCE);
786
787
assert!(component_access_set
788
.get_conflicts_single(&filter)
789
.is_empty(),
790
"error[B0002]: Res<{}> in system {} conflicts with a previous query. Consider removing the duplicate access. See: https://bevy.org/learn/errors/b0002",
791
DebugName::type_name::<T>(),
792
system_meta.name
793
);
794
795
component_access_set.add(filter);
796
}
797
798
#[inline]
799
unsafe fn validate_param(
800
&mut component_id: &mut Self::State,
801
_system_meta: &SystemMeta,
802
world: UnsafeWorldCell,
803
) -> Result<(), SystemParamValidationError> {
804
// SAFETY: Read-only access to the resource
805
if let Some(entity) = unsafe { world.resource_entities() }.get(component_id)
806
&& let Ok(entity_ref) = world.get_entity(*entity)
807
&& entity_ref.contains_id(component_id)
808
{
809
Ok(())
810
} else {
811
Err(SystemParamValidationError::invalid::<Self>(
812
"Resource does not exist",
813
))
814
}
815
}
816
817
#[inline]
818
unsafe fn get_param<'w, 's>(
819
&mut component_id: &'s mut Self::State,
820
system_meta: &SystemMeta,
821
world: UnsafeWorldCell<'w>,
822
change_tick: Tick,
823
) -> Self::Item<'w, 's> {
824
let (ptr, ticks) = world
825
.get_resource_with_ticks(component_id)
826
.unwrap_or_else(|| {
827
panic!(
828
"Resource requested by {} does not exist: {}",
829
system_meta.name,
830
DebugName::type_name::<T>()
831
);
832
});
833
Res {
834
value: ptr.deref(),
835
ticks: ComponentTicksRef {
836
added: ticks.added.deref(),
837
changed: ticks.changed.deref(),
838
changed_by: ticks.changed_by.map(|changed_by| changed_by.deref()),
839
last_run: system_meta.last_run,
840
this_run: change_tick,
841
},
842
}
843
}
844
}
845
846
// SAFETY: Res ComponentId access is applied to SystemMeta. If this Res
847
// conflicts with any prior access, a panic will occur.
848
unsafe impl<'a, T: Resource> SystemParam for ResMut<'a, T> {
849
type State = ComponentId;
850
type Item<'w, 's> = ResMut<'w, T>;
851
852
fn init_state(world: &mut World) -> Self::State {
853
world.components_registrator().register_component::<T>()
854
}
855
856
fn init_access(
857
&component_id: &Self::State,
858
system_meta: &mut SystemMeta,
859
component_access_set: &mut FilteredAccessSet,
860
_world: &mut World,
861
) {
862
let combined_access = component_access_set.combined_access();
863
if combined_access.has_resource_write(component_id) {
864
panic!(
865
"error[B0002]: ResMut<{}> in system {} conflicts with a previous ResMut<{0}> access. Consider removing the duplicate access. See: https://bevy.org/learn/errors/b0002",
866
DebugName::type_name::<T>(), system_meta.name);
867
} else if combined_access.has_resource_read(component_id) {
868
panic!(
869
"error[B0002]: ResMut<{}> in system {} conflicts with a previous Res<{0}> access. Consider removing the duplicate access. See: https://bevy.org/learn/errors/b0002",
870
DebugName::type_name::<T>(), system_meta.name);
871
}
872
873
let mut filter = FilteredAccess::default();
874
filter.add_component_write(component_id);
875
filter.add_resource_write(component_id);
876
filter.and_with(IS_RESOURCE);
877
878
assert!(component_access_set
879
.get_conflicts_single(&filter)
880
.is_empty(),
881
"error[B0002]: ResMut<{}> in system {} conflicts with a previous query. Consider removing the duplicate access. See: https://bevy.org/learn/errors/b0002",
882
DebugName::type_name::<T>(),
883
system_meta.name
884
);
885
886
component_access_set.add(filter);
887
}
888
889
#[inline]
890
unsafe fn validate_param(
891
&mut component_id: &mut Self::State,
892
_system_meta: &SystemMeta,
893
world: UnsafeWorldCell,
894
) -> Result<(), SystemParamValidationError> {
895
// SAFETY: Read-only access to the resource.
896
if let Some(entity) = unsafe { world.resource_entities() }.get(component_id)
897
&& let Ok(entity_ref) = world.get_entity(*entity)
898
&& entity_ref.contains_id(component_id)
899
{
900
Ok(())
901
} else {
902
Err(SystemParamValidationError::invalid::<Self>(
903
"Resource does not exist",
904
))
905
}
906
}
907
908
#[inline]
909
unsafe fn get_param<'w, 's>(
910
&mut component_id: &'s mut Self::State,
911
system_meta: &SystemMeta,
912
world: UnsafeWorldCell<'w>,
913
change_tick: Tick,
914
) -> Self::Item<'w, 's> {
915
let value = world
916
.get_resource_mut_by_id(component_id)
917
.unwrap_or_else(|| {
918
panic!(
919
"Resource requested by {} does not exist: {}",
920
system_meta.name,
921
DebugName::type_name::<T>()
922
);
923
});
924
ResMut {
925
value: value.value.deref_mut::<T>(),
926
ticks: ComponentTicksMut {
927
added: value.ticks.added,
928
changed: value.ticks.changed,
929
changed_by: value.ticks.changed_by,
930
last_run: system_meta.last_run,
931
this_run: change_tick,
932
},
933
}
934
}
935
}
936
937
// SAFETY: only reads world
938
unsafe impl<'w> ReadOnlySystemParam for &'w World {}
939
940
// SAFETY: `read_all` access is set and conflicts result in a panic
941
unsafe impl SystemParam for &'_ World {
942
type State = ();
943
type Item<'w, 's> = &'w World;
944
945
fn init_state(_world: &mut World) -> Self::State {}
946
947
fn init_access(
948
_state: &Self::State,
949
_system_meta: &mut SystemMeta,
950
component_access_set: &mut FilteredAccessSet,
951
_world: &mut World,
952
) {
953
let mut filtered_access = FilteredAccess::default();
954
955
filtered_access.read_all();
956
if !component_access_set
957
.get_conflicts_single(&filtered_access)
958
.is_empty()
959
{
960
panic!("&World conflicts with a previous mutable system parameter. Allowing this would break Rust's mutability rules");
961
}
962
component_access_set.add(filtered_access);
963
}
964
965
#[inline]
966
unsafe fn get_param<'w, 's>(
967
_state: &'s mut Self::State,
968
_system_meta: &SystemMeta,
969
world: UnsafeWorldCell<'w>,
970
_change_tick: Tick,
971
) -> Self::Item<'w, 's> {
972
// SAFETY: Read-only access to the entire world was registered in `init_state`.
973
unsafe { world.world() }
974
}
975
}
976
977
// SAFETY: `DeferredWorld` can read all components and resources but cannot be used to gain any other mutable references.
978
unsafe impl<'w> SystemParam for DeferredWorld<'w> {
979
type State = ();
980
type Item<'world, 'state> = DeferredWorld<'world>;
981
982
fn init_state(_world: &mut World) -> Self::State {}
983
984
fn init_access(
985
_state: &Self::State,
986
system_meta: &mut SystemMeta,
987
component_access_set: &mut FilteredAccessSet,
988
_world: &mut World,
989
) {
990
assert!(
991
!component_access_set.combined_access().has_any_read(),
992
"DeferredWorld in system {} conflicts with a previous access.",
993
system_meta.name,
994
);
995
component_access_set.write_all();
996
}
997
998
unsafe fn get_param<'world, 'state>(
999
_state: &'state mut Self::State,
1000
_system_meta: &SystemMeta,
1001
world: UnsafeWorldCell<'world>,
1002
_change_tick: Tick,
1003
) -> Self::Item<'world, 'state> {
1004
// SAFETY: Upheld by caller
1005
unsafe { world.into_deferred() }
1006
}
1007
}
1008
1009
/// A [`SystemParam`] that provides a system-private value of `T` that persists across system calls.
1010
///
1011
/// The initial value is created by calling `T`'s [`FromWorld::from_world`] (or [`Default::default`] if `T: Default`).
1012
///
1013
/// A local may only be accessed by the system itself and is therefore not visible to other systems.
1014
/// If two or more systems specify the same local type each will have their own unique local.
1015
/// If multiple [`SystemParam`]s within the same system each specify the same local type
1016
/// each will get their own distinct data storage.
1017
///
1018
/// The supplied lifetime parameter is the [`SystemParam`]s `'s` lifetime.
1019
///
1020
/// # Examples
1021
///
1022
/// ```
1023
/// # use bevy_ecs::prelude::*;
1024
/// # let world = &mut World::default();
1025
/// fn counter(mut count: Local<u32>) -> u32 {
1026
/// *count += 1;
1027
/// *count
1028
/// }
1029
/// let mut counter_system = IntoSystem::into_system(counter);
1030
/// counter_system.initialize(world);
1031
///
1032
/// // Counter is initialized to u32's default value of 0, and increases to 1 on first run.
1033
/// assert_eq!(counter_system.run((), world).unwrap(), 1);
1034
/// // Counter gets the same value and increases to 2 on its second call.
1035
/// assert_eq!(counter_system.run((), world).unwrap(), 2);
1036
/// ```
1037
///
1038
/// A simple way to set a different default value for a local is by wrapping the value with an Option.
1039
///
1040
/// ```
1041
/// # use bevy_ecs::prelude::*;
1042
/// # let world = &mut World::default();
1043
/// fn counter_from_10(mut count: Local<Option<u32>>) -> u32 {
1044
/// let count = count.get_or_insert(10);
1045
/// *count += 1;
1046
/// *count
1047
/// }
1048
/// let mut counter_system = IntoSystem::into_system(counter_from_10);
1049
/// counter_system.initialize(world);
1050
///
1051
/// // Counter is initialized at 10, and increases to 11 on first run.
1052
/// assert_eq!(counter_system.run((), world).unwrap(), 11);
1053
/// // Counter is only increased by 1 on subsequent runs.
1054
/// assert_eq!(counter_system.run((), world).unwrap(), 12);
1055
/// ```
1056
///
1057
/// A system can have multiple `Local` values with the same type, each with distinct values.
1058
///
1059
/// ```
1060
/// # use bevy_ecs::prelude::*;
1061
/// # let world = &mut World::default();
1062
/// fn double_counter(mut count: Local<u32>, mut double_count: Local<u32>) -> (u32, u32) {
1063
/// *count += 1;
1064
/// *double_count += 2;
1065
/// (*count, *double_count)
1066
/// }
1067
/// let mut counter_system = IntoSystem::into_system(double_counter);
1068
/// counter_system.initialize(world);
1069
///
1070
/// assert_eq!(counter_system.run((), world).unwrap(), (1, 2));
1071
/// assert_eq!(counter_system.run((), world).unwrap(), (2, 4));
1072
/// ```
1073
///
1074
/// This example shows that two systems using the same type for their own `Local` get distinct locals.
1075
///
1076
/// ```
1077
/// # use bevy_ecs::prelude::*;
1078
/// # let world = &mut World::default();
1079
/// fn write_to_local(mut local: Local<usize>) {
1080
/// *local = 42;
1081
/// }
1082
/// fn read_from_local(local: Local<usize>) -> usize {
1083
/// *local
1084
/// }
1085
/// let mut write_system = IntoSystem::into_system(write_to_local);
1086
/// let mut read_system = IntoSystem::into_system(read_from_local);
1087
/// write_system.initialize(world);
1088
/// read_system.initialize(world);
1089
///
1090
/// assert_eq!(read_system.run((), world).unwrap(), 0);
1091
/// write_system.run((), world);
1092
/// // The read local is still 0 due to the locals not being shared.
1093
/// assert_eq!(read_system.run((), world).unwrap(), 0);
1094
/// ```
1095
///
1096
/// You can use a `Local` to avoid reallocating memory every system call.
1097
///
1098
/// ```
1099
/// # use bevy_ecs::prelude::*;
1100
/// fn some_system(mut vec: Local<Vec<u32>>) {
1101
/// // Do your regular system logic, using the vec, as normal.
1102
///
1103
/// // At end of function, clear the vec's contents so its empty for next system call.
1104
/// // If it's possible the capacity could get too large, you may want to check and resize that as well.
1105
/// vec.clear();
1106
/// }
1107
/// ```
1108
///
1109
/// N.B. A [`Local`]s value cannot be read or written to outside of the containing system.
1110
/// To add configuration to a system, convert a capturing closure into the system instead:
1111
///
1112
/// ```
1113
/// # use bevy_ecs::prelude::*;
1114
/// # use bevy_ecs::system::assert_is_system;
1115
/// struct Config(u32);
1116
/// #[derive(Resource)]
1117
/// struct MyU32Wrapper(u32);
1118
/// fn reset_to_system(value: Config) -> impl FnMut(ResMut<MyU32Wrapper>) {
1119
/// move |mut val| val.0 = value.0
1120
/// }
1121
///
1122
/// // .add_systems(reset_to_system(my_config))
1123
/// # assert_is_system(reset_to_system(Config(10)));
1124
/// ```
1125
#[derive(Debug)]
1126
pub struct Local<'s, T: FromWorld + Send + 'static>(pub(crate) &'s mut T);
1127
1128
// SAFETY: Local only accesses internal state
1129
unsafe impl<'s, T: FromWorld + Send + 'static> ReadOnlySystemParam for Local<'s, T> {}
1130
1131
impl<'s, T: FromWorld + Send + 'static> Deref for Local<'s, T> {
1132
type Target = T;
1133
1134
#[inline]
1135
fn deref(&self) -> &Self::Target {
1136
self.0
1137
}
1138
}
1139
1140
impl<'s, T: FromWorld + Send + 'static> DerefMut for Local<'s, T> {
1141
#[inline]
1142
fn deref_mut(&mut self) -> &mut Self::Target {
1143
self.0
1144
}
1145
}
1146
1147
impl<'s, 'a, T: FromWorld + Send + 'static> IntoIterator for &'a Local<'s, T>
1148
where
1149
&'a T: IntoIterator,
1150
{
1151
type Item = <&'a T as IntoIterator>::Item;
1152
type IntoIter = <&'a T as IntoIterator>::IntoIter;
1153
1154
fn into_iter(self) -> Self::IntoIter {
1155
self.0.into_iter()
1156
}
1157
}
1158
1159
impl<'s, 'a, T: FromWorld + Send + 'static> IntoIterator for &'a mut Local<'s, T>
1160
where
1161
&'a mut T: IntoIterator,
1162
{
1163
type Item = <&'a mut T as IntoIterator>::Item;
1164
type IntoIter = <&'a mut T as IntoIterator>::IntoIter;
1165
1166
fn into_iter(self) -> Self::IntoIter {
1167
self.0.into_iter()
1168
}
1169
}
1170
1171
// SAFETY: only local state is accessed
1172
unsafe impl<'a, T: FromWorld + Send + 'static> SystemParam for Local<'a, T> {
1173
type State = SyncCell<T>;
1174
type Item<'w, 's> = Local<'s, T>;
1175
1176
fn init_state(world: &mut World) -> Self::State {
1177
SyncCell::new(T::from_world(world))
1178
}
1179
1180
fn init_access(
1181
_state: &Self::State,
1182
_system_meta: &mut SystemMeta,
1183
_component_access_set: &mut FilteredAccessSet,
1184
_world: &mut World,
1185
) {
1186
}
1187
1188
#[inline]
1189
unsafe fn get_param<'w, 's>(
1190
state: &'s mut Self::State,
1191
_system_meta: &SystemMeta,
1192
_world: UnsafeWorldCell<'w>,
1193
_change_tick: Tick,
1194
) -> Self::Item<'w, 's> {
1195
Local(state.get())
1196
}
1197
}
1198
1199
/// Types that can be used with [`Deferred<T>`] in systems.
1200
/// This allows storing system-local data which is used to defer [`World`] mutations.
1201
///
1202
/// Types that implement `SystemBuffer` should take care to perform as many
1203
/// computations up-front as possible. Buffers cannot be applied in parallel,
1204
/// so you should try to minimize the time spent in [`SystemBuffer::apply`].
1205
pub trait SystemBuffer: FromWorld + Send + 'static {
1206
/// Applies any deferred mutations to the [`World`].
1207
fn apply(&mut self, system_meta: &SystemMeta, world: &mut World) {
1208
self.queue(system_meta, world.into());
1209
}
1210
/// Queues any deferred mutations to be applied at the next [`ApplyDeferred`](crate::prelude::ApplyDeferred).
1211
///
1212
/// To queue structural changes to [`DeferredWorld`], a command queue of the [`DeferredWorld`]
1213
/// should be used via [`commands`](crate::world::DeferredWorld::commands).
1214
fn queue(&mut self, _system_meta: &SystemMeta, _world: DeferredWorld);
1215
}
1216
1217
/// A [`SystemParam`] that stores a buffer which gets applied to the [`World`] during
1218
/// [`ApplyDeferred`](crate::schedule::ApplyDeferred).
1219
/// This is used internally by [`Commands`] to defer `World` mutations.
1220
///
1221
/// [`Commands`]: crate::system::Commands
1222
///
1223
/// # Examples
1224
///
1225
/// By using this type to defer mutations, you can avoid mutable `World` access within
1226
/// a system, which allows it to run in parallel with more systems.
1227
///
1228
/// Note that deferring mutations is *not* free, and should only be used if
1229
/// the gains in parallelization outweigh the time it takes to apply deferred mutations.
1230
/// In general, [`Deferred`] should only be used for mutations that are infrequent,
1231
/// or which otherwise take up a small portion of a system's run-time.
1232
///
1233
/// ```
1234
/// # use bevy_ecs::prelude::*;
1235
/// # use bevy_ecs::world::DeferredWorld;
1236
/// // Tracks whether or not there is a threat the player should be aware of.
1237
/// #[derive(Resource, Default)]
1238
/// pub struct Alarm(bool);
1239
///
1240
/// #[derive(Component)]
1241
/// pub struct Settlement {
1242
/// // ...
1243
/// }
1244
///
1245
/// // A threat from inside the settlement.
1246
/// #[derive(Component)]
1247
/// pub struct Criminal;
1248
///
1249
/// // A threat from outside the settlement.
1250
/// #[derive(Component)]
1251
/// pub struct Monster;
1252
///
1253
/// # impl Criminal { pub fn is_threat(&self, _: &Settlement) -> bool { true } }
1254
///
1255
/// use bevy_ecs::system::{Deferred, SystemBuffer, SystemMeta};
1256
///
1257
/// // Uses deferred mutations to allow signaling the alarm from multiple systems in parallel.
1258
/// #[derive(Resource, Default)]
1259
/// struct AlarmFlag(bool);
1260
///
1261
/// impl AlarmFlag {
1262
/// /// Sounds the alarm the next time buffers are applied via ApplyDeferred.
1263
/// pub fn flag(&mut self) {
1264
/// self.0 = true;
1265
/// }
1266
/// }
1267
///
1268
/// impl SystemBuffer for AlarmFlag {
1269
/// // When `AlarmFlag` is used in a system, this function will get
1270
/// // called the next time buffers are applied via ApplyDeferred.
1271
/// fn queue(&mut self, system_meta: &SystemMeta, mut world: DeferredWorld) {
1272
/// if self.0 {
1273
/// world.resource_mut::<Alarm>().0 = true;
1274
/// self.0 = false;
1275
/// }
1276
/// }
1277
/// }
1278
///
1279
/// // Sound the alarm if there are any criminals who pose a threat.
1280
/// fn alert_criminal(
1281
/// settlement: Single<&Settlement>,
1282
/// criminals: Query<&Criminal>,
1283
/// mut alarm: Deferred<AlarmFlag>
1284
/// ) {
1285
/// for criminal in &criminals {
1286
/// // Only sound the alarm if the criminal is a threat.
1287
/// // For this example, assume that this check is expensive to run.
1288
/// // Since the majority of this system's run-time is dominated
1289
/// // by calling `is_threat()`, we defer sounding the alarm to
1290
/// // allow this system to run in parallel with other alarm systems.
1291
/// if criminal.is_threat(*settlement) {
1292
/// alarm.flag();
1293
/// }
1294
/// }
1295
/// }
1296
///
1297
/// // Sound the alarm if there is a monster.
1298
/// fn alert_monster(
1299
/// monsters: Query<&Monster>,
1300
/// mut alarm: ResMut<Alarm>
1301
/// ) {
1302
/// if monsters.iter().next().is_some() {
1303
/// // Since this system does nothing except for sounding the alarm,
1304
/// // it would be pointless to defer it, so we sound the alarm directly.
1305
/// alarm.0 = true;
1306
/// }
1307
/// }
1308
///
1309
/// let mut world = World::new();
1310
/// world.init_resource::<Alarm>();
1311
/// world.spawn(Settlement {
1312
/// // ...
1313
/// });
1314
///
1315
/// let mut schedule = Schedule::default();
1316
/// // These two systems have no conflicts and will run in parallel.
1317
/// schedule.add_systems((alert_criminal, alert_monster));
1318
///
1319
/// // There are no criminals or monsters, so the alarm is not sounded.
1320
/// schedule.run(&mut world);
1321
/// assert_eq!(world.resource::<Alarm>().0, false);
1322
///
1323
/// // Spawn a monster, which will cause the alarm to be sounded.
1324
/// let m_id = world.spawn(Monster).id();
1325
/// schedule.run(&mut world);
1326
/// assert_eq!(world.resource::<Alarm>().0, true);
1327
///
1328
/// // Remove the monster and reset the alarm.
1329
/// world.entity_mut(m_id).despawn();
1330
/// world.resource_mut::<Alarm>().0 = false;
1331
///
1332
/// // Spawn a criminal, which will cause the alarm to be sounded.
1333
/// world.spawn(Criminal);
1334
/// schedule.run(&mut world);
1335
/// assert_eq!(world.resource::<Alarm>().0, true);
1336
/// ```
1337
pub struct Deferred<'a, T: SystemBuffer>(pub(crate) &'a mut T);
1338
1339
impl<'a, T: SystemBuffer> Deref for Deferred<'a, T> {
1340
type Target = T;
1341
#[inline]
1342
fn deref(&self) -> &Self::Target {
1343
self.0
1344
}
1345
}
1346
1347
impl<'a, T: SystemBuffer> DerefMut for Deferred<'a, T> {
1348
#[inline]
1349
fn deref_mut(&mut self) -> &mut Self::Target {
1350
self.0
1351
}
1352
}
1353
1354
impl<T: SystemBuffer> Deferred<'_, T> {
1355
/// Returns a [`Deferred<T>`] with a smaller lifetime.
1356
/// This is useful if you have `&mut Deferred<T>` but need `Deferred<T>`.
1357
pub fn reborrow(&mut self) -> Deferred<'_, T> {
1358
Deferred(self.0)
1359
}
1360
}
1361
1362
// SAFETY: Only local state is accessed.
1363
unsafe impl<T: SystemBuffer> ReadOnlySystemParam for Deferred<'_, T> {}
1364
1365
// SAFETY: Only local state is accessed.
1366
unsafe impl<T: SystemBuffer> SystemParam for Deferred<'_, T> {
1367
type State = SyncCell<T>;
1368
type Item<'w, 's> = Deferred<'s, T>;
1369
1370
#[track_caller]
1371
fn init_state(world: &mut World) -> Self::State {
1372
SyncCell::new(T::from_world(world))
1373
}
1374
1375
fn init_access(
1376
_state: &Self::State,
1377
system_meta: &mut SystemMeta,
1378
_component_access_set: &mut FilteredAccessSet,
1379
_world: &mut World,
1380
) {
1381
system_meta.set_has_deferred();
1382
}
1383
1384
fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) {
1385
state.get().apply(system_meta, world);
1386
}
1387
1388
fn queue(state: &mut Self::State, system_meta: &SystemMeta, world: DeferredWorld) {
1389
state.get().queue(system_meta, world);
1390
}
1391
1392
#[inline]
1393
unsafe fn get_param<'w, 's>(
1394
state: &'s mut Self::State,
1395
_system_meta: &SystemMeta,
1396
_world: UnsafeWorldCell<'w>,
1397
_change_tick: Tick,
1398
) -> Self::Item<'w, 's> {
1399
Deferred(state.get())
1400
}
1401
}
1402
1403
/// A dummy type to tell the executor to run the system exclusively.
1404
pub struct ExclusiveMarker(PhantomData<()>);
1405
1406
// SAFETY: No world access.
1407
unsafe impl SystemParam for ExclusiveMarker {
1408
type State = ();
1409
type Item<'w, 's> = Self;
1410
1411
#[inline]
1412
fn init_state(_world: &mut World) -> Self::State {}
1413
1414
fn init_access(
1415
_state: &Self::State,
1416
system_meta: &mut SystemMeta,
1417
_component_access_set: &mut FilteredAccessSet,
1418
_world: &mut World,
1419
) {
1420
system_meta.set_exclusive();
1421
}
1422
1423
#[inline]
1424
unsafe fn get_param<'world, 'state>(
1425
_state: &'state mut Self::State,
1426
_system_meta: &SystemMeta,
1427
_world: UnsafeWorldCell<'world>,
1428
_change_tick: Tick,
1429
) -> Self::Item<'world, 'state> {
1430
Self(PhantomData)
1431
}
1432
}
1433
1434
// SAFETY: Does not read any world state
1435
unsafe impl ReadOnlySystemParam for ExclusiveMarker {}
1436
1437
/// A dummy type that is [`!Send`](Send), to force systems to run on the main thread.
1438
pub struct NonSendMarker(PhantomData<*mut ()>);
1439
1440
// SAFETY: No world access.
1441
unsafe impl SystemParam for NonSendMarker {
1442
type State = ();
1443
type Item<'w, 's> = Self;
1444
1445
#[inline]
1446
fn init_state(_world: &mut World) -> Self::State {}
1447
1448
fn init_access(
1449
_state: &Self::State,
1450
system_meta: &mut SystemMeta,
1451
_component_access_set: &mut FilteredAccessSet,
1452
_world: &mut World,
1453
) {
1454
system_meta.set_non_send();
1455
}
1456
1457
#[inline]
1458
unsafe fn get_param<'world, 'state>(
1459
_state: &'state mut Self::State,
1460
_system_meta: &SystemMeta,
1461
_world: UnsafeWorldCell<'world>,
1462
_change_tick: Tick,
1463
) -> Self::Item<'world, 'state> {
1464
Self(PhantomData)
1465
}
1466
}
1467
1468
// SAFETY: Does not read any world state
1469
unsafe impl ReadOnlySystemParam for NonSendMarker {}
1470
1471
// SAFETY: Only reads a single World non-send resource
1472
unsafe impl<'w, T> ReadOnlySystemParam for NonSend<'w, T> {}
1473
1474
// SAFETY: NonSendComponentId access is applied to SystemMeta. If this
1475
// NonSend conflicts with any prior access, a panic will occur.
1476
unsafe impl<'a, T: 'static> SystemParam for NonSend<'a, T> {
1477
type State = ComponentId;
1478
type Item<'w, 's> = NonSend<'w, T>;
1479
1480
fn init_state(world: &mut World) -> Self::State {
1481
world.components_registrator().register_non_send::<T>()
1482
}
1483
1484
fn init_access(
1485
&component_id: &Self::State,
1486
system_meta: &mut SystemMeta,
1487
component_access_set: &mut FilteredAccessSet,
1488
_world: &mut World,
1489
) {
1490
system_meta.set_non_send();
1491
1492
let combined_access = component_access_set.combined_access();
1493
assert!(
1494
!combined_access.has_resource_write(component_id),
1495
"error[B0002]: NonSend<{}> in system {} conflicts with a previous mutable resource access ({0}). Consider removing the duplicate access. See: https://bevy.org/learn/errors/b0002",
1496
DebugName::type_name::<T>(),
1497
system_meta.name,
1498
);
1499
component_access_set.add_unfiltered_resource_read(component_id);
1500
}
1501
1502
#[inline]
1503
unsafe fn validate_param(
1504
&mut component_id: &mut Self::State,
1505
_system_meta: &SystemMeta,
1506
world: UnsafeWorldCell,
1507
) -> Result<(), SystemParamValidationError> {
1508
// SAFETY: Read-only access to non-send metadata.
1509
if unsafe { world.storages() }
1510
.non_sends
1511
.get(component_id)
1512
.is_some_and(NonSendData::is_present)
1513
{
1514
Ok(())
1515
} else {
1516
Err(SystemParamValidationError::invalid::<Self>(
1517
"Non-send resource does not exist",
1518
))
1519
}
1520
}
1521
1522
#[inline]
1523
unsafe fn get_param<'w, 's>(
1524
&mut component_id: &'s mut Self::State,
1525
system_meta: &SystemMeta,
1526
world: UnsafeWorldCell<'w>,
1527
change_tick: Tick,
1528
) -> Self::Item<'w, 's> {
1529
let (ptr, ticks) = world
1530
.get_non_send_with_ticks(component_id)
1531
.unwrap_or_else(|| {
1532
panic!(
1533
"Non-send resource requested by {} does not exist: {}",
1534
system_meta.name,
1535
DebugName::type_name::<T>()
1536
);
1537
});
1538
NonSend {
1539
value: ptr.deref(),
1540
ticks: ComponentTicksRef::from_tick_cells(ticks, system_meta.last_run, change_tick),
1541
}
1542
}
1543
}
1544
1545
// SAFETY: NonSendMut ComponentId access is applied to SystemMeta. If this
1546
// NonSendMut conflicts with any prior access, a panic will occur.
1547
unsafe impl<'a, T: 'static> SystemParam for NonSendMut<'a, T> {
1548
type State = ComponentId;
1549
type Item<'w, 's> = NonSendMut<'w, T>;
1550
1551
fn init_state(world: &mut World) -> Self::State {
1552
world.components_registrator().register_non_send::<T>()
1553
}
1554
1555
fn init_access(
1556
&component_id: &Self::State,
1557
system_meta: &mut SystemMeta,
1558
component_access_set: &mut FilteredAccessSet,
1559
_world: &mut World,
1560
) {
1561
system_meta.set_non_send();
1562
1563
let combined_access = component_access_set.combined_access();
1564
if combined_access.has_resource_write(component_id) {
1565
panic!(
1566
"error[B0002]: NonSendMut<{}> in system {} conflicts with a previous mutable resource access ({0}). Consider removing the duplicate access. See: https://bevy.org/learn/errors/b0002",
1567
DebugName::type_name::<T>(), system_meta.name);
1568
} else if combined_access.has_resource_read(component_id) {
1569
panic!(
1570
"error[B0002]: NonSendMut<{}> in system {} conflicts with a previous immutable resource access ({0}). Consider removing the duplicate access. See: https://bevy.org/learn/errors/b0002",
1571
DebugName::type_name::<T>(), system_meta.name);
1572
}
1573
component_access_set.add_unfiltered_resource_write(component_id);
1574
}
1575
1576
#[inline]
1577
unsafe fn validate_param(
1578
&mut component_id: &mut Self::State,
1579
_system_meta: &SystemMeta,
1580
world: UnsafeWorldCell,
1581
) -> Result<(), SystemParamValidationError> {
1582
// SAFETY: Read-only access to non-send metadata.
1583
if unsafe { world.storages() }
1584
.non_sends
1585
.get(component_id)
1586
.is_some_and(NonSendData::is_present)
1587
{
1588
Ok(())
1589
} else {
1590
Err(SystemParamValidationError::invalid::<Self>(
1591
"Non-send resource does not exist",
1592
))
1593
}
1594
}
1595
1596
#[inline]
1597
unsafe fn get_param<'w, 's>(
1598
&mut component_id: &'s mut Self::State,
1599
system_meta: &SystemMeta,
1600
world: UnsafeWorldCell<'w>,
1601
change_tick: Tick,
1602
) -> Self::Item<'w, 's> {
1603
let (ptr, ticks) = world
1604
.get_non_send_with_ticks(component_id)
1605
.unwrap_or_else(|| {
1606
panic!(
1607
"Non-send resource requested by {} does not exist: {}",
1608
system_meta.name,
1609
DebugName::type_name::<T>()
1610
);
1611
});
1612
NonSendMut {
1613
value: ptr.assert_unique().deref_mut(),
1614
ticks: ComponentTicksMut::from_tick_cells(ticks, system_meta.last_run, change_tick),
1615
}
1616
}
1617
}
1618
1619
// SAFETY: Only reads World archetypes
1620
unsafe impl<'a> ReadOnlySystemParam for &'a Archetypes {}
1621
1622
// SAFETY: no component value access
1623
unsafe impl<'a> SystemParam for &'a Archetypes {
1624
type State = ();
1625
type Item<'w, 's> = &'w Archetypes;
1626
1627
fn init_state(_world: &mut World) -> Self::State {}
1628
1629
fn init_access(
1630
_state: &Self::State,
1631
_system_meta: &mut SystemMeta,
1632
_component_access_set: &mut FilteredAccessSet,
1633
_world: &mut World,
1634
) {
1635
}
1636
1637
#[inline]
1638
unsafe fn get_param<'w, 's>(
1639
_state: &'s mut Self::State,
1640
_system_meta: &SystemMeta,
1641
world: UnsafeWorldCell<'w>,
1642
_change_tick: Tick,
1643
) -> Self::Item<'w, 's> {
1644
world.archetypes()
1645
}
1646
}
1647
1648
// SAFETY: Only reads World components
1649
unsafe impl<'a> ReadOnlySystemParam for &'a Components {}
1650
1651
// SAFETY: no component value access
1652
unsafe impl<'a> SystemParam for &'a Components {
1653
type State = ();
1654
type Item<'w, 's> = &'w Components;
1655
1656
fn init_state(_world: &mut World) -> Self::State {}
1657
1658
fn init_access(
1659
_state: &Self::State,
1660
_system_meta: &mut SystemMeta,
1661
_component_access_set: &mut FilteredAccessSet,
1662
_world: &mut World,
1663
) {
1664
}
1665
1666
#[inline]
1667
unsafe fn get_param<'w, 's>(
1668
_state: &'s mut Self::State,
1669
_system_meta: &SystemMeta,
1670
world: UnsafeWorldCell<'w>,
1671
_change_tick: Tick,
1672
) -> Self::Item<'w, 's> {
1673
world.components()
1674
}
1675
}
1676
1677
// SAFETY: Only reads World entities
1678
unsafe impl<'a> ReadOnlySystemParam for &'a Entities {}
1679
1680
// SAFETY: no component value access
1681
unsafe impl<'a> SystemParam for &'a Entities {
1682
type State = ();
1683
type Item<'w, 's> = &'w Entities;
1684
1685
fn init_state(_world: &mut World) -> Self::State {}
1686
1687
fn init_access(
1688
_state: &Self::State,
1689
_system_meta: &mut SystemMeta,
1690
_component_access_set: &mut FilteredAccessSet,
1691
_world: &mut World,
1692
) {
1693
}
1694
1695
#[inline]
1696
unsafe fn get_param<'w, 's>(
1697
_state: &'s mut Self::State,
1698
_system_meta: &SystemMeta,
1699
world: UnsafeWorldCell<'w>,
1700
_change_tick: Tick,
1701
) -> Self::Item<'w, 's> {
1702
world.entities()
1703
}
1704
}
1705
1706
// SAFETY: Only reads World entities
1707
unsafe impl<'a> ReadOnlySystemParam for &'a EntityAllocator {}
1708
1709
// SAFETY: no component value access
1710
unsafe impl<'a> SystemParam for &'a EntityAllocator {
1711
type State = ();
1712
type Item<'w, 's> = &'w EntityAllocator;
1713
1714
fn init_state(_world: &mut World) -> Self::State {}
1715
1716
fn init_access(
1717
_state: &Self::State,
1718
_system_meta: &mut SystemMeta,
1719
_component_access_set: &mut FilteredAccessSet,
1720
_world: &mut World,
1721
) {
1722
}
1723
1724
#[inline]
1725
unsafe fn get_param<'w, 's>(
1726
_state: &'s mut Self::State,
1727
_system_meta: &SystemMeta,
1728
world: UnsafeWorldCell<'w>,
1729
_change_tick: Tick,
1730
) -> Self::Item<'w, 's> {
1731
world.entity_allocator()
1732
}
1733
}
1734
1735
// SAFETY: Only reads World bundles
1736
unsafe impl<'a> ReadOnlySystemParam for &'a Bundles {}
1737
1738
// SAFETY: no component value access
1739
unsafe impl<'a> SystemParam for &'a Bundles {
1740
type State = ();
1741
type Item<'w, 's> = &'w Bundles;
1742
1743
fn init_state(_world: &mut World) -> Self::State {}
1744
1745
fn init_access(
1746
_state: &Self::State,
1747
_system_meta: &mut SystemMeta,
1748
_component_access_set: &mut FilteredAccessSet,
1749
_world: &mut World,
1750
) {
1751
}
1752
1753
#[inline]
1754
unsafe fn get_param<'w, 's>(
1755
_state: &'s mut Self::State,
1756
_system_meta: &SystemMeta,
1757
world: UnsafeWorldCell<'w>,
1758
_change_tick: Tick,
1759
) -> Self::Item<'w, 's> {
1760
world.bundles()
1761
}
1762
}
1763
1764
/// A [`SystemParam`] that reads the previous and current change ticks of the system.
1765
///
1766
/// A system's change ticks are updated each time it runs:
1767
/// - `last_run` copies the previous value of `change_tick`
1768
/// - `this_run` copies the current value of [`World::read_change_tick`]
1769
///
1770
/// Component change ticks that are more recent than `last_run` will be detected by the system.
1771
/// Those can be read by calling [`last_changed`](crate::change_detection::DetectChanges::last_changed)
1772
/// on a [`Mut<T>`](crate::change_detection::Mut) or [`ResMut<T>`](ResMut).
1773
#[derive(Debug, Clone, Copy)]
1774
pub struct SystemChangeTick {
1775
last_run: Tick,
1776
this_run: Tick,
1777
}
1778
1779
impl SystemChangeTick {
1780
/// Returns the current [`World`] change tick seen by the system.
1781
#[inline]
1782
pub fn this_run(&self) -> Tick {
1783
self.this_run
1784
}
1785
1786
/// Returns the [`World`] change tick seen by the system the previous time it ran.
1787
#[inline]
1788
pub fn last_run(&self) -> Tick {
1789
self.last_run
1790
}
1791
}
1792
1793
// SAFETY: Only reads internal system state
1794
unsafe impl ReadOnlySystemParam for SystemChangeTick {}
1795
1796
// SAFETY: `SystemChangeTick` doesn't require any world access
1797
unsafe impl SystemParam for SystemChangeTick {
1798
type State = ();
1799
type Item<'w, 's> = SystemChangeTick;
1800
1801
fn init_state(_world: &mut World) -> Self::State {}
1802
1803
fn init_access(
1804
_state: &Self::State,
1805
_system_meta: &mut SystemMeta,
1806
_component_access_set: &mut FilteredAccessSet,
1807
_world: &mut World,
1808
) {
1809
}
1810
1811
#[inline]
1812
unsafe fn get_param<'w, 's>(
1813
_state: &'s mut Self::State,
1814
system_meta: &SystemMeta,
1815
_world: UnsafeWorldCell<'w>,
1816
change_tick: Tick,
1817
) -> Self::Item<'w, 's> {
1818
SystemChangeTick {
1819
last_run: system_meta.last_run,
1820
this_run: change_tick,
1821
}
1822
}
1823
}
1824
1825
// SAFETY: Delegates to `T`, which ensures the safety requirements are met
1826
unsafe impl<T: SystemParam> SystemParam for Option<T> {
1827
type State = T::State;
1828
1829
type Item<'world, 'state> = Option<T::Item<'world, 'state>>;
1830
1831
fn init_state(world: &mut World) -> Self::State {
1832
T::init_state(world)
1833
}
1834
1835
fn init_access(
1836
state: &Self::State,
1837
system_meta: &mut SystemMeta,
1838
component_access_set: &mut FilteredAccessSet,
1839
world: &mut World,
1840
) {
1841
T::init_access(state, system_meta, component_access_set, world);
1842
}
1843
1844
#[inline]
1845
unsafe fn get_param<'world, 'state>(
1846
state: &'state mut Self::State,
1847
system_meta: &SystemMeta,
1848
world: UnsafeWorldCell<'world>,
1849
change_tick: Tick,
1850
) -> Self::Item<'world, 'state> {
1851
// SAFETY: Upheld by caller
1852
unsafe {
1853
T::validate_param(state, system_meta, world)
1854
.ok()
1855
.map(|()| T::get_param(state, system_meta, world, change_tick))
1856
}
1857
}
1858
1859
fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) {
1860
T::apply(state, system_meta, world);
1861
}
1862
1863
fn queue(state: &mut Self::State, system_meta: &SystemMeta, world: DeferredWorld) {
1864
T::queue(state, system_meta, world);
1865
}
1866
}
1867
1868
// SAFETY: Delegates to `T`, which ensures the safety requirements are met
1869
unsafe impl<T: ReadOnlySystemParam> ReadOnlySystemParam for Option<T> {}
1870
1871
// SAFETY: Delegates to `T`, which ensures the safety requirements are met
1872
unsafe impl<T: SystemParam> SystemParam for Result<T, SystemParamValidationError> {
1873
type State = T::State;
1874
1875
type Item<'world, 'state> = Result<T::Item<'world, 'state>, SystemParamValidationError>;
1876
1877
fn init_state(world: &mut World) -> Self::State {
1878
T::init_state(world)
1879
}
1880
1881
fn init_access(
1882
state: &Self::State,
1883
system_meta: &mut SystemMeta,
1884
component_access_set: &mut FilteredAccessSet,
1885
world: &mut World,
1886
) {
1887
T::init_access(state, system_meta, component_access_set, world);
1888
}
1889
1890
#[inline]
1891
unsafe fn get_param<'world, 'state>(
1892
state: &'state mut Self::State,
1893
system_meta: &SystemMeta,
1894
world: UnsafeWorldCell<'world>,
1895
change_tick: Tick,
1896
) -> Self::Item<'world, 'state> {
1897
// SAFETY: Upheld by caller
1898
unsafe {
1899
T::validate_param(state, system_meta, world)
1900
.map(|()| T::get_param(state, system_meta, world, change_tick))
1901
}
1902
}
1903
1904
fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) {
1905
T::apply(state, system_meta, world);
1906
}
1907
1908
fn queue(state: &mut Self::State, system_meta: &SystemMeta, world: DeferredWorld) {
1909
T::queue(state, system_meta, world);
1910
}
1911
}
1912
1913
// SAFETY: Delegates to `T`, which ensures the safety requirements are met
1914
unsafe impl<T: ReadOnlySystemParam> ReadOnlySystemParam for Result<T, SystemParamValidationError> {}
1915
1916
/// A [`SystemParam`] that wraps another parameter and causes its system to skip instead of failing when the parameter is invalid.
1917
///
1918
/// # Example
1919
///
1920
/// ```
1921
/// # use bevy_ecs::prelude::*;
1922
/// # #[derive(Resource)]
1923
/// # struct SomeResource;
1924
/// // This system will fail if `SomeResource` is not present.
1925
/// fn fails_on_missing_resource(res: Res<SomeResource>) {}
1926
///
1927
/// // This system will skip without error if `SomeResource` is not present.
1928
/// fn skips_on_missing_resource(res: If<Res<SomeResource>>) {
1929
/// // The inner parameter is available using `Deref`
1930
/// let some_resource: &SomeResource = &res;
1931
/// }
1932
/// # bevy_ecs::system::assert_is_system(skips_on_missing_resource);
1933
/// ```
1934
#[derive(Debug)]
1935
pub struct If<T>(pub T);
1936
1937
impl<T> If<T> {
1938
/// Returns the inner `T`.
1939
///
1940
/// The inner value is `pub`, so you can also obtain it by destructuring the parameter:
1941
///
1942
/// ```
1943
/// # use bevy_ecs::prelude::*;
1944
/// # #[derive(Resource)]
1945
/// # struct SomeResource;
1946
/// fn skips_on_missing_resource(If(res): If<Res<SomeResource>>) {
1947
/// let some_resource: Res<SomeResource> = res;
1948
/// }
1949
/// # bevy_ecs::system::assert_is_system(skips_on_missing_resource);
1950
/// ```
1951
pub fn into_inner(self) -> T {
1952
self.0
1953
}
1954
}
1955
1956
impl<T> Deref for If<T> {
1957
type Target = T;
1958
fn deref(&self) -> &Self::Target {
1959
&self.0
1960
}
1961
}
1962
1963
impl<T> DerefMut for If<T> {
1964
fn deref_mut(&mut self) -> &mut Self::Target {
1965
&mut self.0
1966
}
1967
}
1968
1969
// SAFETY: Delegates to `T`, which ensures the safety requirements are met
1970
unsafe impl<T: SystemParam> SystemParam for If<T> {
1971
type State = T::State;
1972
1973
type Item<'world, 'state> = If<T::Item<'world, 'state>>;
1974
1975
fn init_state(world: &mut World) -> Self::State {
1976
T::init_state(world)
1977
}
1978
1979
fn init_access(
1980
state: &Self::State,
1981
system_meta: &mut SystemMeta,
1982
component_access_set: &mut FilteredAccessSet,
1983
world: &mut World,
1984
) {
1985
T::init_access(state, system_meta, component_access_set, world);
1986
}
1987
1988
#[inline]
1989
unsafe fn validate_param(
1990
state: &mut Self::State,
1991
system_meta: &SystemMeta,
1992
world: UnsafeWorldCell,
1993
) -> Result<(), SystemParamValidationError> {
1994
// SAFETY: Upheld by caller
1995
unsafe { T::validate_param(state, system_meta, world) }.map_err(|mut e| {
1996
e.skipped = true;
1997
e
1998
})
1999
}
2000
2001
#[inline]
2002
unsafe fn get_param<'world, 'state>(
2003
state: &'state mut Self::State,
2004
system_meta: &SystemMeta,
2005
world: UnsafeWorldCell<'world>,
2006
change_tick: Tick,
2007
) -> Self::Item<'world, 'state> {
2008
// SAFETY: Upheld by caller.
2009
If(unsafe { T::get_param(state, system_meta, world, change_tick) })
2010
}
2011
2012
fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) {
2013
T::apply(state, system_meta, world);
2014
}
2015
2016
fn queue(state: &mut Self::State, system_meta: &SystemMeta, world: DeferredWorld) {
2017
T::queue(state, system_meta, world);
2018
}
2019
}
2020
2021
// SAFETY: Delegates to `T`, which ensures the safety requirements are met
2022
unsafe impl<T: ReadOnlySystemParam> ReadOnlySystemParam for If<T> {}
2023
2024
// SAFETY: Registers access for each element of `state`.
2025
// If any one conflicts, it will panic.
2026
unsafe impl<T: SystemParam> SystemParam for Vec<T> {
2027
type State = Vec<T::State>;
2028
2029
type Item<'world, 'state> = Vec<T::Item<'world, 'state>>;
2030
2031
fn init_state(_world: &mut World) -> Self::State {
2032
Vec::new()
2033
}
2034
2035
fn init_access(
2036
state: &Self::State,
2037
system_meta: &mut SystemMeta,
2038
component_access_set: &mut FilteredAccessSet,
2039
world: &mut World,
2040
) {
2041
for state in state {
2042
T::init_access(state, system_meta, component_access_set, world);
2043
}
2044
}
2045
2046
#[inline]
2047
unsafe fn validate_param(
2048
state: &mut Self::State,
2049
system_meta: &SystemMeta,
2050
world: UnsafeWorldCell,
2051
) -> Result<(), SystemParamValidationError> {
2052
for state in state {
2053
// SAFETY: Upheld by caller
2054
unsafe { T::validate_param(state, system_meta, world)? };
2055
}
2056
Ok(())
2057
}
2058
2059
#[inline]
2060
unsafe fn get_param<'world, 'state>(
2061
state: &'state mut Self::State,
2062
system_meta: &SystemMeta,
2063
world: UnsafeWorldCell<'world>,
2064
change_tick: Tick,
2065
) -> Self::Item<'world, 'state> {
2066
state
2067
.iter_mut()
2068
// SAFETY:
2069
// - We initialized the access for each parameter in `init_access`, so the caller ensures we have access to any world data needed by each param.
2070
// - The caller ensures this was the world used to initialize our state, and we used that world to initialize parameter states
2071
.map(|state| unsafe { T::get_param(state, system_meta, world, change_tick) })
2072
.collect()
2073
}
2074
2075
fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) {
2076
for state in state {
2077
T::apply(state, system_meta, world);
2078
}
2079
}
2080
2081
fn queue(state: &mut Self::State, system_meta: &SystemMeta, mut world: DeferredWorld) {
2082
for state in state {
2083
T::queue(state, system_meta, world.reborrow());
2084
}
2085
}
2086
}
2087
2088
// SAFETY: Registers access for each element of `state`.
2089
// If any one conflicts with a previous parameter,
2090
// the call passing a copy of the current access will panic.
2091
unsafe impl<T: SystemParam> SystemParam for ParamSet<'_, '_, Vec<T>> {
2092
type State = Vec<T::State>;
2093
2094
type Item<'world, 'state> = ParamSet<'world, 'state, Vec<T>>;
2095
2096
fn init_state(_world: &mut World) -> Self::State {
2097
Vec::new()
2098
}
2099
2100
fn init_access(
2101
state: &Self::State,
2102
system_meta: &mut SystemMeta,
2103
component_access_set: &mut FilteredAccessSet,
2104
world: &mut World,
2105
) {
2106
for state in state {
2107
// Call `init_access` on a clone of the original access set to check for conflicts
2108
let component_access_set_clone = &mut component_access_set.clone();
2109
T::init_access(state, system_meta, component_access_set_clone, world);
2110
}
2111
for state in state {
2112
// Pretend to add the param to the system alone to gather the new access,
2113
// then merge its access into the system.
2114
let mut access_set = FilteredAccessSet::new();
2115
T::init_access(state, system_meta, &mut access_set, world);
2116
component_access_set.extend(access_set);
2117
}
2118
}
2119
2120
#[inline]
2121
unsafe fn get_param<'world, 'state>(
2122
state: &'state mut Self::State,
2123
system_meta: &SystemMeta,
2124
world: UnsafeWorldCell<'world>,
2125
change_tick: Tick,
2126
) -> Self::Item<'world, 'state> {
2127
ParamSet {
2128
param_states: state,
2129
system_meta: system_meta.clone(),
2130
world,
2131
change_tick,
2132
}
2133
}
2134
2135
fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) {
2136
for state in state {
2137
T::apply(state, system_meta, world);
2138
}
2139
}
2140
2141
fn queue(state: &mut Self::State, system_meta: &SystemMeta, mut world: DeferredWorld) {
2142
for state in state {
2143
T::queue(state, system_meta, world.reborrow());
2144
}
2145
}
2146
}
2147
2148
impl<T: SystemParam> ParamSet<'_, '_, Vec<T>> {
2149
/// Accesses the parameter at the given index.
2150
/// No other parameters may be accessed while this one is active.
2151
pub fn get_mut(&mut self, index: usize) -> T::Item<'_, '_> {
2152
// SAFETY:
2153
// - We initialized the access for each parameter, so the caller ensures we have access to any world data needed by any param.
2154
// We have mutable access to the ParamSet, so no other params in the set are active.
2155
// - The caller of `get_param` ensured that this was the world used to initialize our state, and we used that world to initialize parameter states
2156
unsafe {
2157
T::get_param(
2158
&mut self.param_states[index],
2159
&self.system_meta,
2160
self.world,
2161
self.change_tick,
2162
)
2163
}
2164
}
2165
2166
/// Calls a closure for each parameter in the set.
2167
pub fn for_each(&mut self, mut f: impl FnMut(T::Item<'_, '_>)) {
2168
self.param_states.iter_mut().for_each(|state| {
2169
f(
2170
// SAFETY:
2171
// - We initialized the access for each parameter, so the caller ensures we have access to any world data needed by any param.
2172
// We have mutable access to the ParamSet, so no other params in the set are active.
2173
// - The caller of `get_param` ensured that this was the world used to initialize our state, and we used that world to initialize parameter states
2174
unsafe { T::get_param(state, &self.system_meta, self.world, self.change_tick) },
2175
);
2176
});
2177
}
2178
}
2179
2180
macro_rules! impl_system_param_tuple {
2181
($(#[$meta:meta])* $($param: ident),*) => {
2182
$(#[$meta])*
2183
// SAFETY: tuple consists only of ReadOnlySystemParams
2184
unsafe impl<$($param: ReadOnlySystemParam),*> ReadOnlySystemParam for ($($param,)*) {}
2185
2186
#[expect(
2187
clippy::allow_attributes,
2188
reason = "This is in a macro, and as such, the below lints may not always apply."
2189
)]
2190
#[allow(
2191
non_snake_case,
2192
reason = "Certain variable names are provided by the caller, not by us."
2193
)]
2194
#[allow(
2195
unused_variables,
2196
reason = "Zero-length tuples won't use some of the parameters."
2197
)]
2198
#[allow(clippy::unused_unit, reason = "Zero length tuple is unit.")]
2199
$(#[$meta])*
2200
// SAFETY: implementers of each `SystemParam` in the tuple have validated their impls
2201
unsafe impl<$($param: SystemParam),*> SystemParam for ($($param,)*) {
2202
type State = ($($param::State,)*);
2203
type Item<'w, 's> = ($($param::Item::<'w, 's>,)*);
2204
2205
#[inline]
2206
#[track_caller]
2207
fn init_state(world: &mut World) -> Self::State {
2208
($($param::init_state(world),)*)
2209
}
2210
2211
fn init_access(state: &Self::State, _system_meta: &mut SystemMeta, _component_access_set: &mut FilteredAccessSet, _world: &mut World) {
2212
let ($($param,)*) = state;
2213
$($param::init_access($param, _system_meta, _component_access_set, _world);)*
2214
}
2215
2216
#[inline]
2217
fn apply(($($param,)*): &mut Self::State, system_meta: &SystemMeta, world: &mut World) {
2218
$($param::apply($param, system_meta, world);)*
2219
}
2220
2221
#[inline]
2222
#[allow(
2223
unused_mut,
2224
reason = "The `world` parameter is unused for zero-length tuples; however, it must be mutable for other lengths of tuples."
2225
)]
2226
fn queue(($($param,)*): &mut Self::State, system_meta: &SystemMeta, mut world: DeferredWorld) {
2227
$($param::queue($param, system_meta, world.reborrow());)*
2228
}
2229
2230
#[inline]
2231
unsafe fn validate_param(
2232
state: &mut Self::State,
2233
system_meta: &SystemMeta,
2234
world: UnsafeWorldCell,
2235
) -> Result<(), SystemParamValidationError> {
2236
let ($($param,)*) = state;
2237
2238
#[allow(
2239
unused_unsafe,
2240
reason = "Zero-length tuples won't have any params to validate."
2241
)]
2242
// SAFETY: Upheld by caller
2243
unsafe {
2244
$(
2245
$param::validate_param($param, system_meta, world)?;
2246
)*
2247
}
2248
Ok(())
2249
}
2250
2251
#[inline]
2252
#[track_caller]
2253
unsafe fn get_param<'w, 's>(
2254
state: &'s mut Self::State,
2255
system_meta: &SystemMeta,
2256
world: UnsafeWorldCell<'w>,
2257
change_tick: Tick,
2258
) -> Self::Item<'w, 's> {
2259
let ($($param,)*) = state;
2260
2261
#[allow(
2262
unused_unsafe,
2263
reason = "Zero-length tuples won't have any params to validate."
2264
)]
2265
// SAFETY: Upheld by caller
2266
unsafe {
2267
#[allow(
2268
clippy::unused_unit,
2269
reason = "Zero-length tuples won't have any params to get."
2270
)]
2271
($($param::get_param($param, system_meta, world, change_tick),)*)
2272
}
2273
}
2274
}
2275
};
2276
}
2277
2278
all_tuples!(
2279
#[doc(fake_variadic)]
2280
impl_system_param_tuple,
2281
0,
2282
16,
2283
P
2284
);
2285
2286
/// Contains type aliases for built-in [`SystemParam`]s with `'static` lifetimes.
2287
/// This makes it more convenient to refer to these types in contexts where
2288
/// explicit lifetime annotations are required.
2289
///
2290
/// Note that this is entirely safe and tracks lifetimes correctly.
2291
/// This purely exists for convenience.
2292
///
2293
/// You can't instantiate a static `SystemParam`, you'll always end up with
2294
/// `Res<'w, T>`, `ResMut<'w, T>` or `&'w T` bound to the lifetime of the provided
2295
/// `&'w World`.
2296
///
2297
/// [`SystemParam`]: super::SystemParam
2298
pub mod lifetimeless {
2299
/// A [`Query`](super::Query) with `'static` lifetimes.
2300
pub type SQuery<D, F = ()> = super::Query<'static, 'static, D, F>;
2301
/// A shorthand for writing `&'static T`.
2302
pub type Read<T> = &'static T;
2303
/// A shorthand for writing `&'static mut T`.
2304
pub type Write<T> = &'static mut T;
2305
/// A [`Res`](super::Res) with `'static` lifetimes.
2306
pub type SRes<T> = super::Res<'static, T>;
2307
/// A [`ResMut`](super::ResMut) with `'static` lifetimes.
2308
pub type SResMut<T> = super::ResMut<'static, T>;
2309
/// [`Commands`](crate::system::Commands) with `'static` lifetimes.
2310
pub type SCommands = crate::system::Commands<'static, 'static>;
2311
}
2312
2313
/// A helper for using system parameters in generic contexts
2314
///
2315
/// This type is a [`SystemParam`] adapter which always has
2316
/// `Self::Item == Self` (ignoring lifetimes for brevity),
2317
/// no matter the argument [`SystemParam`] (`P`) (other than
2318
/// that `P` must be `'static`)
2319
///
2320
/// This makes it useful for having arbitrary [`SystemParam`] type arguments
2321
/// to function systems, or for generic types using the [`derive@SystemParam`]
2322
/// derive:
2323
///
2324
/// ```
2325
/// # use bevy_ecs::prelude::*;
2326
/// use bevy_ecs::system::{SystemParam, StaticSystemParam};
2327
/// #[derive(SystemParam)]
2328
/// struct GenericParam<'w,'s, T: SystemParam + 'static> {
2329
/// field: StaticSystemParam<'w, 's, T>,
2330
/// }
2331
/// fn do_thing_generically<T: SystemParam + 'static>(t: StaticSystemParam<T>) {}
2332
///
2333
/// fn check_always_is_system<T: SystemParam + 'static>(){
2334
/// bevy_ecs::system::assert_is_system(do_thing_generically::<T>);
2335
/// }
2336
/// ```
2337
/// Note that in a real case you'd generally want
2338
/// additional bounds on `P`, for your use of the parameter
2339
/// to have a reason to be generic.
2340
///
2341
/// For example, using this would allow a type to be generic over
2342
/// whether a resource is accessed mutably or not, with
2343
/// impls being bounded on [`P: Deref<Target=MyType>`](Deref), and
2344
/// [`P: DerefMut<Target=MyType>`](DerefMut) depending on whether the
2345
/// method requires mutable access or not.
2346
///
2347
/// The method which doesn't use this type will not compile:
2348
/// ```compile_fail
2349
/// # use bevy_ecs::prelude::*;
2350
/// # use bevy_ecs::system::{SystemParam, StaticSystemParam};
2351
///
2352
/// fn do_thing_generically<T: SystemParam + 'static>(t: T) {}
2353
///
2354
/// #[derive(SystemParam)]
2355
/// struct GenericParam<'w, 's, T: SystemParam> {
2356
/// field: T,
2357
/// // Use the lifetimes in this type, or they will be unbound.
2358
/// phantom: std::marker::PhantomData<&'w &'s ()>
2359
/// }
2360
/// # fn check_always_is_system<T: SystemParam + 'static>(){
2361
/// # bevy_ecs::system::assert_is_system(do_thing_generically::<T>);
2362
/// # }
2363
/// ```
2364
pub struct StaticSystemParam<'w, 's, P: SystemParam>(SystemParamItem<'w, 's, P>);
2365
2366
impl<'w, 's, P: SystemParam> Deref for StaticSystemParam<'w, 's, P> {
2367
type Target = SystemParamItem<'w, 's, P>;
2368
2369
fn deref(&self) -> &Self::Target {
2370
&self.0
2371
}
2372
}
2373
2374
impl<'w, 's, P: SystemParam> DerefMut for StaticSystemParam<'w, 's, P> {
2375
fn deref_mut(&mut self) -> &mut Self::Target {
2376
&mut self.0
2377
}
2378
}
2379
2380
impl<'w, 's, P: SystemParam> StaticSystemParam<'w, 's, P> {
2381
/// Get the value of the parameter
2382
pub fn into_inner(self) -> SystemParamItem<'w, 's, P> {
2383
self.0
2384
}
2385
}
2386
2387
// SAFETY: This doesn't add any more reads, and the delegated fetch confirms it
2388
unsafe impl<'w, 's, P: ReadOnlySystemParam + 'static> ReadOnlySystemParam
2389
for StaticSystemParam<'w, 's, P>
2390
{
2391
}
2392
2393
// SAFETY: all methods are just delegated to `P`'s `SystemParam` implementation
2394
unsafe impl<P: SystemParam + 'static> SystemParam for StaticSystemParam<'_, '_, P> {
2395
type State = P::State;
2396
type Item<'world, 'state> = StaticSystemParam<'world, 'state, P>;
2397
2398
fn init_state(world: &mut World) -> Self::State {
2399
P::init_state(world)
2400
}
2401
2402
fn init_access(
2403
state: &Self::State,
2404
system_meta: &mut SystemMeta,
2405
component_access_set: &mut FilteredAccessSet,
2406
world: &mut World,
2407
) {
2408
P::init_access(state, system_meta, component_access_set, world);
2409
}
2410
2411
fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) {
2412
P::apply(state, system_meta, world);
2413
}
2414
2415
fn queue(state: &mut Self::State, system_meta: &SystemMeta, world: DeferredWorld) {
2416
P::queue(state, system_meta, world);
2417
}
2418
2419
#[inline]
2420
unsafe fn validate_param(
2421
state: &mut Self::State,
2422
system_meta: &SystemMeta,
2423
world: UnsafeWorldCell,
2424
) -> Result<(), SystemParamValidationError> {
2425
// SAFETY: Upheld by caller
2426
unsafe { P::validate_param(state, system_meta, world) }
2427
}
2428
2429
#[inline]
2430
unsafe fn get_param<'world, 'state>(
2431
state: &'state mut Self::State,
2432
system_meta: &SystemMeta,
2433
world: UnsafeWorldCell<'world>,
2434
change_tick: Tick,
2435
) -> Self::Item<'world, 'state> {
2436
// SAFETY: Defer to the safety of P::SystemParam
2437
StaticSystemParam(unsafe { P::get_param(state, system_meta, world, change_tick) })
2438
}
2439
}
2440
2441
// SAFETY: No world access.
2442
unsafe impl<T: ?Sized> SystemParam for PhantomData<T> {
2443
type State = ();
2444
type Item<'world, 'state> = Self;
2445
2446
fn init_state(_world: &mut World) -> Self::State {}
2447
2448
fn init_access(
2449
_state: &Self::State,
2450
_system_meta: &mut SystemMeta,
2451
_component_access_set: &mut FilteredAccessSet,
2452
_world: &mut World,
2453
) {
2454
}
2455
2456
#[inline]
2457
unsafe fn get_param<'world, 'state>(
2458
_state: &'state mut Self::State,
2459
_system_meta: &SystemMeta,
2460
_world: UnsafeWorldCell<'world>,
2461
_change_tick: Tick,
2462
) -> Self::Item<'world, 'state> {
2463
PhantomData
2464
}
2465
}
2466
2467
// SAFETY: No world access.
2468
unsafe impl<T: ?Sized> ReadOnlySystemParam for PhantomData<T> {}
2469
2470
/// A [`SystemParam`] with a type that can be configured at runtime.
2471
///
2472
/// To be useful, this must be configured using a [`DynParamBuilder`](crate::system::DynParamBuilder) to build the system using a [`SystemParamBuilder`](crate::prelude::SystemParamBuilder).
2473
///
2474
/// # Examples
2475
///
2476
/// ```
2477
/// # use bevy_ecs::{prelude::*, system::*};
2478
/// #
2479
/// # #[derive(Default, Resource)]
2480
/// # struct A;
2481
/// #
2482
/// # #[derive(Default, Resource)]
2483
/// # struct B;
2484
/// #
2485
/// # let mut world = World::new();
2486
/// # world.init_resource::<A>();
2487
/// # world.init_resource::<B>();
2488
/// #
2489
/// // If the inner parameter doesn't require any special building, use `ParamBuilder`.
2490
/// // Either specify the type parameter on `DynParamBuilder::new()` ...
2491
/// let system = (DynParamBuilder::new::<Res<A>>(ParamBuilder),)
2492
/// .build_state(&mut world)
2493
/// .build_system(expects_res_a);
2494
/// # world.run_system_once(system);
2495
///
2496
/// // ... or use a factory method on `ParamBuilder` that returns a specific type.
2497
/// let system = (DynParamBuilder::new(ParamBuilder::resource::<A>()),)
2498
/// .build_state(&mut world)
2499
/// .build_system(expects_res_a);
2500
/// # world.run_system_once(system);
2501
///
2502
/// fn expects_res_a(mut param: DynSystemParam) {
2503
/// // Use the `downcast` methods to retrieve the inner parameter.
2504
/// // They will return `None` if the type does not match.
2505
/// assert!(param.is::<Res<A>>());
2506
/// assert!(!param.is::<Res<B>>());
2507
/// assert!(param.downcast_mut::<Res<B>>().is_none());
2508
/// let res = param.downcast_mut::<Res<A>>().unwrap();
2509
/// // The type parameter can be left out if it can be determined from use.
2510
/// let res: Res<A> = param.downcast().unwrap();
2511
/// }
2512
///
2513
/// let system = (
2514
/// // If the inner parameter also requires building,
2515
/// // pass the appropriate `SystemParamBuilder`.
2516
/// DynParamBuilder::new(LocalBuilder(10usize)),
2517
/// // `DynSystemParam` is just an ordinary `SystemParam`,
2518
/// // and can be combined with other parameters as usual!
2519
/// ParamBuilder::query(),
2520
/// )
2521
/// .build_state(&mut world)
2522
/// .build_system(|param: DynSystemParam, query: Query<()>| {
2523
/// let local: Local<usize> = param.downcast::<Local<usize>>().unwrap();
2524
/// assert_eq!(*local, 10);
2525
/// });
2526
/// # world.run_system_once(system);
2527
/// ```
2528
pub struct DynSystemParam<'w, 's> {
2529
/// A `ParamState<T>` wrapping the state for the underlying system param.
2530
state: &'s mut dyn Any,
2531
world: UnsafeWorldCell<'w>,
2532
system_meta: SystemMeta,
2533
change_tick: Tick,
2534
}
2535
2536
impl<'w, 's> DynSystemParam<'w, 's> {
2537
/// # Safety
2538
/// - `state` must be a `ParamState<T>` for some inner `T: SystemParam`.
2539
/// - The passed [`UnsafeWorldCell`] must have access to any world data registered
2540
/// in [`init_state`](SystemParam::init_state) for the inner system param.
2541
/// - `world` must be the same `World` that was used to initialize
2542
/// [`state`](SystemParam::init_state) for the inner system param.
2543
unsafe fn new(
2544
state: &'s mut dyn Any,
2545
world: UnsafeWorldCell<'w>,
2546
system_meta: SystemMeta,
2547
change_tick: Tick,
2548
) -> Self {
2549
Self {
2550
state,
2551
world,
2552
system_meta,
2553
change_tick,
2554
}
2555
}
2556
2557
/// Returns `true` if the inner system param is the same as `T`.
2558
pub fn is<T: SystemParam>(&self) -> bool
2559
// See downcast() function for an explanation of the where clause
2560
where
2561
T::Item<'static, 'static>: SystemParam<Item<'w, 's> = T> + 'static,
2562
{
2563
self.state.is::<ParamState<T::Item<'static, 'static>>>()
2564
}
2565
2566
/// Returns the inner system param if it is the correct type.
2567
/// This consumes the dyn param, so the returned param can have its original world and state lifetimes.
2568
pub fn downcast<T: SystemParam>(self) -> Option<T>
2569
// See downcast() function for an explanation of the where clause
2570
where
2571
T::Item<'static, 'static>: SystemParam<Item<'w, 's> = T> + 'static,
2572
{
2573
// SAFETY:
2574
// - `DynSystemParam::new()` ensures `state` is a `ParamState<T>`, that the world matches,
2575
// and that it has access required by the inner system param.
2576
// - This consumes the `DynSystemParam`, so it is the only use of `world` with this access and it is available for `'w`.
2577
unsafe { downcast::<T>(self.state, &self.system_meta, self.world, self.change_tick) }
2578
}
2579
2580
/// Returns the inner system parameter if it is the correct type.
2581
/// This borrows the dyn param, so the returned param is only valid for the duration of that borrow.
2582
pub fn downcast_mut<'a, T: SystemParam>(&'a mut self) -> Option<T>
2583
// See downcast() function for an explanation of the where clause
2584
where
2585
T::Item<'static, 'static>: SystemParam<Item<'a, 'a> = T> + 'static,
2586
{
2587
// SAFETY:
2588
// - `DynSystemParam::new()` ensures `state` is a `ParamState<T>`, that the world matches,
2589
// and that it has access required by the inner system param.
2590
// - This exclusively borrows the `DynSystemParam` for `'_`, so it is the only use of `world` with this access for `'_`.
2591
unsafe { downcast::<T>(self.state, &self.system_meta, self.world, self.change_tick) }
2592
}
2593
2594
/// Returns the inner system parameter if it is the correct type.
2595
/// This borrows the dyn param, so the returned param is only valid for the duration of that borrow,
2596
/// but since it only performs read access it can keep the original world lifetime.
2597
/// This can be useful with methods like [`Query::iter_inner()`] or [`Res::into_inner()`]
2598
/// to obtain references with the original world lifetime.
2599
pub fn downcast_mut_inner<'a, T: ReadOnlySystemParam>(&'a mut self) -> Option<T>
2600
// See downcast() function for an explanation of the where clause
2601
where
2602
T::Item<'static, 'static>: SystemParam<Item<'w, 'a> = T> + 'static,
2603
{
2604
// SAFETY:
2605
// - `DynSystemParam::new()` ensures `state` is a `ParamState<T>`, that the world matches,
2606
// and that it has access required by the inner system param.
2607
// - The inner system param only performs read access, so it's safe to copy that access for the full `'w` lifetime.
2608
unsafe { downcast::<T>(self.state, &self.system_meta, self.world, self.change_tick) }
2609
}
2610
}
2611
2612
/// # Safety
2613
/// - `state` must be a `ParamState<T>` for some inner `T: SystemParam`.
2614
/// - The passed [`UnsafeWorldCell`] must have access to any world data registered
2615
/// in [`init_state`](SystemParam::init_state) for the inner system param.
2616
/// - `world` must be the same `World` that was used to initialize
2617
/// [`state`](SystemParam::init_state) for the inner system param.
2618
unsafe fn downcast<'w, 's, T: SystemParam>(
2619
state: &'s mut dyn Any,
2620
system_meta: &SystemMeta,
2621
world: UnsafeWorldCell<'w>,
2622
change_tick: Tick,
2623
) -> Option<T>
2624
// We need a 'static version of the SystemParam to use with `Any::downcast_mut()`,
2625
// and we need a <'w, 's> version to actually return.
2626
// The type parameter T must be the one we return in order to get type inference from the return value.
2627
// So we use `T::Item<'static, 'static>` as the 'static version, and require that it be 'static.
2628
// That means the return value will be T::Item<'static, 'static>::Item<'w, 's>,
2629
// so we constrain that to be equal to T.
2630
// Every actual `SystemParam` implementation has `T::Item == T` up to lifetimes,
2631
// so they should all work with this constraint.
2632
where
2633
T::Item<'static, 'static>: SystemParam<Item<'w, 's> = T> + 'static,
2634
{
2635
state
2636
.downcast_mut::<ParamState<T::Item<'static, 'static>>>()
2637
.map(|state| {
2638
// SAFETY:
2639
// - The caller ensures the world has access for the underlying system param,
2640
// and since the downcast succeeded, the underlying system param is T.
2641
// - The caller ensures the `world` matches.
2642
unsafe { T::Item::get_param(&mut state.0, system_meta, world, change_tick) }
2643
})
2644
}
2645
2646
/// The [`SystemParam::State`] for a [`DynSystemParam`].
2647
pub struct DynSystemParamState(Box<dyn DynParamState>);
2648
2649
impl DynSystemParamState {
2650
pub(crate) fn new<T: SystemParam + 'static>(state: T::State) -> Self {
2651
Self(Box::new(ParamState::<T>(state)))
2652
}
2653
}
2654
2655
/// Allows a [`SystemParam::State`] to be used as a trait object for implementing [`DynSystemParam`].
2656
trait DynParamState: Sync + Send + Any {
2657
/// Applies any deferred mutations stored in this [`SystemParam`]'s state.
2658
/// This is used to apply [`Commands`] during [`ApplyDeferred`](crate::prelude::ApplyDeferred).
2659
///
2660
/// [`Commands`]: crate::prelude::Commands
2661
fn apply(&mut self, system_meta: &SystemMeta, world: &mut World);
2662
2663
/// Queues any deferred mutations to be applied at the next [`ApplyDeferred`](crate::prelude::ApplyDeferred).
2664
fn queue(&mut self, system_meta: &SystemMeta, world: DeferredWorld);
2665
2666
/// Registers any [`World`] access used by this [`SystemParam`]
2667
fn init_access(
2668
&self,
2669
system_meta: &mut SystemMeta,
2670
component_access_set: &mut FilteredAccessSet,
2671
world: &mut World,
2672
);
2673
2674
/// Refer to [`SystemParam::validate_param`].
2675
///
2676
/// # Safety
2677
/// Refer to [`SystemParam::validate_param`].
2678
unsafe fn validate_param(
2679
&mut self,
2680
system_meta: &SystemMeta,
2681
world: UnsafeWorldCell,
2682
) -> Result<(), SystemParamValidationError>;
2683
}
2684
2685
/// A wrapper around a [`SystemParam::State`] that can be used as a trait object in a [`DynSystemParam`].
2686
struct ParamState<T: SystemParam>(T::State);
2687
2688
impl<T: SystemParam + 'static> DynParamState for ParamState<T> {
2689
fn apply(&mut self, system_meta: &SystemMeta, world: &mut World) {
2690
T::apply(&mut self.0, system_meta, world);
2691
}
2692
2693
fn queue(&mut self, system_meta: &SystemMeta, world: DeferredWorld) {
2694
T::queue(&mut self.0, system_meta, world);
2695
}
2696
2697
fn init_access(
2698
&self,
2699
system_meta: &mut SystemMeta,
2700
component_access_set: &mut FilteredAccessSet,
2701
world: &mut World,
2702
) {
2703
T::init_access(&self.0, system_meta, component_access_set, world);
2704
}
2705
2706
unsafe fn validate_param(
2707
&mut self,
2708
system_meta: &SystemMeta,
2709
world: UnsafeWorldCell,
2710
) -> Result<(), SystemParamValidationError> {
2711
// SAFETY: Upheld by caller
2712
unsafe { T::validate_param(&mut self.0, system_meta, world) }
2713
}
2714
}
2715
2716
// SAFETY: Delegates to the wrapped parameter, which ensures the safety requirements are met
2717
unsafe impl SystemParam for DynSystemParam<'_, '_> {
2718
type State = DynSystemParamState;
2719
2720
type Item<'world, 'state> = DynSystemParam<'world, 'state>;
2721
2722
fn init_state(_world: &mut World) -> Self::State {
2723
DynSystemParamState::new::<()>(())
2724
}
2725
2726
fn init_access(
2727
state: &Self::State,
2728
system_meta: &mut SystemMeta,
2729
component_access_set: &mut FilteredAccessSet,
2730
world: &mut World,
2731
) {
2732
state
2733
.0
2734
.init_access(system_meta, component_access_set, world);
2735
}
2736
2737
#[inline]
2738
unsafe fn validate_param(
2739
state: &mut Self::State,
2740
system_meta: &SystemMeta,
2741
world: UnsafeWorldCell,
2742
) -> Result<(), SystemParamValidationError> {
2743
// SAFETY: Upheld by caller.
2744
unsafe { state.0.validate_param(system_meta, world) }
2745
}
2746
2747
#[inline]
2748
unsafe fn get_param<'world, 'state>(
2749
state: &'state mut Self::State,
2750
system_meta: &SystemMeta,
2751
world: UnsafeWorldCell<'world>,
2752
change_tick: Tick,
2753
) -> Self::Item<'world, 'state> {
2754
// SAFETY:
2755
// - `state.0` is a boxed `ParamState<T>`.
2756
// - `init_access` calls `DynParamState::init_access`, which calls `init_access` on the inner parameter,
2757
// so the caller ensures the world has the necessary access.
2758
// - The caller ensures that the provided world is the same and has the required access.
2759
unsafe { DynSystemParam::new(state.0.as_mut(), world, system_meta.clone(), change_tick) }
2760
}
2761
2762
fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) {
2763
state.0.apply(system_meta, world);
2764
}
2765
2766
fn queue(state: &mut Self::State, system_meta: &SystemMeta, world: DeferredWorld) {
2767
state.0.queue(system_meta, world);
2768
}
2769
}
2770
2771
// SAFETY: Resource ComponentId access is applied to the access. If this FilteredResources
2772
// conflicts with any prior access, a panic will occur.
2773
unsafe impl SystemParam for FilteredResources<'_, '_> {
2774
type State = Access;
2775
2776
type Item<'world, 'state> = FilteredResources<'world, 'state>;
2777
2778
fn init_state(_world: &mut World) -> Self::State {
2779
Access::new()
2780
}
2781
2782
fn init_access(
2783
access: &Self::State,
2784
system_meta: &mut SystemMeta,
2785
component_access_set: &mut FilteredAccessSet,
2786
world: &mut World,
2787
) {
2788
let combined_access = component_access_set.combined_access();
2789
let conflicts = combined_access.get_conflicts(access);
2790
if !conflicts.is_empty() {
2791
let accesses = conflicts.format_conflict_list(world);
2792
let system_name = &system_meta.name;
2793
panic!("error[B0002]: FilteredResources in system {system_name} accesses resources(s){accesses} in a way that conflicts with a previous system parameter. Consider removing the duplicate access. See: https://bevy.org/learn/errors/b0002");
2794
}
2795
2796
if access.has_read_all_resources() {
2797
component_access_set.add_unfiltered_read_all_resources();
2798
} else {
2799
for component_id in access.resource_reads_and_writes() {
2800
component_access_set.add_unfiltered_resource_read(component_id);
2801
}
2802
}
2803
}
2804
2805
unsafe fn get_param<'world, 'state>(
2806
state: &'state mut Self::State,
2807
system_meta: &SystemMeta,
2808
world: UnsafeWorldCell<'world>,
2809
change_tick: Tick,
2810
) -> Self::Item<'world, 'state> {
2811
// SAFETY: The caller ensures that `world` has access to anything registered in `init_access`,
2812
// and we registered all resource access in `state``.
2813
unsafe { FilteredResources::new(world, state, system_meta.last_run, change_tick) }
2814
}
2815
}
2816
2817
// SAFETY: FilteredResources only reads resources.
2818
unsafe impl ReadOnlySystemParam for FilteredResources<'_, '_> {}
2819
2820
// SAFETY: Resource ComponentId access is applied to the access. If this FilteredResourcesMut
2821
// conflicts with any prior access, a panic will occur.
2822
unsafe impl SystemParam for FilteredResourcesMut<'_, '_> {
2823
type State = Access;
2824
2825
type Item<'world, 'state> = FilteredResourcesMut<'world, 'state>;
2826
2827
fn init_state(_world: &mut World) -> Self::State {
2828
Access::new()
2829
}
2830
2831
fn init_access(
2832
access: &Self::State,
2833
system_meta: &mut SystemMeta,
2834
component_access_set: &mut FilteredAccessSet,
2835
world: &mut World,
2836
) {
2837
let combined_access = component_access_set.combined_access();
2838
let conflicts = combined_access.get_conflicts(access);
2839
if !conflicts.is_empty() {
2840
let accesses = conflicts.format_conflict_list(world);
2841
let system_name = &system_meta.name;
2842
panic!("error[B0002]: FilteredResourcesMut in system {system_name} accesses resources(s){accesses} in a way that conflicts with a previous system parameter. Consider removing the duplicate access. See: https://bevy.org/learn/errors/b0002");
2843
}
2844
2845
if access.has_read_all_resources() {
2846
component_access_set.add_unfiltered_read_all_resources();
2847
} else {
2848
for component_id in access.resource_reads() {
2849
component_access_set.add_unfiltered_resource_read(component_id);
2850
}
2851
}
2852
2853
if access.has_write_all_resources() {
2854
component_access_set.add_unfiltered_write_all_resources();
2855
} else {
2856
for component_id in access.resource_writes() {
2857
component_access_set.add_unfiltered_resource_write(component_id);
2858
}
2859
}
2860
}
2861
2862
unsafe fn get_param<'world, 'state>(
2863
state: &'state mut Self::State,
2864
system_meta: &SystemMeta,
2865
world: UnsafeWorldCell<'world>,
2866
change_tick: Tick,
2867
) -> Self::Item<'world, 'state> {
2868
// SAFETY: The caller ensures that `world` has access to anything registered in `init_access`,
2869
// and we registered all resource access in `state``.
2870
unsafe { FilteredResourcesMut::new(world, state, system_meta.last_run, change_tick) }
2871
}
2872
}
2873
2874
/// An error that occurs when a system parameter is not valid,
2875
/// used by system executors to determine what to do with a system.
2876
///
2877
/// Returned as an error from [`SystemParam::validate_param`],
2878
/// and handled using the unified error handling mechanisms defined in [`bevy_ecs::error`].
2879
#[derive(Debug, PartialEq, Eq, Clone, Error)]
2880
pub struct SystemParamValidationError {
2881
/// Whether the system should be skipped.
2882
///
2883
/// If `false`, the error should be handled.
2884
/// By default, this will result in a panic. See [`error`](`crate::error`) for more information.
2885
///
2886
/// This is the default behavior, and is suitable for system params that should *always* be valid,
2887
/// either because sensible fallback behavior exists (like [`Query`]) or because
2888
/// failures in validation should be considered a bug in the user's logic that must be immediately addressed (like [`Res`]).
2889
///
2890
/// If `true`, the system should be skipped.
2891
/// This is set by wrapping the system param in [`If`],
2892
/// and indicates that the system is intended to only operate in certain application states.
2893
pub skipped: bool,
2894
2895
/// A message describing the validation error.
2896
pub message: Cow<'static, str>,
2897
2898
/// A string identifying the invalid parameter.
2899
/// This is usually the type name of the parameter.
2900
pub param: DebugName,
2901
2902
/// A string identifying the field within a parameter using `#[derive(SystemParam)]`.
2903
/// This will be an empty string for other parameters.
2904
///
2905
/// This will be printed after `param` in the `Display` impl, and should include a `::` prefix if non-empty.
2906
pub field: Cow<'static, str>,
2907
}
2908
2909
impl SystemParamValidationError {
2910
/// Constructs a `SystemParamValidationError` that skips the system.
2911
/// The parameter name is initialized to the type name of `T`, so a `SystemParam` should usually pass `Self`.
2912
pub fn skipped<T>(message: impl Into<Cow<'static, str>>) -> Self {
2913
Self::new::<T>(true, message, Cow::Borrowed(""))
2914
}
2915
2916
/// Constructs a `SystemParamValidationError` for an invalid parameter that should be treated as an error.
2917
/// The parameter name is initialized to the type name of `T`, so a `SystemParam` should usually pass `Self`.
2918
pub fn invalid<T>(message: impl Into<Cow<'static, str>>) -> Self {
2919
Self::new::<T>(false, message, Cow::Borrowed(""))
2920
}
2921
2922
/// Constructs a `SystemParamValidationError` for an invalid parameter.
2923
/// The parameter name is initialized to the type name of `T`, so a `SystemParam` should usually pass `Self`.
2924
pub fn new<T>(
2925
skipped: bool,
2926
message: impl Into<Cow<'static, str>>,
2927
field: impl Into<Cow<'static, str>>,
2928
) -> Self {
2929
Self {
2930
skipped,
2931
message: message.into(),
2932
param: DebugName::type_name::<T>(),
2933
field: field.into(),
2934
}
2935
}
2936
2937
pub(crate) const EMPTY: Self = Self {
2938
skipped: false,
2939
message: Cow::Borrowed(""),
2940
param: DebugName::borrowed(""),
2941
field: Cow::Borrowed(""),
2942
};
2943
}
2944
2945
impl Display for SystemParamValidationError {
2946
fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
2947
write!(
2948
fmt,
2949
"Parameter `{}{}` failed validation: {}",
2950
self.param.shortname(),
2951
self.field,
2952
self.message
2953
)?;
2954
if !self.skipped {
2955
write!(fmt, "\nIf this is an expected state, wrap the parameter in `Option<T>` and handle `None` when it happens, or wrap the parameter in `If<T>` to skip the system when it happens.")?;
2956
}
2957
Ok(())
2958
}
2959
}
2960
2961
#[cfg(test)]
2962
mod tests {
2963
use super::*;
2964
use crate::system::assert_is_system;
2965
use core::cell::RefCell;
2966
2967
#[test]
2968
#[should_panic]
2969
fn non_send_alias() {
2970
#[derive(Resource)]
2971
struct A(usize);
2972
fn my_system(mut res0: NonSendMut<A>, mut res1: NonSendMut<A>) {
2973
res0.0 += 1;
2974
res1.0 += 1;
2975
}
2976
let mut world = World::new();
2977
world.insert_non_send(A(42));
2978
let mut schedule = crate::schedule::Schedule::default();
2979
schedule.add_systems(my_system);
2980
schedule.run(&mut world);
2981
}
2982
2983
// Compile test for https://github.com/bevyengine/bevy/pull/2838.
2984
#[test]
2985
fn system_param_generic_bounds() {
2986
#[derive(SystemParam)]
2987
pub struct SpecialQuery<
2988
'w,
2989
's,
2990
D: QueryData + Send + Sync + 'static,
2991
F: QueryFilter + Send + Sync + 'static = (),
2992
> {
2993
_query: Query<'w, 's, D, F>,
2994
}
2995
2996
fn my_system(_: SpecialQuery<(), ()>) {}
2997
assert_is_system(my_system);
2998
}
2999
3000
// Compile tests for https://github.com/bevyengine/bevy/pull/6694.
3001
#[test]
3002
fn system_param_flexibility() {
3003
#[derive(SystemParam)]
3004
pub struct SpecialRes<'w, T: Resource> {
3005
_res: Res<'w, T>,
3006
}
3007
3008
#[derive(SystemParam)]
3009
pub struct SpecialLocal<'s, T: FromWorld + Send + 'static> {
3010
_local: Local<'s, T>,
3011
}
3012
3013
#[derive(Resource)]
3014
struct R;
3015
3016
fn my_system(_: SpecialRes<R>, _: SpecialLocal<u32>) {}
3017
assert_is_system(my_system);
3018
}
3019
3020
#[derive(Resource)]
3021
pub struct R<const I: usize>;
3022
3023
// Compile test for https://github.com/bevyengine/bevy/pull/7001.
3024
#[test]
3025
fn system_param_const_generics() {
3026
#[expect(
3027
dead_code,
3028
reason = "This struct is used to ensure that const generics are supported as a SystemParam; thus, the inner value never needs to be read."
3029
)]
3030
#[derive(SystemParam)]
3031
pub struct ConstGenericParam<'w, const I: usize>(Res<'w, R<I>>);
3032
3033
fn my_system(_: ConstGenericParam<0>, _: ConstGenericParam<1000>) {}
3034
assert_is_system(my_system);
3035
}
3036
3037
// Compile test for https://github.com/bevyengine/bevy/pull/6867.
3038
#[test]
3039
fn system_param_field_limit() {
3040
#[derive(SystemParam)]
3041
pub struct LongParam<'w> {
3042
// Each field should be a distinct type so there will
3043
// be an error if the derive messes up the field order.
3044
_r0: Res<'w, R<0>>,
3045
_r1: Res<'w, R<1>>,
3046
_r2: Res<'w, R<2>>,
3047
_r3: Res<'w, R<3>>,
3048
_r4: Res<'w, R<4>>,
3049
_r5: Res<'w, R<5>>,
3050
_r6: Res<'w, R<6>>,
3051
_r7: Res<'w, R<7>>,
3052
_r8: Res<'w, R<8>>,
3053
_r9: Res<'w, R<9>>,
3054
_r10: Res<'w, R<10>>,
3055
_r11: Res<'w, R<11>>,
3056
_r12: Res<'w, R<12>>,
3057
_r13: Res<'w, R<13>>,
3058
_r14: Res<'w, R<14>>,
3059
_r15: Res<'w, R<15>>,
3060
_r16: Res<'w, R<16>>,
3061
}
3062
3063
fn long_system(_: LongParam) {}
3064
assert_is_system(long_system);
3065
}
3066
3067
// Compile test for https://github.com/bevyengine/bevy/pull/6919.
3068
// Regression test for https://github.com/bevyengine/bevy/issues/7447.
3069
#[test]
3070
fn system_param_phantom_data() {
3071
#[derive(SystemParam)]
3072
struct PhantomParam<'w, T: Resource, Marker: 'static> {
3073
_foo: Res<'w, T>,
3074
marker: PhantomData<&'w Marker>,
3075
}
3076
3077
fn my_system(_: PhantomParam<R<0>, ()>) {}
3078
assert_is_system(my_system);
3079
}
3080
3081
// Compile tests for https://github.com/bevyengine/bevy/pull/6957.
3082
#[test]
3083
fn system_param_struct_variants() {
3084
#[derive(SystemParam)]
3085
pub struct UnitParam;
3086
3087
#[expect(
3088
dead_code,
3089
reason = "This struct is used to ensure that tuple structs are supported as a SystemParam; thus, the inner values never need to be read."
3090
)]
3091
#[derive(SystemParam)]
3092
pub struct TupleParam<'w, 's, R: Resource, L: FromWorld + Send + 'static>(
3093
Res<'w, R>,
3094
Local<'s, L>,
3095
);
3096
3097
fn my_system(_: UnitParam, _: TupleParam<R<0>, u32>) {}
3098
assert_is_system(my_system);
3099
}
3100
3101
// Regression test for https://github.com/bevyengine/bevy/issues/4200.
3102
#[test]
3103
fn system_param_private_fields() {
3104
#[derive(Resource)]
3105
struct PrivateResource;
3106
3107
#[expect(
3108
dead_code,
3109
reason = "This struct is used to ensure that SystemParam's derive can't leak private fields; thus, the inner values never need to be read."
3110
)]
3111
#[derive(SystemParam)]
3112
pub struct EncapsulatedParam<'w>(Res<'w, PrivateResource>);
3113
3114
fn my_system(_: EncapsulatedParam) {}
3115
assert_is_system(my_system);
3116
}
3117
3118
// Regression test for https://github.com/bevyengine/bevy/issues/7103.
3119
#[test]
3120
fn system_param_where_clause() {
3121
#[derive(SystemParam)]
3122
pub struct WhereParam<'w, 's, D>
3123
where
3124
D: 'static + QueryData,
3125
{
3126
_q: Query<'w, 's, D, ()>,
3127
}
3128
3129
fn my_system(_: WhereParam<()>) {}
3130
assert_is_system(my_system);
3131
}
3132
3133
// Regression test for https://github.com/bevyengine/bevy/issues/1727.
3134
#[test]
3135
fn system_param_name_collision() {
3136
#[derive(Resource)]
3137
pub struct FetchState;
3138
3139
#[derive(SystemParam)]
3140
pub struct Collide<'w> {
3141
_x: Res<'w, FetchState>,
3142
}
3143
3144
fn my_system(_: Collide) {}
3145
assert_is_system(my_system);
3146
}
3147
3148
// Regression test for https://github.com/bevyengine/bevy/issues/8192.
3149
#[test]
3150
fn system_param_invariant_lifetime() {
3151
#[derive(SystemParam)]
3152
pub struct InvariantParam<'w, 's> {
3153
_set: ParamSet<'w, 's, (Query<'w, 's, ()>,)>,
3154
}
3155
3156
fn my_system(_: InvariantParam) {}
3157
assert_is_system(my_system);
3158
}
3159
3160
// Compile test for https://github.com/bevyengine/bevy/pull/9589.
3161
#[test]
3162
fn non_sync_local() {
3163
fn non_sync_system(cell: Local<RefCell<u8>>) {
3164
assert_eq!(*cell.borrow(), 0);
3165
}
3166
3167
let mut world = World::new();
3168
let mut schedule = crate::schedule::Schedule::default();
3169
schedule.add_systems(non_sync_system);
3170
schedule.run(&mut world);
3171
}
3172
3173
// Regression test for https://github.com/bevyengine/bevy/issues/10207.
3174
#[test]
3175
fn param_set_non_send_first() {
3176
fn non_send_param_set(mut p: ParamSet<(NonSend<*mut u8>, ())>) {
3177
let _ = p.p0();
3178
p.p1();
3179
}
3180
3181
let mut world = World::new();
3182
world.insert_non_send(core::ptr::null_mut::<u8>());
3183
let mut schedule = crate::schedule::Schedule::default();
3184
schedule.add_systems((non_send_param_set, non_send_param_set, non_send_param_set));
3185
schedule.run(&mut world);
3186
}
3187
3188
// Regression test for https://github.com/bevyengine/bevy/issues/10207.
3189
#[test]
3190
fn param_set_non_send_second() {
3191
fn non_send_param_set(mut p: ParamSet<((), NonSendMut<*mut u8>)>) {
3192
p.p0();
3193
let _ = p.p1();
3194
}
3195
3196
let mut world = World::new();
3197
world.insert_non_send(core::ptr::null_mut::<u8>());
3198
let mut schedule = crate::schedule::Schedule::default();
3199
schedule.add_systems((non_send_param_set, non_send_param_set, non_send_param_set));
3200
schedule.run(&mut world);
3201
}
3202
3203
fn _dyn_system_param_type_inference(mut p: DynSystemParam) {
3204
// Make sure the downcast() methods are able to infer their type parameters from the use of the return type.
3205
// This is just a compilation test, so there is nothing to run.
3206
let _query: Query<()> = p.downcast_mut().unwrap();
3207
let _query: Query<()> = p.downcast_mut_inner().unwrap();
3208
let _query: Query<()> = p.downcast().unwrap();
3209
}
3210
3211
#[test]
3212
#[should_panic]
3213
fn missing_resource_error() {
3214
#[derive(Resource)]
3215
pub struct MissingResource;
3216
3217
let mut schedule = crate::schedule::Schedule::default();
3218
schedule.add_systems(res_system);
3219
let mut world = World::new();
3220
schedule.run(&mut world);
3221
3222
fn res_system(_: Res<MissingResource>) {}
3223
}
3224
3225
#[test]
3226
#[should_panic]
3227
fn missing_message_error() {
3228
use crate::prelude::{Message, MessageReader};
3229
3230
#[derive(Message)]
3231
pub struct MissingEvent;
3232
3233
let mut schedule = crate::schedule::Schedule::default();
3234
schedule.add_systems(message_system);
3235
let mut world = World::new();
3236
schedule.run(&mut world);
3237
3238
fn message_system(_: MessageReader<MissingEvent>) {}
3239
}
3240
}
3241
3242