Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_ecs/src/system/mod.rs
6604 views
1
//! Tools for controlling behavior in an ECS application.
2
//!
3
//! Systems define how an ECS based application behaves.
4
//! Systems are added to a [`Schedule`](crate::schedule::Schedule), which is then run.
5
//! A system is usually written as a normal function, which is automatically converted into a system.
6
//!
7
//! System functions can have parameters, through which one can query and mutate Bevy ECS state.
8
//! Only types that implement [`SystemParam`] can be used, automatically fetching data from
9
//! the [`World`].
10
//!
11
//! System functions often look like this:
12
//!
13
//! ```
14
//! # use bevy_ecs::prelude::*;
15
//! #
16
//! # #[derive(Component)]
17
//! # struct Player { alive: bool }
18
//! # #[derive(Component)]
19
//! # struct Score(u32);
20
//! # #[derive(Resource)]
21
//! # struct Round(u32);
22
//! #
23
//! fn update_score_system(
24
//! mut query: Query<(&Player, &mut Score)>,
25
//! mut round: ResMut<Round>,
26
//! ) {
27
//! for (player, mut score) in &mut query {
28
//! if player.alive {
29
//! score.0 += round.0;
30
//! }
31
//! }
32
//! round.0 += 1;
33
//! }
34
//! # bevy_ecs::system::assert_is_system(update_score_system);
35
//! ```
36
//!
37
//! # System ordering
38
//!
39
//! By default, the execution of systems is parallel and not deterministic.
40
//! Not all systems can run together: if a system mutably accesses data,
41
//! no other system that reads or writes that data can be run at the same time.
42
//! These systems are said to be **incompatible**.
43
//!
44
//! The relative order in which incompatible systems are run matters.
45
//! When this is not specified, a **system order ambiguity** exists in your schedule.
46
//! You can **explicitly order** systems:
47
//!
48
//! - by calling the `.before(this_system)` or `.after(that_system)` methods when adding them to your schedule
49
//! - by adding them to a [`SystemSet`], and then using `.configure_sets(ThisSet.before(ThatSet))` syntax to configure many systems at once
50
//! - through the use of `.add_systems((system_a, system_b, system_c).chain())`
51
//!
52
//! [`SystemSet`]: crate::schedule::SystemSet
53
//!
54
//! ## Example
55
//!
56
//! ```
57
//! # use bevy_ecs::prelude::*;
58
//! # let mut schedule = Schedule::default();
59
//! # let mut world = World::new();
60
//! // Configure these systems to run in order using `chain()`.
61
//! schedule.add_systems((print_first, print_last).chain());
62
//! // Prints "HelloWorld!"
63
//! schedule.run(&mut world);
64
//!
65
//! // Configure this system to run in between the other two systems
66
//! // using explicit dependencies.
67
//! schedule.add_systems(print_mid.after(print_first).before(print_last));
68
//! // Prints "Hello, World!"
69
//! schedule.run(&mut world);
70
//!
71
//! fn print_first() {
72
//! print!("Hello");
73
//! }
74
//! fn print_mid() {
75
//! print!(", ");
76
//! }
77
//! fn print_last() {
78
//! println!("World!");
79
//! }
80
//! ```
81
//!
82
//! # System return type
83
//!
84
//! Systems added to a schedule through [`add_systems`](crate::schedule::Schedule) may either return
85
//! empty `()` or a [`Result`](crate::error::Result). Other contexts (like one shot systems) allow
86
//! systems to return arbitrary values.
87
//!
88
//! # System parameter list
89
//! Following is the complete list of accepted types as system parameters:
90
//!
91
//! - [`Query`]
92
//! - [`Res`] and `Option<Res>`
93
//! - [`ResMut`] and `Option<ResMut>`
94
//! - [`Commands`]
95
//! - [`Local`]
96
//! - [`EventReader`](crate::event::EventReader)
97
//! - [`EventWriter`](crate::event::EventWriter)
98
//! - [`NonSend`] and `Option<NonSend>`
99
//! - [`NonSendMut`] and `Option<NonSendMut>`
100
//! - [`RemovedComponents`](crate::lifecycle::RemovedComponents)
101
//! - [`SystemName`]
102
//! - [`SystemChangeTick`]
103
//! - [`Archetypes`](crate::archetype::Archetypes) (Provides Archetype metadata)
104
//! - [`Bundles`](crate::bundle::Bundles) (Provides Bundles metadata)
105
//! - [`Components`](crate::component::Components) (Provides Components metadata)
106
//! - [`Entities`](crate::entity::Entities) (Provides Entities metadata)
107
//! - All tuples between 1 to 16 elements where each element implements [`SystemParam`]
108
//! - [`ParamSet`]
109
//! - [`()` (unit primitive type)](https://doc.rust-lang.org/stable/std/primitive.unit.html)
110
//!
111
//! In addition, the following parameters can be used when constructing a dynamic system with [`SystemParamBuilder`],
112
//! but will only provide an empty value when used with an ordinary system:
113
//!
114
//! - [`FilteredResources`](crate::world::FilteredResources)
115
//! - [`FilteredResourcesMut`](crate::world::FilteredResourcesMut)
116
//! - [`DynSystemParam`]
117
//! - [`Vec<P>`] where `P: SystemParam`
118
//! - [`ParamSet<Vec<P>>`] where `P: SystemParam`
119
//!
120
//! [`Vec<P>`]: alloc::vec::Vec
121
122
mod adapter_system;
123
mod builder;
124
mod combinator;
125
mod commands;
126
mod exclusive_function_system;
127
mod exclusive_system_param;
128
mod function_system;
129
mod input;
130
mod observer_system;
131
mod query;
132
mod schedule_system;
133
mod system;
134
mod system_name;
135
mod system_param;
136
mod system_registry;
137
138
use core::any::TypeId;
139
140
pub use adapter_system::*;
141
pub use builder::*;
142
pub use combinator::*;
143
pub use commands::*;
144
pub use exclusive_function_system::*;
145
pub use exclusive_system_param::*;
146
pub use function_system::*;
147
pub use input::*;
148
pub use observer_system::*;
149
pub use query::*;
150
pub use schedule_system::*;
151
pub use system::*;
152
pub use system_name::*;
153
pub use system_param::*;
154
pub use system_registry::*;
155
156
use crate::world::{FromWorld, World};
157
158
/// Conversion trait to turn something into a [`System`].
159
///
160
/// Use this to get a system from a function. Also note that every system implements this trait as
161
/// well.
162
///
163
/// # Usage notes
164
///
165
/// This trait should only be used as a bound for trait implementations or as an
166
/// argument to a function. If a system needs to be returned from a function or
167
/// stored somewhere, use [`System`] instead of this trait.
168
///
169
/// # Examples
170
///
171
/// ```
172
/// use bevy_ecs::prelude::*;
173
///
174
/// fn my_system_function(a_usize_local: Local<usize>) {}
175
///
176
/// let system = IntoSystem::into_system(my_system_function);
177
/// ```
178
// This trait has to be generic because we have potentially overlapping impls, in particular
179
// because Rust thinks a type could impl multiple different `FnMut` combinations
180
// even though none can currently
181
#[diagnostic::on_unimplemented(
182
message = "`{Self}` is not a valid system with input `{In}` and output `{Out}`",
183
label = "invalid system"
184
)]
185
pub trait IntoSystem<In: SystemInput, Out, Marker>: Sized {
186
/// The type of [`System`] that this instance converts into.
187
type System: System<In = In, Out = Out>;
188
189
/// Turns this value into its corresponding [`System`].
190
fn into_system(this: Self) -> Self::System;
191
192
/// Pass the output of this system `A` into a second system `B`, creating a new compound system.
193
///
194
/// The second system must have [`In<T>`](crate::system::In) as its first parameter,
195
/// where `T` is the return type of the first system.
196
fn pipe<B, BIn, BOut, MarkerB>(self, system: B) -> IntoPipeSystem<Self, B>
197
where
198
Out: 'static,
199
B: IntoSystem<BIn, BOut, MarkerB>,
200
for<'a> BIn: SystemInput<Inner<'a> = Out>,
201
{
202
IntoPipeSystem::new(self, system)
203
}
204
205
/// Pass the output of this system into the passed function `f`, creating a new system that
206
/// outputs the value returned from the function.
207
///
208
/// ```
209
/// # use bevy_ecs::prelude::*;
210
/// # let mut schedule = Schedule::default();
211
/// // Ignores the output of a system that may fail.
212
/// schedule.add_systems(my_system.map(drop));
213
/// # let mut world = World::new();
214
/// # world.insert_resource(T);
215
/// # schedule.run(&mut world);
216
///
217
/// # #[derive(Resource)] struct T;
218
/// # type Err = ();
219
/// fn my_system(res: Res<T>) -> Result<(), Err> {
220
/// // ...
221
/// # Err(())
222
/// }
223
/// ```
224
fn map<T, F>(self, f: F) -> IntoAdapterSystem<F, Self>
225
where
226
F: Send + Sync + 'static + FnMut(Out) -> T,
227
{
228
IntoAdapterSystem::new(f, self)
229
}
230
231
/// Passes a mutable reference to `value` as input to the system each run,
232
/// turning it into a system that takes no input.
233
///
234
/// `Self` can have any [`SystemInput`] type that takes a mutable reference
235
/// to `T`, such as [`InMut`].
236
///
237
/// # Example
238
///
239
/// ```
240
/// # use bevy_ecs::prelude::*;
241
/// #
242
/// fn my_system(InMut(value): InMut<usize>) {
243
/// *value += 1;
244
/// if *value > 10 {
245
/// println!("Value is greater than 10!");
246
/// }
247
/// }
248
///
249
/// # let mut schedule = Schedule::default();
250
/// schedule.add_systems(my_system.with_input(0));
251
/// # bevy_ecs::system::assert_is_system(my_system.with_input(0));
252
/// ```
253
fn with_input<T>(self, value: T) -> WithInputWrapper<Self::System, T>
254
where
255
for<'i> In: SystemInput<Inner<'i> = &'i mut T>,
256
T: Send + Sync + 'static,
257
{
258
WithInputWrapper::new(self, value)
259
}
260
261
/// Passes a mutable reference to a value of type `T` created via
262
/// [`FromWorld`] as input to the system each run, turning it into a system
263
/// that takes no input.
264
///
265
/// `Self` can have any [`SystemInput`] type that takes a mutable reference
266
/// to `T`, such as [`InMut`].
267
///
268
/// # Example
269
///
270
/// ```
271
/// # use bevy_ecs::prelude::*;
272
/// #
273
/// struct MyData {
274
/// value: usize,
275
/// }
276
///
277
/// impl FromWorld for MyData {
278
/// fn from_world(world: &mut World) -> Self {
279
/// // Fetch from the world the data needed to create `MyData`
280
/// # MyData { value: 0 }
281
/// }
282
/// }
283
///
284
/// fn my_system(InMut(data): InMut<MyData>) {
285
/// data.value += 1;
286
/// if data.value > 10 {
287
/// println!("Value is greater than 10!");
288
/// }
289
/// }
290
/// # let mut schedule = Schedule::default();
291
/// schedule.add_systems(my_system.with_input_from::<MyData>());
292
/// # bevy_ecs::system::assert_is_system(my_system.with_input_from::<MyData>());
293
/// ```
294
fn with_input_from<T>(self) -> WithInputFromWrapper<Self::System, T>
295
where
296
for<'i> In: SystemInput<Inner<'i> = &'i mut T>,
297
T: FromWorld + Send + Sync + 'static,
298
{
299
WithInputFromWrapper::new(self)
300
}
301
302
/// Get the [`TypeId`] of the [`System`] produced after calling [`into_system`](`IntoSystem::into_system`).
303
#[inline]
304
fn system_type_id(&self) -> TypeId {
305
TypeId::of::<Self::System>()
306
}
307
}
308
309
// All systems implicitly implement IntoSystem.
310
impl<T: System> IntoSystem<T::In, T::Out, ()> for T {
311
type System = T;
312
fn into_system(this: Self) -> Self {
313
this
314
}
315
}
316
317
/// Ensure that a given function is a [system](System).
318
///
319
/// This should be used when writing doc examples,
320
/// to confirm that systems used in an example are
321
/// valid systems.
322
///
323
/// # Examples
324
///
325
/// The following example will panic when run since the
326
/// system's parameters mutably access the same component
327
/// multiple times.
328
///
329
/// ```should_panic
330
/// # use bevy_ecs::{prelude::*, system::assert_is_system};
331
/// #
332
/// # #[derive(Component)]
333
/// # struct Transform;
334
/// #
335
/// fn my_system(query1: Query<&mut Transform>, query2: Query<&mut Transform>) {
336
/// // ...
337
/// }
338
///
339
/// assert_is_system(my_system);
340
/// ```
341
pub fn assert_is_system<In: SystemInput, Out: 'static, Marker>(
342
system: impl IntoSystem<In, Out, Marker>,
343
) {
344
let mut system = IntoSystem::into_system(system);
345
346
// Initialize the system, which will panic if the system has access conflicts.
347
let mut world = World::new();
348
system.initialize(&mut world);
349
}
350
351
/// Ensure that a given function is a [read-only system](ReadOnlySystem).
352
///
353
/// This should be used when writing doc examples,
354
/// to confirm that systems used in an example are
355
/// valid systems.
356
///
357
/// # Examples
358
///
359
/// The following example will fail to compile
360
/// since the system accesses a component mutably.
361
///
362
/// ```compile_fail
363
/// # use bevy_ecs::{prelude::*, system::assert_is_read_only_system};
364
/// #
365
/// # #[derive(Component)]
366
/// # struct Transform;
367
/// #
368
/// fn my_system(query: Query<&mut Transform>) {
369
/// // ...
370
/// }
371
///
372
/// assert_is_read_only_system(my_system);
373
/// ```
374
pub fn assert_is_read_only_system<In, Out, Marker, S>(system: S)
375
where
376
In: SystemInput,
377
Out: 'static,
378
S: IntoSystem<In, Out, Marker>,
379
S::System: ReadOnlySystem,
380
{
381
assert_is_system(system);
382
}
383
384
/// Ensures that the provided system doesn't conflict with itself.
385
///
386
/// This function will panic if the provided system conflict with itself.
387
///
388
/// Note: this will run the system on an empty world.
389
pub fn assert_system_does_not_conflict<Out, Params, S: IntoSystem<(), Out, Params>>(sys: S) {
390
let mut world = World::new();
391
let mut system = IntoSystem::into_system(sys);
392
system.initialize(&mut world);
393
system.run((), &mut world).unwrap();
394
}
395
396
#[cfg(test)]
397
#[expect(clippy::print_stdout, reason = "Allowed in tests.")]
398
mod tests {
399
use alloc::{vec, vec::Vec};
400
use bevy_utils::default;
401
use core::any::TypeId;
402
use std::println;
403
404
use crate::{
405
archetype::Archetypes,
406
bundle::Bundles,
407
change_detection::DetectChanges,
408
component::{Component, Components},
409
entity::{Entities, Entity},
410
error::Result,
411
lifecycle::RemovedComponents,
412
name::Name,
413
prelude::{Add, AnyOf, EntityRef, On},
414
query::{Added, Changed, Or, SpawnDetails, Spawned, With, Without},
415
resource::Resource,
416
schedule::{
417
common_conditions::resource_exists, ApplyDeferred, IntoScheduleConfigs, Schedule,
418
SystemCondition,
419
},
420
system::{
421
Commands, In, InMut, IntoSystem, Local, NonSend, NonSendMut, ParamSet, Query, Res,
422
ResMut, Single, StaticSystemParam, System, SystemState,
423
},
424
world::{DeferredWorld, EntityMut, FromWorld, World},
425
};
426
427
use super::ScheduleSystem;
428
429
#[derive(Resource, PartialEq, Debug)]
430
enum SystemRan {
431
Yes,
432
No,
433
}
434
435
#[derive(Component, Resource, Debug, Eq, PartialEq, Default)]
436
struct A;
437
#[derive(Component, Resource)]
438
struct B;
439
#[derive(Component, Resource)]
440
struct C;
441
#[derive(Component, Resource)]
442
struct D;
443
#[derive(Component, Resource)]
444
struct E;
445
#[derive(Component, Resource)]
446
struct F;
447
448
#[derive(Component, Debug)]
449
struct W<T>(T);
450
451
#[test]
452
fn simple_system() {
453
fn sys(query: Query<&A>) {
454
for a in &query {
455
println!("{a:?}");
456
}
457
}
458
459
let mut system = IntoSystem::into_system(sys);
460
let mut world = World::new();
461
world.spawn(A);
462
463
system.initialize(&mut world);
464
system.run((), &mut world).unwrap();
465
}
466
467
fn run_system<Marker, S: IntoScheduleConfigs<ScheduleSystem, Marker>>(
468
world: &mut World,
469
system: S,
470
) {
471
let mut schedule = Schedule::default();
472
schedule.add_systems(system);
473
schedule.run(world);
474
}
475
476
#[test]
477
fn get_many_is_ordered() {
478
use crate::resource::Resource;
479
const ENTITIES_COUNT: usize = 1000;
480
481
#[derive(Resource)]
482
struct EntitiesArray(Vec<Entity>);
483
484
fn query_system(
485
mut ran: ResMut<SystemRan>,
486
entities_array: Res<EntitiesArray>,
487
q: Query<&W<usize>>,
488
) {
489
let entities_array: [Entity; ENTITIES_COUNT] =
490
entities_array.0.clone().try_into().unwrap();
491
492
for (i, w) in (0..ENTITIES_COUNT).zip(q.get_many(entities_array).unwrap()) {
493
assert_eq!(i, w.0);
494
}
495
496
*ran = SystemRan::Yes;
497
}
498
499
fn query_system_mut(
500
mut ran: ResMut<SystemRan>,
501
entities_array: Res<EntitiesArray>,
502
mut q: Query<&mut W<usize>>,
503
) {
504
let entities_array: [Entity; ENTITIES_COUNT] =
505
entities_array.0.clone().try_into().unwrap();
506
507
for (i, w) in (0..ENTITIES_COUNT).zip(q.get_many_mut(entities_array).unwrap()) {
508
assert_eq!(i, w.0);
509
}
510
511
*ran = SystemRan::Yes;
512
}
513
514
let mut world = World::default();
515
world.insert_resource(SystemRan::No);
516
let entity_ids = (0..ENTITIES_COUNT)
517
.map(|i| world.spawn(W(i)).id())
518
.collect();
519
world.insert_resource(EntitiesArray(entity_ids));
520
521
run_system(&mut world, query_system);
522
assert_eq!(*world.resource::<SystemRan>(), SystemRan::Yes);
523
524
world.insert_resource(SystemRan::No);
525
run_system(&mut world, query_system_mut);
526
assert_eq!(*world.resource::<SystemRan>(), SystemRan::Yes);
527
}
528
529
#[test]
530
fn or_param_set_system() {
531
// Regression test for issue #762
532
fn query_system(
533
mut ran: ResMut<SystemRan>,
534
mut set: ParamSet<(
535
Query<(), Or<(Changed<A>, Changed<B>)>>,
536
Query<(), Or<(Added<A>, Added<B>)>>,
537
)>,
538
) {
539
let changed = set.p0().iter().count();
540
let added = set.p1().iter().count();
541
542
assert_eq!(changed, 1);
543
assert_eq!(added, 1);
544
545
*ran = SystemRan::Yes;
546
}
547
548
let mut world = World::default();
549
world.insert_resource(SystemRan::No);
550
world.spawn((A, B));
551
552
run_system(&mut world, query_system);
553
554
assert_eq!(*world.resource::<SystemRan>(), SystemRan::Yes);
555
}
556
557
#[test]
558
fn changed_resource_system() {
559
use crate::resource::Resource;
560
561
#[derive(Resource)]
562
struct Flipper(bool);
563
564
#[derive(Resource)]
565
struct Added(usize);
566
567
#[derive(Resource)]
568
struct Changed(usize);
569
570
fn incr_e_on_flip(
571
value: Res<Flipper>,
572
mut changed: ResMut<Changed>,
573
mut added: ResMut<Added>,
574
) {
575
if value.is_added() {
576
added.0 += 1;
577
}
578
579
if value.is_changed() {
580
changed.0 += 1;
581
}
582
}
583
584
let mut world = World::default();
585
world.insert_resource(Flipper(false));
586
world.insert_resource(Added(0));
587
world.insert_resource(Changed(0));
588
589
let mut schedule = Schedule::default();
590
591
schedule.add_systems((incr_e_on_flip, ApplyDeferred, World::clear_trackers).chain());
592
593
schedule.run(&mut world);
594
assert_eq!(world.resource::<Added>().0, 1);
595
assert_eq!(world.resource::<Changed>().0, 1);
596
597
schedule.run(&mut world);
598
assert_eq!(world.resource::<Added>().0, 1);
599
assert_eq!(world.resource::<Changed>().0, 1);
600
601
world.resource_mut::<Flipper>().0 = true;
602
schedule.run(&mut world);
603
assert_eq!(world.resource::<Added>().0, 1);
604
assert_eq!(world.resource::<Changed>().0, 2);
605
}
606
607
#[test]
608
#[should_panic = "error[B0001]"]
609
fn option_has_no_filter_with() {
610
fn sys(_: Query<(Option<&A>, &mut B)>, _: Query<&mut B, Without<A>>) {}
611
let mut world = World::default();
612
run_system(&mut world, sys);
613
}
614
615
#[test]
616
fn option_doesnt_remove_unrelated_filter_with() {
617
fn sys(_: Query<(Option<&A>, &mut B, &A)>, _: Query<&mut B, Without<A>>) {}
618
let mut world = World::default();
619
run_system(&mut world, sys);
620
}
621
622
#[test]
623
fn any_of_working() {
624
fn sys(_: Query<AnyOf<(&mut A, &B)>>) {}
625
let mut world = World::default();
626
run_system(&mut world, sys);
627
}
628
629
#[test]
630
fn any_of_with_and_without_common() {
631
fn sys(_: Query<(&mut D, &C, AnyOf<(&A, &B)>)>, _: Query<&mut D, Without<C>>) {}
632
let mut world = World::default();
633
run_system(&mut world, sys);
634
}
635
636
#[test]
637
#[should_panic]
638
fn any_of_with_mut_and_ref() {
639
fn sys(_: Query<AnyOf<(&mut A, &A)>>) {}
640
let mut world = World::default();
641
run_system(&mut world, sys);
642
}
643
644
#[test]
645
#[should_panic]
646
fn any_of_with_ref_and_mut() {
647
fn sys(_: Query<AnyOf<(&A, &mut A)>>) {}
648
let mut world = World::default();
649
run_system(&mut world, sys);
650
}
651
652
#[test]
653
#[should_panic]
654
fn any_of_with_mut_and_option() {
655
fn sys(_: Query<AnyOf<(&mut A, Option<&A>)>>) {}
656
let mut world = World::default();
657
run_system(&mut world, sys);
658
}
659
660
#[test]
661
fn any_of_with_entity_and_mut() {
662
fn sys(_: Query<AnyOf<(Entity, &mut A)>>) {}
663
let mut world = World::default();
664
run_system(&mut world, sys);
665
}
666
667
#[test]
668
fn any_of_with_empty_and_mut() {
669
fn sys(_: Query<AnyOf<((), &mut A)>>) {}
670
let mut world = World::default();
671
run_system(&mut world, sys);
672
}
673
674
#[test]
675
#[should_panic = "error[B0001]"]
676
fn any_of_has_no_filter_with() {
677
fn sys(_: Query<(AnyOf<(&A, ())>, &mut B)>, _: Query<&mut B, Without<A>>) {}
678
let mut world = World::default();
679
run_system(&mut world, sys);
680
}
681
682
#[test]
683
#[should_panic]
684
fn any_of_with_conflicting() {
685
fn sys(_: Query<AnyOf<(&mut A, &mut A)>>) {}
686
let mut world = World::default();
687
run_system(&mut world, sys);
688
}
689
690
#[test]
691
fn any_of_has_filter_with_when_both_have_it() {
692
fn sys(_: Query<(AnyOf<(&A, &A)>, &mut B)>, _: Query<&mut B, Without<A>>) {}
693
let mut world = World::default();
694
run_system(&mut world, sys);
695
}
696
697
#[test]
698
fn any_of_doesnt_remove_unrelated_filter_with() {
699
fn sys(_: Query<(AnyOf<(&A, ())>, &mut B, &A)>, _: Query<&mut B, Without<A>>) {}
700
let mut world = World::default();
701
run_system(&mut world, sys);
702
}
703
704
#[test]
705
fn any_of_and_without() {
706
fn sys(_: Query<(AnyOf<(&A, &B)>, &mut C)>, _: Query<&mut C, (Without<A>, Without<B>)>) {}
707
let mut world = World::default();
708
run_system(&mut world, sys);
709
}
710
711
#[test]
712
#[should_panic = "error[B0001]"]
713
fn or_has_no_filter_with() {
714
fn sys(_: Query<&mut B, Or<(With<A>, With<B>)>>, _: Query<&mut B, Without<A>>) {}
715
let mut world = World::default();
716
run_system(&mut world, sys);
717
}
718
719
#[test]
720
fn or_has_filter_with_when_both_have_it() {
721
fn sys(_: Query<&mut B, Or<(With<A>, With<A>)>>, _: Query<&mut B, Without<A>>) {}
722
let mut world = World::default();
723
run_system(&mut world, sys);
724
}
725
726
#[test]
727
fn or_has_filter_with() {
728
fn sys(
729
_: Query<&mut C, Or<(With<A>, With<B>)>>,
730
_: Query<&mut C, (Without<A>, Without<B>)>,
731
) {
732
}
733
let mut world = World::default();
734
run_system(&mut world, sys);
735
}
736
737
#[test]
738
fn or_expanded_with_and_without_common() {
739
fn sys(_: Query<&mut D, (With<A>, Or<(With<B>, With<C>)>)>, _: Query<&mut D, Without<A>>) {}
740
let mut world = World::default();
741
run_system(&mut world, sys);
742
}
743
744
#[test]
745
fn or_expanded_nested_with_and_without_common() {
746
fn sys(
747
_: Query<&mut E, (Or<((With<B>, With<C>), (With<C>, With<D>))>, With<A>)>,
748
_: Query<&mut E, (Without<B>, Without<D>)>,
749
) {
750
}
751
let mut world = World::default();
752
run_system(&mut world, sys);
753
}
754
755
#[test]
756
#[should_panic = "error[B0001]"]
757
fn or_expanded_nested_with_and_disjoint_without() {
758
fn sys(
759
_: Query<&mut E, (Or<((With<B>, With<C>), (With<C>, With<D>))>, With<A>)>,
760
_: Query<&mut E, Without<D>>,
761
) {
762
}
763
let mut world = World::default();
764
run_system(&mut world, sys);
765
}
766
767
#[test]
768
#[should_panic = "error[B0001]"]
769
fn or_expanded_nested_or_with_and_disjoint_without() {
770
fn sys(
771
_: Query<&mut D, Or<(Or<(With<A>, With<B>)>, Or<(With<A>, With<C>)>)>>,
772
_: Query<&mut D, Without<A>>,
773
) {
774
}
775
let mut world = World::default();
776
run_system(&mut world, sys);
777
}
778
779
#[test]
780
fn or_expanded_nested_with_and_common_nested_without() {
781
fn sys(
782
_: Query<&mut D, Or<((With<A>, With<B>), (With<B>, With<C>))>>,
783
_: Query<&mut D, Or<(Without<D>, Without<B>)>>,
784
) {
785
}
786
let mut world = World::default();
787
run_system(&mut world, sys);
788
}
789
790
#[test]
791
fn or_with_without_and_compatible_with_without() {
792
fn sys(
793
_: Query<&mut C, Or<(With<A>, Without<B>)>>,
794
_: Query<&mut C, (With<B>, Without<A>)>,
795
) {
796
}
797
let mut world = World::default();
798
run_system(&mut world, sys);
799
}
800
801
#[test]
802
#[should_panic = "error[B0001]"]
803
fn with_and_disjoint_or_empty_without() {
804
fn sys(_: Query<&mut B, With<A>>, _: Query<&mut B, Or<((), Without<A>)>>) {}
805
let mut world = World::default();
806
run_system(&mut world, sys);
807
}
808
809
#[test]
810
#[should_panic = "error[B0001]"]
811
fn or_expanded_with_and_disjoint_nested_without() {
812
fn sys(
813
_: Query<&mut D, Or<(With<A>, With<B>)>>,
814
_: Query<&mut D, Or<(Without<A>, Without<B>)>>,
815
) {
816
}
817
let mut world = World::default();
818
run_system(&mut world, sys);
819
}
820
821
#[test]
822
#[should_panic = "error[B0001]"]
823
fn or_expanded_nested_with_and_disjoint_nested_without() {
824
fn sys(
825
_: Query<&mut D, Or<((With<A>, With<B>), (With<B>, With<C>))>>,
826
_: Query<&mut D, Or<(Without<A>, Without<B>)>>,
827
) {
828
}
829
let mut world = World::default();
830
run_system(&mut world, sys);
831
}
832
833
#[test]
834
fn or_doesnt_remove_unrelated_filter_with() {
835
fn sys(_: Query<&mut B, (Or<(With<A>, With<B>)>, With<A>)>, _: Query<&mut B, Without<A>>) {}
836
let mut world = World::default();
837
run_system(&mut world, sys);
838
}
839
840
#[test]
841
#[should_panic]
842
fn conflicting_query_mut_system() {
843
fn sys(_q1: Query<&mut A>, _q2: Query<&mut A>) {}
844
845
let mut world = World::default();
846
run_system(&mut world, sys);
847
}
848
849
#[test]
850
fn disjoint_query_mut_system() {
851
fn sys(_q1: Query<&mut A, With<B>>, _q2: Query<&mut A, Without<B>>) {}
852
853
let mut world = World::default();
854
run_system(&mut world, sys);
855
}
856
857
#[test]
858
fn disjoint_query_mut_read_component_system() {
859
fn sys(_q1: Query<(&mut A, &B)>, _q2: Query<&mut A, Without<B>>) {}
860
861
let mut world = World::default();
862
run_system(&mut world, sys);
863
}
864
865
#[test]
866
#[should_panic]
867
fn conflicting_query_immut_system() {
868
fn sys(_q1: Query<&A>, _q2: Query<&mut A>) {}
869
870
let mut world = World::default();
871
run_system(&mut world, sys);
872
}
873
874
#[test]
875
#[should_panic]
876
fn changed_trackers_or_conflict() {
877
fn sys(_: Query<&mut A>, _: Query<(), Or<(Changed<A>,)>>) {}
878
879
let mut world = World::default();
880
run_system(&mut world, sys);
881
}
882
883
#[test]
884
fn query_set_system() {
885
fn sys(mut _set: ParamSet<(Query<&mut A>, Query<&A>)>) {}
886
let mut world = World::default();
887
run_system(&mut world, sys);
888
}
889
890
#[test]
891
#[should_panic]
892
fn conflicting_query_with_query_set_system() {
893
fn sys(_query: Query<&mut A>, _set: ParamSet<(Query<&mut A>, Query<&B>)>) {}
894
895
let mut world = World::default();
896
run_system(&mut world, sys);
897
}
898
899
#[test]
900
#[should_panic]
901
fn conflicting_query_sets_system() {
902
fn sys(_set_1: ParamSet<(Query<&mut A>,)>, _set_2: ParamSet<(Query<&mut A>, Query<&B>)>) {}
903
904
let mut world = World::default();
905
run_system(&mut world, sys);
906
}
907
908
#[derive(Default, Resource)]
909
struct BufferRes {
910
_buffer: Vec<u8>,
911
}
912
913
fn test_for_conflicting_resources<Marker, S: IntoSystem<(), (), Marker>>(sys: S) {
914
let mut world = World::default();
915
world.insert_resource(BufferRes::default());
916
world.insert_resource(A);
917
world.insert_resource(B);
918
run_system(&mut world, sys);
919
}
920
921
#[test]
922
#[should_panic]
923
fn conflicting_system_resources() {
924
fn sys(_: ResMut<BufferRes>, _: Res<BufferRes>) {}
925
test_for_conflicting_resources(sys);
926
}
927
928
#[test]
929
#[should_panic]
930
fn conflicting_system_resources_reverse_order() {
931
fn sys(_: Res<BufferRes>, _: ResMut<BufferRes>) {}
932
test_for_conflicting_resources(sys);
933
}
934
935
#[test]
936
#[should_panic]
937
fn conflicting_system_resources_multiple_mutable() {
938
fn sys(_: ResMut<BufferRes>, _: ResMut<BufferRes>) {}
939
test_for_conflicting_resources(sys);
940
}
941
942
#[test]
943
fn nonconflicting_system_resources() {
944
fn sys(_: Local<BufferRes>, _: ResMut<BufferRes>, _: Local<A>, _: ResMut<A>) {}
945
test_for_conflicting_resources(sys);
946
}
947
948
#[test]
949
fn local_system() {
950
let mut world = World::default();
951
world.insert_resource(ProtoFoo { value: 1 });
952
world.insert_resource(SystemRan::No);
953
954
struct Foo {
955
value: u32,
956
}
957
958
#[derive(Resource)]
959
struct ProtoFoo {
960
value: u32,
961
}
962
963
impl FromWorld for Foo {
964
fn from_world(world: &mut World) -> Self {
965
Foo {
966
value: world.resource::<ProtoFoo>().value + 1,
967
}
968
}
969
}
970
971
fn sys(local: Local<Foo>, mut system_ran: ResMut<SystemRan>) {
972
assert_eq!(local.value, 2);
973
*system_ran = SystemRan::Yes;
974
}
975
976
run_system(&mut world, sys);
977
978
// ensure the system actually ran
979
assert_eq!(*world.resource::<SystemRan>(), SystemRan::Yes);
980
}
981
982
#[test]
983
#[expect(
984
dead_code,
985
reason = "The `NotSend1` and `NotSend2` structs is used to verify that a system will run, even if the system params include a non-Send resource. As such, the inner value doesn't matter."
986
)]
987
fn non_send_option_system() {
988
let mut world = World::default();
989
990
world.insert_resource(SystemRan::No);
991
// Two structs are used, one which is inserted and one which is not, to verify that wrapping
992
// non-Send resources in an `Option` will allow the system to run regardless of their
993
// existence.
994
struct NotSend1(alloc::rc::Rc<i32>);
995
struct NotSend2(alloc::rc::Rc<i32>);
996
world.insert_non_send_resource(NotSend1(alloc::rc::Rc::new(0)));
997
998
fn sys(
999
op: Option<NonSend<NotSend1>>,
1000
mut _op2: Option<NonSendMut<NotSend2>>,
1001
mut system_ran: ResMut<SystemRan>,
1002
) {
1003
op.expect("NonSend should exist");
1004
*system_ran = SystemRan::Yes;
1005
}
1006
1007
run_system(&mut world, sys);
1008
// ensure the system actually ran
1009
assert_eq!(*world.resource::<SystemRan>(), SystemRan::Yes);
1010
}
1011
1012
#[test]
1013
#[expect(
1014
dead_code,
1015
reason = "The `NotSend1` and `NotSend2` structs are used to verify that a system will run, even if the system params include a non-Send resource. As such, the inner value doesn't matter."
1016
)]
1017
fn non_send_system() {
1018
let mut world = World::default();
1019
1020
world.insert_resource(SystemRan::No);
1021
struct NotSend1(alloc::rc::Rc<i32>);
1022
struct NotSend2(alloc::rc::Rc<i32>);
1023
1024
world.insert_non_send_resource(NotSend1(alloc::rc::Rc::new(1)));
1025
world.insert_non_send_resource(NotSend2(alloc::rc::Rc::new(2)));
1026
1027
fn sys(
1028
_op: NonSend<NotSend1>,
1029
mut _op2: NonSendMut<NotSend2>,
1030
mut system_ran: ResMut<SystemRan>,
1031
) {
1032
*system_ran = SystemRan::Yes;
1033
}
1034
1035
run_system(&mut world, sys);
1036
assert_eq!(*world.resource::<SystemRan>(), SystemRan::Yes);
1037
}
1038
1039
#[test]
1040
fn removal_tracking() {
1041
let mut world = World::new();
1042
1043
let entity_to_despawn = world.spawn(W(1)).id();
1044
let entity_to_remove_w_from = world.spawn(W(2)).id();
1045
let spurious_entity = world.spawn_empty().id();
1046
1047
// Track which entities we want to operate on
1048
#[derive(Resource)]
1049
struct Despawned(Entity);
1050
world.insert_resource(Despawned(entity_to_despawn));
1051
1052
#[derive(Resource)]
1053
struct Removed(Entity);
1054
world.insert_resource(Removed(entity_to_remove_w_from));
1055
1056
// Verify that all the systems actually ran
1057
#[derive(Default, Resource)]
1058
struct NSystems(usize);
1059
world.insert_resource(NSystems::default());
1060
1061
// First, check that removal detection is triggered if and only if we despawn an entity with the correct component
1062
world.entity_mut(entity_to_despawn).despawn();
1063
world.entity_mut(spurious_entity).despawn();
1064
1065
fn validate_despawn(
1066
mut removed_i32: RemovedComponents<W<i32>>,
1067
despawned: Res<Despawned>,
1068
mut n_systems: ResMut<NSystems>,
1069
) {
1070
assert_eq!(
1071
removed_i32.read().collect::<Vec<_>>(),
1072
&[despawned.0],
1073
"despawning causes the correct entity to show up in the 'RemovedComponent' system parameter."
1074
);
1075
1076
n_systems.0 += 1;
1077
}
1078
1079
run_system(&mut world, validate_despawn);
1080
1081
// Reset the trackers to clear the buffer of removed components
1082
// Ordinarily, this is done in a system added by MinimalPlugins
1083
world.clear_trackers();
1084
1085
// Then, try removing a component
1086
world.spawn(W(3));
1087
world.spawn(W(4));
1088
world.entity_mut(entity_to_remove_w_from).remove::<W<i32>>();
1089
1090
fn validate_remove(
1091
mut removed_i32: RemovedComponents<W<i32>>,
1092
despawned: Res<Despawned>,
1093
removed: Res<Removed>,
1094
mut n_systems: ResMut<NSystems>,
1095
) {
1096
// The despawned entity from the previous frame was
1097
// double buffered so we now have it in this system as well.
1098
assert_eq!(
1099
removed_i32.read().collect::<Vec<_>>(),
1100
&[despawned.0, removed.0],
1101
"removing a component causes the correct entity to show up in the 'RemovedComponent' system parameter."
1102
);
1103
1104
n_systems.0 += 1;
1105
}
1106
1107
run_system(&mut world, validate_remove);
1108
1109
// Verify that both systems actually ran
1110
assert_eq!(world.resource::<NSystems>().0, 2);
1111
}
1112
1113
#[test]
1114
fn world_collections_system() {
1115
let mut world = World::default();
1116
world.insert_resource(SystemRan::No);
1117
world.spawn((W(42), W(true)));
1118
fn sys(
1119
archetypes: &Archetypes,
1120
components: &Components,
1121
entities: &Entities,
1122
bundles: &Bundles,
1123
query: Query<Entity, With<W<i32>>>,
1124
mut system_ran: ResMut<SystemRan>,
1125
) {
1126
assert_eq!(query.iter().count(), 1, "entity exists");
1127
for entity in &query {
1128
let location = entities.get(entity).unwrap();
1129
let archetype = archetypes.get(location.archetype_id).unwrap();
1130
let archetype_components = archetype.components();
1131
let bundle_id = bundles
1132
.get_id(TypeId::of::<(W<i32>, W<bool>)>())
1133
.expect("Bundle used to spawn entity should exist");
1134
let bundle_info = bundles.get(bundle_id).unwrap();
1135
let mut bundle_components = bundle_info.contributed_components().to_vec();
1136
bundle_components.sort();
1137
for component_id in &bundle_components {
1138
assert!(
1139
components.get_info(*component_id).is_some(),
1140
"every bundle component exists in Components"
1141
);
1142
}
1143
assert_eq!(
1144
bundle_components, archetype_components,
1145
"entity's bundle components exactly match entity's archetype components"
1146
);
1147
}
1148
*system_ran = SystemRan::Yes;
1149
}
1150
1151
run_system(&mut world, sys);
1152
1153
// ensure the system actually ran
1154
assert_eq!(*world.resource::<SystemRan>(), SystemRan::Yes);
1155
}
1156
1157
#[test]
1158
fn get_system_conflicts() {
1159
fn sys_x(_: Res<A>, _: Res<B>, _: Query<(&C, &D)>) {}
1160
1161
fn sys_y(_: Res<A>, _: ResMut<B>, _: Query<(&C, &mut D)>) {}
1162
1163
let mut world = World::default();
1164
let mut x = IntoSystem::into_system(sys_x);
1165
let mut y = IntoSystem::into_system(sys_y);
1166
let x_access = x.initialize(&mut world);
1167
let y_access = y.initialize(&mut world);
1168
1169
let conflicts = x_access.get_conflicts(&y_access);
1170
let b_id = world
1171
.components()
1172
.get_resource_id(TypeId::of::<B>())
1173
.unwrap();
1174
let d_id = world.components().get_id(TypeId::of::<D>()).unwrap();
1175
assert_eq!(conflicts, vec![b_id, d_id].into());
1176
}
1177
1178
#[test]
1179
fn query_is_empty() {
1180
fn without_filter(not_empty: Query<&A>, empty: Query<&B>) {
1181
assert!(!not_empty.is_empty());
1182
assert!(empty.is_empty());
1183
}
1184
1185
fn with_filter(not_empty: Query<&A, With<C>>, empty: Query<&A, With<D>>) {
1186
assert!(!not_empty.is_empty());
1187
assert!(empty.is_empty());
1188
}
1189
1190
let mut world = World::default();
1191
world.spawn(A).insert(C);
1192
1193
let mut without_filter = IntoSystem::into_system(without_filter);
1194
without_filter.initialize(&mut world);
1195
without_filter.run((), &mut world).unwrap();
1196
1197
let mut with_filter = IntoSystem::into_system(with_filter);
1198
with_filter.initialize(&mut world);
1199
with_filter.run((), &mut world).unwrap();
1200
}
1201
1202
#[test]
1203
fn can_have_16_parameters() {
1204
fn sys_x(
1205
_: Res<A>,
1206
_: Res<B>,
1207
_: Res<C>,
1208
_: Res<D>,
1209
_: Res<E>,
1210
_: Res<F>,
1211
_: Query<&A>,
1212
_: Query<&B>,
1213
_: Query<&C>,
1214
_: Query<&D>,
1215
_: Query<&E>,
1216
_: Query<&F>,
1217
_: Query<(&A, &B)>,
1218
_: Query<(&C, &D)>,
1219
_: Query<(&E, &F)>,
1220
) {
1221
}
1222
fn sys_y(
1223
_: (
1224
Res<A>,
1225
Res<B>,
1226
Res<C>,
1227
Res<D>,
1228
Res<E>,
1229
Res<F>,
1230
Query<&A>,
1231
Query<&B>,
1232
Query<&C>,
1233
Query<&D>,
1234
Query<&E>,
1235
Query<&F>,
1236
Query<(&A, &B)>,
1237
Query<(&C, &D)>,
1238
Query<(&E, &F)>,
1239
),
1240
) {
1241
}
1242
let mut world = World::default();
1243
let mut x = IntoSystem::into_system(sys_x);
1244
let mut y = IntoSystem::into_system(sys_y);
1245
x.initialize(&mut world);
1246
y.initialize(&mut world);
1247
}
1248
1249
#[test]
1250
fn read_system_state() {
1251
#[derive(Eq, PartialEq, Debug, Resource)]
1252
struct A(usize);
1253
1254
#[derive(Component, Eq, PartialEq, Debug)]
1255
struct B(usize);
1256
1257
let mut world = World::default();
1258
world.insert_resource(A(42));
1259
world.spawn(B(7));
1260
1261
let mut system_state: SystemState<(
1262
Res<A>,
1263
Option<Single<&B>>,
1264
ParamSet<(Query<&C>, Query<&D>)>,
1265
)> = SystemState::new(&mut world);
1266
let (a, query, _) = system_state.get(&world);
1267
assert_eq!(*a, A(42), "returned resource matches initial value");
1268
assert_eq!(
1269
**query.unwrap(),
1270
B(7),
1271
"returned component matches initial value"
1272
);
1273
}
1274
1275
#[test]
1276
fn write_system_state() {
1277
#[derive(Resource, Eq, PartialEq, Debug)]
1278
struct A(usize);
1279
1280
#[derive(Component, Eq, PartialEq, Debug)]
1281
struct B(usize);
1282
1283
let mut world = World::default();
1284
world.insert_resource(A(42));
1285
world.spawn(B(7));
1286
1287
let mut system_state: SystemState<(ResMut<A>, Option<Single<&mut B>>)> =
1288
SystemState::new(&mut world);
1289
1290
// The following line shouldn't compile because the parameters used are not ReadOnlySystemParam
1291
// let (a, query) = system_state.get(&world);
1292
1293
let (a, query) = system_state.get_mut(&mut world);
1294
assert_eq!(*a, A(42), "returned resource matches initial value");
1295
assert_eq!(
1296
**query.unwrap(),
1297
B(7),
1298
"returned component matches initial value"
1299
);
1300
}
1301
1302
#[test]
1303
fn system_state_change_detection() {
1304
#[derive(Component, Eq, PartialEq, Debug)]
1305
struct A(usize);
1306
1307
let mut world = World::default();
1308
let entity = world.spawn(A(1)).id();
1309
1310
let mut system_state: SystemState<Option<Single<&A, Changed<A>>>> =
1311
SystemState::new(&mut world);
1312
{
1313
let query = system_state.get(&world);
1314
assert_eq!(**query.unwrap(), A(1));
1315
}
1316
1317
{
1318
let query = system_state.get(&world);
1319
assert!(query.is_none());
1320
}
1321
1322
world.entity_mut(entity).get_mut::<A>().unwrap().0 = 2;
1323
{
1324
let query = system_state.get(&world);
1325
assert_eq!(**query.unwrap(), A(2));
1326
}
1327
}
1328
1329
#[test]
1330
fn system_state_spawned() {
1331
let mut world = World::default();
1332
world.spawn_empty();
1333
let spawn_tick = world.change_tick();
1334
1335
let mut system_state: SystemState<Option<Single<SpawnDetails, Spawned>>> =
1336
SystemState::new(&mut world);
1337
{
1338
let query = system_state.get(&world);
1339
assert_eq!(query.unwrap().spawned_at(), spawn_tick);
1340
}
1341
1342
{
1343
let query = system_state.get(&world);
1344
assert!(query.is_none());
1345
}
1346
}
1347
1348
#[test]
1349
#[should_panic]
1350
fn system_state_invalid_world() {
1351
let mut world = World::default();
1352
let mut system_state = SystemState::<Query<&A>>::new(&mut world);
1353
let mismatched_world = World::default();
1354
system_state.get(&mismatched_world);
1355
}
1356
1357
#[test]
1358
fn system_state_archetype_update() {
1359
#[derive(Component, Eq, PartialEq, Debug)]
1360
struct A(usize);
1361
1362
#[derive(Component, Eq, PartialEq, Debug)]
1363
struct B(usize);
1364
1365
let mut world = World::default();
1366
world.spawn(A(1));
1367
1368
let mut system_state = SystemState::<Query<&A>>::new(&mut world);
1369
{
1370
let query = system_state.get(&world);
1371
assert_eq!(
1372
query.iter().collect::<Vec<_>>(),
1373
vec![&A(1)],
1374
"exactly one component returned"
1375
);
1376
}
1377
1378
world.spawn((A(2), B(2)));
1379
{
1380
let query = system_state.get(&world);
1381
assert_eq!(
1382
query.iter().collect::<Vec<_>>(),
1383
vec![&A(1), &A(2)],
1384
"components from both archetypes returned"
1385
);
1386
}
1387
}
1388
1389
#[test]
1390
#[expect(
1391
dead_code,
1392
reason = "This test exists to show that read-only world-only queries can return data that lives as long as `'world`."
1393
)]
1394
fn long_life_test() {
1395
struct Holder<'w> {
1396
value: &'w A,
1397
}
1398
1399
struct State {
1400
state: SystemState<Res<'static, A>>,
1401
state_q: SystemState<Query<'static, 'static, &'static A>>,
1402
}
1403
1404
impl State {
1405
fn hold_res<'w>(&mut self, world: &'w World) -> Holder<'w> {
1406
let a = self.state.get(world);
1407
Holder {
1408
value: a.into_inner(),
1409
}
1410
}
1411
fn hold_component<'w>(&mut self, world: &'w World, entity: Entity) -> Holder<'w> {
1412
let q = self.state_q.get(world);
1413
let a = q.get_inner(entity).unwrap();
1414
Holder { value: a }
1415
}
1416
fn hold_components<'w>(&mut self, world: &'w World) -> Vec<Holder<'w>> {
1417
let mut components = Vec::new();
1418
let q = self.state_q.get(world);
1419
for a in q.iter_inner() {
1420
components.push(Holder { value: a });
1421
}
1422
components
1423
}
1424
}
1425
}
1426
1427
#[test]
1428
fn immutable_mut_test() {
1429
#[derive(Component, Eq, PartialEq, Debug, Clone, Copy)]
1430
struct A(usize);
1431
1432
let mut world = World::default();
1433
world.spawn(A(1));
1434
world.spawn(A(2));
1435
1436
let mut system_state = SystemState::<Query<&mut A>>::new(&mut world);
1437
{
1438
let mut query = system_state.get_mut(&mut world);
1439
assert_eq!(
1440
query.iter_mut().map(|m| *m).collect::<Vec<A>>(),
1441
vec![A(1), A(2)],
1442
"both components returned by iter_mut of &mut"
1443
);
1444
assert_eq!(
1445
query.iter().collect::<Vec<&A>>(),
1446
vec![&A(1), &A(2)],
1447
"both components returned by iter of &mut"
1448
);
1449
}
1450
}
1451
1452
#[test]
1453
fn convert_mut_to_immut() {
1454
{
1455
let mut world = World::new();
1456
1457
fn mutable_query(mut query: Query<&mut A>) {
1458
for _ in &mut query {}
1459
1460
immutable_query(query.as_readonly());
1461
}
1462
1463
fn immutable_query(_: Query<&A>) {}
1464
1465
let mut sys = IntoSystem::into_system(mutable_query);
1466
sys.initialize(&mut world);
1467
}
1468
1469
{
1470
let mut world = World::new();
1471
1472
fn mutable_query(mut query: Query<Option<&mut A>>) {
1473
for _ in &mut query {}
1474
1475
immutable_query(query.as_readonly());
1476
}
1477
1478
fn immutable_query(_: Query<Option<&A>>) {}
1479
1480
let mut sys = IntoSystem::into_system(mutable_query);
1481
sys.initialize(&mut world);
1482
}
1483
1484
{
1485
let mut world = World::new();
1486
1487
fn mutable_query(mut query: Query<(&mut A, &B)>) {
1488
for _ in &mut query {}
1489
1490
immutable_query(query.as_readonly());
1491
}
1492
1493
fn immutable_query(_: Query<(&A, &B)>) {}
1494
1495
let mut sys = IntoSystem::into_system(mutable_query);
1496
sys.initialize(&mut world);
1497
}
1498
1499
{
1500
let mut world = World::new();
1501
1502
fn mutable_query(mut query: Query<(&mut A, &mut B)>) {
1503
for _ in &mut query {}
1504
1505
immutable_query(query.as_readonly());
1506
}
1507
1508
fn immutable_query(_: Query<(&A, &B)>) {}
1509
1510
let mut sys = IntoSystem::into_system(mutable_query);
1511
sys.initialize(&mut world);
1512
}
1513
1514
{
1515
let mut world = World::new();
1516
1517
fn mutable_query(mut query: Query<(&mut A, &mut B), With<C>>) {
1518
for _ in &mut query {}
1519
1520
immutable_query(query.as_readonly());
1521
}
1522
1523
fn immutable_query(_: Query<(&A, &B), With<C>>) {}
1524
1525
let mut sys = IntoSystem::into_system(mutable_query);
1526
sys.initialize(&mut world);
1527
}
1528
1529
{
1530
let mut world = World::new();
1531
1532
fn mutable_query(mut query: Query<(&mut A, &mut B), Without<C>>) {
1533
for _ in &mut query {}
1534
1535
immutable_query(query.as_readonly());
1536
}
1537
1538
fn immutable_query(_: Query<(&A, &B), Without<C>>) {}
1539
1540
let mut sys = IntoSystem::into_system(mutable_query);
1541
sys.initialize(&mut world);
1542
}
1543
1544
{
1545
let mut world = World::new();
1546
1547
fn mutable_query(mut query: Query<(&mut A, &mut B), Added<C>>) {
1548
for _ in &mut query {}
1549
1550
immutable_query(query.as_readonly());
1551
}
1552
1553
fn immutable_query(_: Query<(&A, &B), Added<C>>) {}
1554
1555
let mut sys = IntoSystem::into_system(mutable_query);
1556
sys.initialize(&mut world);
1557
}
1558
1559
{
1560
let mut world = World::new();
1561
1562
fn mutable_query(mut query: Query<(&mut A, &mut B), Changed<C>>) {
1563
for _ in &mut query {}
1564
1565
immutable_query(query.as_readonly());
1566
}
1567
1568
fn immutable_query(_: Query<(&A, &B), Changed<C>>) {}
1569
1570
let mut sys = IntoSystem::into_system(mutable_query);
1571
sys.initialize(&mut world);
1572
}
1573
1574
{
1575
let mut world = World::new();
1576
1577
fn mutable_query(mut query: Query<(&mut A, &mut B, SpawnDetails), Spawned>) {
1578
for _ in &mut query {}
1579
1580
immutable_query(query.as_readonly());
1581
}
1582
1583
fn immutable_query(_: Query<(&A, &B, SpawnDetails), Spawned>) {}
1584
1585
let mut sys = IntoSystem::into_system(mutable_query);
1586
sys.initialize(&mut world);
1587
}
1588
}
1589
1590
#[test]
1591
fn commands_param_set() {
1592
// Regression test for #4676
1593
let mut world = World::new();
1594
let entity = world.spawn_empty().id();
1595
1596
run_system(
1597
&mut world,
1598
move |mut commands_set: ParamSet<(Commands, Commands)>| {
1599
commands_set.p0().entity(entity).insert(A);
1600
commands_set.p1().entity(entity).insert(B);
1601
},
1602
);
1603
1604
let entity = world.entity(entity);
1605
assert!(entity.contains::<A>());
1606
assert!(entity.contains::<B>());
1607
}
1608
1609
#[test]
1610
fn into_iter_impl() {
1611
let mut world = World::new();
1612
world.spawn(W(42u32));
1613
run_system(&mut world, |mut q: Query<&mut W<u32>>| {
1614
for mut a in &mut q {
1615
assert_eq!(a.0, 42);
1616
a.0 = 0;
1617
}
1618
for a in &q {
1619
assert_eq!(a.0, 0);
1620
}
1621
});
1622
}
1623
1624
#[test]
1625
#[should_panic]
1626
fn assert_system_does_not_conflict() {
1627
fn system(_query: Query<(&mut W<u32>, &mut W<u32>)>) {}
1628
super::assert_system_does_not_conflict(system);
1629
}
1630
1631
#[test]
1632
#[should_panic]
1633
fn assert_world_and_entity_mut_system_does_conflict_first() {
1634
fn system(_query: &World, _q2: Query<EntityMut>) {}
1635
super::assert_system_does_not_conflict(system);
1636
}
1637
1638
#[test]
1639
#[should_panic]
1640
fn assert_world_and_entity_mut_system_does_conflict_second() {
1641
fn system(_: Query<EntityMut>, _: &World) {}
1642
super::assert_system_does_not_conflict(system);
1643
}
1644
1645
#[test]
1646
#[should_panic]
1647
fn assert_entity_ref_and_entity_mut_system_does_conflict() {
1648
fn system(_query: Query<EntityRef>, _q2: Query<EntityMut>) {}
1649
super::assert_system_does_not_conflict(system);
1650
}
1651
1652
#[test]
1653
#[should_panic]
1654
fn assert_entity_mut_system_does_conflict() {
1655
fn system(_query: Query<EntityMut>, _q2: Query<EntityMut>) {}
1656
super::assert_system_does_not_conflict(system);
1657
}
1658
1659
#[test]
1660
#[should_panic]
1661
fn assert_deferred_world_and_entity_ref_system_does_conflict_first() {
1662
fn system(_world: DeferredWorld, _query: Query<EntityRef>) {}
1663
super::assert_system_does_not_conflict(system);
1664
}
1665
1666
#[test]
1667
#[should_panic]
1668
fn assert_deferred_world_and_entity_ref_system_does_conflict_second() {
1669
fn system(_query: Query<EntityRef>, _world: DeferredWorld) {}
1670
super::assert_system_does_not_conflict(system);
1671
}
1672
1673
#[test]
1674
fn assert_deferred_world_and_empty_query_does_not_conflict_first() {
1675
fn system(_world: DeferredWorld, _query: Query<Entity>) {}
1676
super::assert_system_does_not_conflict(system);
1677
}
1678
1679
#[test]
1680
fn assert_deferred_world_and_empty_query_does_not_conflict_second() {
1681
fn system(_query: Query<Entity>, _world: DeferredWorld) {}
1682
super::assert_system_does_not_conflict(system);
1683
}
1684
1685
#[test]
1686
#[should_panic]
1687
fn panic_inside_system() {
1688
let mut world = World::new();
1689
let system: fn() = || {
1690
panic!("this system panics");
1691
};
1692
run_system(&mut world, system);
1693
}
1694
1695
#[test]
1696
fn assert_systems() {
1697
use core::str::FromStr;
1698
1699
use crate::{prelude::*, system::assert_is_system};
1700
1701
/// Mocks a system that returns a value of type `T`.
1702
fn returning<T>() -> T {
1703
unimplemented!()
1704
}
1705
1706
/// Mocks an exclusive system that takes an input and returns an output.
1707
fn exclusive_in_out<A, B>(_: In<A>, _: &mut World) -> B {
1708
unimplemented!()
1709
}
1710
1711
fn static_system_param(_: StaticSystemParam<Query<'static, 'static, &W<u32>>>) {
1712
unimplemented!()
1713
}
1714
1715
fn exclusive_with_state(
1716
_: &mut World,
1717
_: Local<bool>,
1718
_: (&mut QueryState<&W<i32>>, &mut SystemState<Query<&W<u32>>>),
1719
_: (),
1720
) {
1721
unimplemented!()
1722
}
1723
1724
fn not(In(val): In<bool>) -> bool {
1725
!val
1726
}
1727
1728
assert_is_system(returning::<Result<u32, std::io::Error>>.map(Result::unwrap));
1729
assert_is_system(returning::<Option<()>>.map(drop));
1730
assert_is_system(returning::<&str>.map(u64::from_str).map(Result::unwrap));
1731
assert_is_system(static_system_param);
1732
assert_is_system(
1733
exclusive_in_out::<(), Result<(), std::io::Error>>.map(|_out| {
1734
#[cfg(feature = "trace")]
1735
if let Err(error) = _out {
1736
tracing::error!("{}", error);
1737
}
1738
}),
1739
);
1740
assert_is_system(exclusive_with_state);
1741
assert_is_system(returning::<bool>.pipe(exclusive_in_out::<bool, ()>));
1742
1743
returning::<()>.run_if(returning::<bool>.pipe(not));
1744
}
1745
1746
#[test]
1747
fn pipe_change_detection() {
1748
#[derive(Resource, Default)]
1749
struct Flag;
1750
1751
#[derive(Default)]
1752
struct Info {
1753
// If true, the respective system will mutate `Flag`.
1754
do_first: bool,
1755
do_second: bool,
1756
1757
// Will be set to true if the respective system saw that `Flag` changed.
1758
first_flag: bool,
1759
second_flag: bool,
1760
}
1761
1762
fn first(In(mut info): In<Info>, mut flag: ResMut<Flag>) -> Info {
1763
if flag.is_changed() {
1764
info.first_flag = true;
1765
}
1766
if info.do_first {
1767
*flag = Flag;
1768
}
1769
1770
info
1771
}
1772
1773
fn second(In(mut info): In<Info>, mut flag: ResMut<Flag>) -> Info {
1774
if flag.is_changed() {
1775
info.second_flag = true;
1776
}
1777
if info.do_second {
1778
*flag = Flag;
1779
}
1780
1781
info
1782
}
1783
1784
let mut world = World::new();
1785
world.init_resource::<Flag>();
1786
let mut sys = IntoSystem::into_system(first.pipe(second));
1787
sys.initialize(&mut world);
1788
1789
sys.run(default(), &mut world).unwrap();
1790
1791
// The second system should observe a change made in the first system.
1792
let info = sys
1793
.run(
1794
Info {
1795
do_first: true,
1796
..default()
1797
},
1798
&mut world,
1799
)
1800
.unwrap();
1801
assert!(!info.first_flag);
1802
assert!(info.second_flag);
1803
1804
// When a change is made in the second system, the first system
1805
// should observe it the next time they are run.
1806
let info1 = sys
1807
.run(
1808
Info {
1809
do_second: true,
1810
..default()
1811
},
1812
&mut world,
1813
)
1814
.unwrap();
1815
let info2 = sys.run(default(), &mut world).unwrap();
1816
assert!(!info1.first_flag);
1817
assert!(!info1.second_flag);
1818
assert!(info2.first_flag);
1819
assert!(!info2.second_flag);
1820
}
1821
1822
#[test]
1823
fn test_combinator_clone() {
1824
let mut world = World::new();
1825
#[derive(Resource)]
1826
struct A;
1827
#[derive(Resource)]
1828
struct B;
1829
#[derive(Resource, PartialEq, Eq, Debug)]
1830
struct C(i32);
1831
1832
world.insert_resource(A);
1833
world.insert_resource(C(0));
1834
let mut sched = Schedule::default();
1835
sched.add_systems(
1836
(
1837
|mut res: ResMut<C>| {
1838
res.0 += 1;
1839
},
1840
|mut res: ResMut<C>| {
1841
res.0 += 2;
1842
},
1843
)
1844
.distributive_run_if(resource_exists::<A>.or(resource_exists::<B>)),
1845
);
1846
sched.initialize(&mut world).unwrap();
1847
sched.run(&mut world);
1848
assert_eq!(world.get_resource(), Some(&C(3)));
1849
}
1850
1851
#[test]
1852
#[should_panic(
1853
expected = "Encountered an error in system `bevy_ecs::system::tests::simple_fallible_system::sys`: error"
1854
)]
1855
fn simple_fallible_system() {
1856
fn sys() -> Result {
1857
Err("error")?;
1858
Ok(())
1859
}
1860
1861
let mut world = World::new();
1862
run_system(&mut world, sys);
1863
}
1864
1865
#[test]
1866
#[should_panic(
1867
expected = "Encountered an error in system `bevy_ecs::system::tests::simple_fallible_exclusive_system::sys`: error"
1868
)]
1869
fn simple_fallible_exclusive_system() {
1870
fn sys(_world: &mut World) -> Result {
1871
Err("error")?;
1872
Ok(())
1873
}
1874
1875
let mut world = World::new();
1876
run_system(&mut world, sys);
1877
}
1878
1879
// Regression test for
1880
// https://github.com/bevyengine/bevy/issues/18778
1881
//
1882
// Dear rustc team, please reach out if you encounter this
1883
// in a crater run and we can work something out!
1884
//
1885
// These todo! macro calls should never be removed;
1886
// they're intended to demonstrate real-world usage
1887
// in a way that's clearer than simply calling `panic!`
1888
//
1889
// Because type inference behaves differently for functions and closures,
1890
// we need to test both, in addition to explicitly annotating the return type
1891
// to ensure that there are no upstream regressions there.
1892
#[test]
1893
fn nondiverging_never_trait_impls() {
1894
// This test is a compilation test:
1895
// no meaningful logic is ever actually evaluated.
1896
// It is simply intended to check that the correct traits are implemented
1897
// when todo! or similar nondiverging panics are used.
1898
let mut world = World::new();
1899
let mut schedule = Schedule::default();
1900
1901
fn sys(_query: Query<&Name>) {
1902
todo!()
1903
}
1904
1905
schedule.add_systems(sys);
1906
schedule.add_systems(|_query: Query<&Name>| {});
1907
schedule.add_systems(|_query: Query<&Name>| todo!());
1908
schedule.add_systems(|_query: Query<&Name>| -> () { todo!() });
1909
1910
fn obs(_event: On<Add, Name>) {
1911
todo!()
1912
}
1913
1914
world.add_observer(obs);
1915
world.add_observer(|_event: On<Add, Name>| {});
1916
world.add_observer(|_event: On<Add, Name>| todo!());
1917
world.add_observer(|_event: On<Add, Name>| -> () { todo!() });
1918
1919
fn my_command(_world: &mut World) {
1920
todo!()
1921
}
1922
1923
world.commands().queue(my_command);
1924
world.commands().queue(|_world: &mut World| {});
1925
world.commands().queue(|_world: &mut World| todo!());
1926
world
1927
.commands()
1928
.queue(|_world: &mut World| -> () { todo!() });
1929
}
1930
1931
#[test]
1932
fn with_input() {
1933
fn sys(InMut(v): InMut<usize>) {
1934
*v += 1;
1935
}
1936
1937
let mut world = World::new();
1938
let mut system = IntoSystem::into_system(sys.with_input(42));
1939
system.initialize(&mut world);
1940
system.run((), &mut world).unwrap();
1941
assert_eq!(*system.value(), 43);
1942
}
1943
1944
#[test]
1945
fn with_input_from() {
1946
struct TestData(usize);
1947
1948
impl FromWorld for TestData {
1949
fn from_world(_world: &mut World) -> Self {
1950
Self(5)
1951
}
1952
}
1953
1954
fn sys(InMut(v): InMut<TestData>) {
1955
v.0 += 1;
1956
}
1957
1958
let mut world = World::new();
1959
let mut system = IntoSystem::into_system(sys.with_input_from::<TestData>());
1960
assert!(system.value().is_none());
1961
system.initialize(&mut world);
1962
assert!(system.value().is_some());
1963
system.run((), &mut world).unwrap();
1964
assert_eq!(system.value().unwrap().0, 6);
1965
}
1966
}
1967
1968