bevy_ecs/system/
mod.rs

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 parameter list
83//! Following is the complete list of accepted types as system parameters:
84//!
85//! - [`Query`]
86//! - [`Res`] and `Option<Res>`
87//! - [`ResMut`] and `Option<ResMut>`
88//! - [`Commands`]
89//! - [`Local`]
90//! - [`EventReader`](crate::event::EventReader)
91//! - [`EventWriter`](crate::event::EventWriter)
92//! - [`NonSend`] and `Option<NonSend>`
93//! - [`NonSendMut`] and `Option<NonSendMut>`
94//! - [`RemovedComponents`](crate::removal_detection::RemovedComponents)
95//! - [`SystemName`]
96//! - [`SystemChangeTick`]
97//! - [`Archetypes`](crate::archetype::Archetypes) (Provides Archetype metadata)
98//! - [`Bundles`](crate::bundle::Bundles) (Provides Bundles metadata)
99//! - [`Components`](crate::component::Components) (Provides Components metadata)
100//! - [`Entities`](crate::entity::Entities) (Provides Entities metadata)
101//! - All tuples between 1 to 16 elements where each element implements [`SystemParam`]
102//! - [`()` (unit primitive type)](https://doc.rust-lang.org/stable/std/primitive.unit.html)
103
104mod adapter_system;
105mod builder;
106mod combinator;
107mod commands;
108mod exclusive_function_system;
109mod exclusive_system_param;
110mod function_system;
111mod observer_system;
112mod query;
113#[allow(clippy::module_inception)]
114mod system;
115mod system_name;
116mod system_param;
117mod system_registry;
118
119use std::{any::TypeId, borrow::Cow};
120
121pub use adapter_system::*;
122pub use builder::*;
123pub use combinator::*;
124pub use commands::*;
125pub use exclusive_function_system::*;
126pub use exclusive_system_param::*;
127pub use function_system::*;
128pub use observer_system::*;
129pub use query::*;
130pub use system::*;
131pub use system_name::*;
132pub use system_param::*;
133pub use system_registry::*;
134
135use crate::world::World;
136
137/// Conversion trait to turn something into a [`System`].
138///
139/// Use this to get a system from a function. Also note that every system implements this trait as
140/// well.
141///
142/// # Examples
143///
144/// ```
145/// use bevy_ecs::prelude::*;
146///
147/// fn my_system_function(a_usize_local: Local<usize>) {}
148///
149/// let system = IntoSystem::into_system(my_system_function);
150/// ```
151// This trait has to be generic because we have potentially overlapping impls, in particular
152// because Rust thinks a type could impl multiple different `FnMut` combinations
153// even though none can currently
154#[diagnostic::on_unimplemented(
155    message = "`{Self}` is not a valid system with input `{In}` and output `{Out}`",
156    label = "invalid system"
157)]
158pub trait IntoSystem<In, Out, Marker>: Sized {
159    /// The type of [`System`] that this instance converts into.
160    type System: System<In = In, Out = Out>;
161
162    /// Turns this value into its corresponding [`System`].
163    fn into_system(this: Self) -> Self::System;
164
165    /// Pass the output of this system `A` into a second system `B`, creating a new compound system.
166    ///
167    /// The second system must have [`In<T>`](crate::system::In) as its first parameter,
168    /// where `T` is the return type of the first system.
169    fn pipe<B, Final, MarkerB>(self, system: B) -> PipeSystem<Self::System, B::System>
170    where
171        B: IntoSystem<Out, Final, MarkerB>,
172    {
173        let system_a = IntoSystem::into_system(self);
174        let system_b = IntoSystem::into_system(system);
175        let name = format!("Pipe({}, {})", system_a.name(), system_b.name());
176        PipeSystem::new(system_a, system_b, Cow::Owned(name))
177    }
178
179    /// Pass the output of this system into the passed function `f`, creating a new system that
180    /// outputs the value returned from the function.
181    ///
182    /// ```
183    /// # use bevy_ecs::prelude::*;
184    /// # let mut schedule = Schedule::default();
185    /// // Ignores the output of a system that may fail.
186    /// schedule.add_systems(my_system.map(drop));
187    /// # let mut world = World::new();
188    /// # world.insert_resource(T);
189    /// # schedule.run(&mut world);
190    ///
191    /// # #[derive(Resource)] struct T;
192    /// # type Err = ();
193    /// fn my_system(res: Res<T>) -> Result<(), Err> {
194    ///     // ...
195    ///     # Err(())
196    /// }
197    /// ```
198    fn map<T, F>(self, f: F) -> AdapterSystem<F, Self::System>
199    where
200        F: Send + Sync + 'static + FnMut(Out) -> T,
201    {
202        let system = Self::into_system(self);
203        let name = system.name();
204        AdapterSystem::new(f, system, name)
205    }
206
207    /// Get the [`TypeId`] of the [`System`] produced after calling [`into_system`](`IntoSystem::into_system`).
208    #[inline]
209    fn system_type_id(&self) -> TypeId {
210        TypeId::of::<Self::System>()
211    }
212}
213
214// All systems implicitly implement IntoSystem.
215impl<T: System> IntoSystem<T::In, T::Out, ()> for T {
216    type System = T;
217    fn into_system(this: Self) -> Self {
218        this
219    }
220}
221
222/// Wrapper type to mark a [`SystemParam`] as an input.
223///
224/// [`System`]s may take an optional input which they require to be passed to them when they
225/// are being [`run`](System::run). For [`FunctionSystems`](FunctionSystem) the input may be marked
226/// with this `In` type, but only the first param of a function may be tagged as an input. This also
227/// means a system can only have one or zero input parameters.
228///
229/// # Examples
230///
231/// Here is a simple example of a system that takes a [`usize`] returning the square of it.
232///
233/// ```
234/// use bevy_ecs::prelude::*;
235///
236/// fn main() {
237///     let mut square_system = IntoSystem::into_system(square);
238///
239///     let mut world = World::default();
240///     square_system.initialize(&mut world);
241///     assert_eq!(square_system.run(12, &mut world), 144);
242/// }
243///
244/// fn square(In(input): In<usize>) -> usize {
245///     input * input
246/// }
247/// ```
248pub struct In<In>(pub In);
249
250/// Ensure that a given function is a [system](System).
251///
252/// This should be used when writing doc examples,
253/// to confirm that systems used in an example are
254/// valid systems.
255///
256/// # Examples
257///
258/// The following example will panic when run since the
259/// system's parameters mutably access the same component
260/// multiple times.
261///
262/// ```should_panic
263/// # use bevy_ecs::{prelude::*, system::assert_is_system};
264/// #
265/// # #[derive(Component)]
266/// # struct Transform;
267/// #
268/// fn my_system(query1: Query<&mut Transform>, query2: Query<&mut Transform>) {
269///     // ...
270/// }
271///
272/// assert_is_system(my_system);
273/// ```
274pub fn assert_is_system<In: 'static, Out: 'static, Marker>(
275    system: impl IntoSystem<In, Out, Marker>,
276) {
277    let mut system = IntoSystem::into_system(system);
278
279    // Initialize the system, which will panic if the system has access conflicts.
280    let mut world = World::new();
281    system.initialize(&mut world);
282}
283
284/// Ensure that a given function is a [read-only system](ReadOnlySystem).
285///
286/// This should be used when writing doc examples,
287/// to confirm that systems used in an example are
288/// valid systems.
289///
290/// # Examples
291///
292/// The following example will fail to compile
293/// since the system accesses a component mutably.
294///
295/// ```compile_fail
296/// # use bevy_ecs::{prelude::*, system::assert_is_read_only_system};
297/// #
298/// # #[derive(Component)]
299/// # struct Transform;
300/// #
301/// fn my_system(query: Query<&mut Transform>) {
302///     // ...
303/// }
304///
305/// assert_is_read_only_system(my_system);
306/// ```
307pub fn assert_is_read_only_system<In: 'static, Out: 'static, Marker, S>(system: S)
308where
309    S: IntoSystem<In, Out, Marker>,
310    S::System: ReadOnlySystem,
311{
312    assert_is_system(system);
313}
314
315/// Ensures that the provided system doesn't with itself.
316///
317/// This function will  panic if the provided system conflict with itself.
318///
319/// Note: this will run the system on an empty world.
320pub fn assert_system_does_not_conflict<Out, Params, S: IntoSystem<(), Out, Params>>(sys: S) {
321    let mut world = World::new();
322    let mut system = IntoSystem::into_system(sys);
323    system.initialize(&mut world);
324    system.run((), &mut world);
325}
326
327impl<T> std::ops::Deref for In<T> {
328    type Target = T;
329
330    fn deref(&self) -> &Self::Target {
331        &self.0
332    }
333}
334
335impl<T> std::ops::DerefMut for In<T> {
336    fn deref_mut(&mut self) -> &mut Self::Target {
337        &mut self.0
338    }
339}
340
341#[cfg(test)]
342mod tests {
343    use std::any::TypeId;
344
345    use bevy_utils::default;
346
347    use crate::{
348        self as bevy_ecs,
349        archetype::{ArchetypeComponentId, Archetypes},
350        bundle::Bundles,
351        change_detection::DetectChanges,
352        component::{Component, Components, Tick},
353        entity::{Entities, Entity},
354        prelude::AnyOf,
355        query::{Added, Changed, Or, With, Without},
356        removal_detection::RemovedComponents,
357        schedule::{
358            apply_deferred, common_conditions::resource_exists, Condition, IntoSystemConfigs,
359            Schedule,
360        },
361        system::{
362            Commands, In, IntoSystem, Local, NonSend, NonSendMut, ParamSet, Query, Res, ResMut,
363            Resource, StaticSystemParam, System, SystemState,
364        },
365        world::{FromWorld, World},
366    };
367
368    #[derive(Resource, PartialEq, Debug)]
369    enum SystemRan {
370        Yes,
371        No,
372    }
373
374    #[derive(Component, Resource, Debug, Eq, PartialEq, Default)]
375    struct A;
376    #[derive(Component, Resource)]
377    struct B;
378    #[derive(Component, Resource)]
379    struct C;
380    #[derive(Component, Resource)]
381    struct D;
382    #[derive(Component, Resource)]
383    struct E;
384    #[derive(Component, Resource)]
385    struct F;
386
387    #[derive(Component, Debug)]
388    struct W<T>(T);
389
390    #[test]
391    fn simple_system() {
392        fn sys(query: Query<&A>) {
393            for a in &query {
394                println!("{a:?}");
395            }
396        }
397
398        let mut system = IntoSystem::into_system(sys);
399        let mut world = World::new();
400        world.spawn(A);
401
402        system.initialize(&mut world);
403        system.run((), &mut world);
404    }
405
406    fn run_system<Marker, S: IntoSystem<(), (), Marker>>(world: &mut World, system: S) {
407        let mut schedule = Schedule::default();
408        schedule.add_systems(system);
409        schedule.run(world);
410    }
411
412    #[test]
413    fn get_many_is_ordered() {
414        use crate::system::Resource;
415        const ENTITIES_COUNT: usize = 1000;
416
417        #[derive(Resource)]
418        struct EntitiesArray(Vec<Entity>);
419
420        fn query_system(
421            mut ran: ResMut<SystemRan>,
422            entities_array: Res<EntitiesArray>,
423            q: Query<&W<usize>>,
424        ) {
425            let entities_array: [Entity; ENTITIES_COUNT] =
426                entities_array.0.clone().try_into().unwrap();
427
428            for (i, w) in (0..ENTITIES_COUNT).zip(q.get_many(entities_array).unwrap()) {
429                assert_eq!(i, w.0);
430            }
431
432            *ran = SystemRan::Yes;
433        }
434
435        fn query_system_mut(
436            mut ran: ResMut<SystemRan>,
437            entities_array: Res<EntitiesArray>,
438            mut q: Query<&mut W<usize>>,
439        ) {
440            let entities_array: [Entity; ENTITIES_COUNT] =
441                entities_array.0.clone().try_into().unwrap();
442
443            #[allow(unused_mut)]
444            for (i, mut w) in (0..ENTITIES_COUNT).zip(q.get_many_mut(entities_array).unwrap()) {
445                assert_eq!(i, w.0);
446            }
447
448            *ran = SystemRan::Yes;
449        }
450
451        let mut world = World::default();
452        world.insert_resource(SystemRan::No);
453        let entity_ids = (0..ENTITIES_COUNT)
454            .map(|i| world.spawn(W(i)).id())
455            .collect();
456        world.insert_resource(EntitiesArray(entity_ids));
457
458        run_system(&mut world, query_system);
459        assert_eq!(*world.resource::<SystemRan>(), SystemRan::Yes);
460
461        world.insert_resource(SystemRan::No);
462        run_system(&mut world, query_system_mut);
463        assert_eq!(*world.resource::<SystemRan>(), SystemRan::Yes);
464    }
465
466    #[test]
467    fn or_param_set_system() {
468        // Regression test for issue #762
469        fn query_system(
470            mut ran: ResMut<SystemRan>,
471            mut set: ParamSet<(
472                Query<(), Or<(Changed<A>, Changed<B>)>>,
473                Query<(), Or<(Added<A>, Added<B>)>>,
474            )>,
475        ) {
476            let changed = set.p0().iter().count();
477            let added = set.p1().iter().count();
478
479            assert_eq!(changed, 1);
480            assert_eq!(added, 1);
481
482            *ran = SystemRan::Yes;
483        }
484
485        let mut world = World::default();
486        world.insert_resource(SystemRan::No);
487        world.spawn((A, B));
488
489        run_system(&mut world, query_system);
490
491        assert_eq!(*world.resource::<SystemRan>(), SystemRan::Yes);
492    }
493
494    #[test]
495    fn changed_resource_system() {
496        use crate::system::Resource;
497
498        #[derive(Resource)]
499        struct Flipper(bool);
500
501        #[derive(Resource)]
502        struct Added(usize);
503
504        #[derive(Resource)]
505        struct Changed(usize);
506
507        fn incr_e_on_flip(
508            value: Res<Flipper>,
509            mut changed: ResMut<Changed>,
510            mut added: ResMut<Added>,
511        ) {
512            if value.is_added() {
513                added.0 += 1;
514            }
515
516            if value.is_changed() {
517                changed.0 += 1;
518            }
519        }
520
521        let mut world = World::default();
522        world.insert_resource(Flipper(false));
523        world.insert_resource(Added(0));
524        world.insert_resource(Changed(0));
525
526        let mut schedule = Schedule::default();
527
528        schedule.add_systems((incr_e_on_flip, apply_deferred, World::clear_trackers).chain());
529
530        schedule.run(&mut world);
531        assert_eq!(world.resource::<Added>().0, 1);
532        assert_eq!(world.resource::<Changed>().0, 1);
533
534        schedule.run(&mut world);
535        assert_eq!(world.resource::<Added>().0, 1);
536        assert_eq!(world.resource::<Changed>().0, 1);
537
538        world.resource_mut::<Flipper>().0 = true;
539        schedule.run(&mut world);
540        assert_eq!(world.resource::<Added>().0, 1);
541        assert_eq!(world.resource::<Changed>().0, 2);
542    }
543
544    #[test]
545    #[should_panic = "error[B0001]"]
546    fn option_has_no_filter_with() {
547        fn sys(_: Query<(Option<&A>, &mut B)>, _: Query<&mut B, Without<A>>) {}
548        let mut world = World::default();
549        run_system(&mut world, sys);
550    }
551
552    #[test]
553    fn option_doesnt_remove_unrelated_filter_with() {
554        fn sys(_: Query<(Option<&A>, &mut B, &A)>, _: Query<&mut B, Without<A>>) {}
555        let mut world = World::default();
556        run_system(&mut world, sys);
557    }
558
559    #[test]
560    fn any_of_working() {
561        fn sys(_: Query<AnyOf<(&mut A, &B)>>) {}
562        let mut world = World::default();
563        run_system(&mut world, sys);
564    }
565
566    #[test]
567    fn any_of_with_and_without_common() {
568        fn sys(_: Query<(&mut D, &C, AnyOf<(&A, &B)>)>, _: Query<&mut D, Without<C>>) {}
569        let mut world = World::default();
570        run_system(&mut world, sys);
571    }
572
573    #[test]
574    #[should_panic = "&bevy_ecs::system::tests::A conflicts with a previous access in this query."]
575    fn any_of_with_mut_and_ref() {
576        fn sys(_: Query<AnyOf<(&mut A, &A)>>) {}
577        let mut world = World::default();
578        run_system(&mut world, sys);
579    }
580
581    #[test]
582    #[should_panic = "&mut bevy_ecs::system::tests::A conflicts with a previous access in this query."]
583    fn any_of_with_ref_and_mut() {
584        fn sys(_: Query<AnyOf<(&A, &mut A)>>) {}
585        let mut world = World::default();
586        run_system(&mut world, sys);
587    }
588
589    #[test]
590    #[should_panic = "&bevy_ecs::system::tests::A conflicts with a previous access in this query."]
591    fn any_of_with_mut_and_option() {
592        fn sys(_: Query<AnyOf<(&mut A, Option<&A>)>>) {}
593        let mut world = World::default();
594        run_system(&mut world, sys);
595    }
596
597    #[test]
598    fn any_of_with_entity_and_mut() {
599        fn sys(_: Query<AnyOf<(Entity, &mut A)>>) {}
600        let mut world = World::default();
601        run_system(&mut world, sys);
602    }
603
604    #[test]
605    fn any_of_with_empty_and_mut() {
606        fn sys(_: Query<AnyOf<((), &mut A)>>) {}
607        let mut world = World::default();
608        run_system(&mut world, sys);
609    }
610
611    #[test]
612    #[should_panic = "error[B0001]"]
613    fn any_of_has_no_filter_with() {
614        fn sys(_: Query<(AnyOf<(&A, ())>, &mut B)>, _: Query<&mut B, Without<A>>) {}
615        let mut world = World::default();
616        run_system(&mut world, sys);
617    }
618
619    #[test]
620    #[should_panic = "&mut bevy_ecs::system::tests::A conflicts with a previous access in this query."]
621    fn any_of_with_conflicting() {
622        fn sys(_: Query<AnyOf<(&mut A, &mut A)>>) {}
623        let mut world = World::default();
624        run_system(&mut world, sys);
625    }
626
627    #[test]
628    fn any_of_has_filter_with_when_both_have_it() {
629        fn sys(_: Query<(AnyOf<(&A, &A)>, &mut B)>, _: Query<&mut B, Without<A>>) {}
630        let mut world = World::default();
631        run_system(&mut world, sys);
632    }
633
634    #[test]
635    fn any_of_doesnt_remove_unrelated_filter_with() {
636        fn sys(_: Query<(AnyOf<(&A, ())>, &mut B, &A)>, _: Query<&mut B, Without<A>>) {}
637        let mut world = World::default();
638        run_system(&mut world, sys);
639    }
640
641    #[test]
642    fn any_of_and_without() {
643        fn sys(_: Query<(AnyOf<(&A, &B)>, &mut C)>, _: Query<&mut C, (Without<A>, Without<B>)>) {}
644        let mut world = World::default();
645        run_system(&mut world, sys);
646    }
647
648    #[test]
649    #[should_panic = "error[B0001]"]
650    fn or_has_no_filter_with() {
651        fn sys(_: Query<&mut B, Or<(With<A>, With<B>)>>, _: Query<&mut B, Without<A>>) {}
652        let mut world = World::default();
653        run_system(&mut world, sys);
654    }
655
656    #[test]
657    fn or_has_filter_with_when_both_have_it() {
658        fn sys(_: Query<&mut B, Or<(With<A>, With<A>)>>, _: Query<&mut B, Without<A>>) {}
659        let mut world = World::default();
660        run_system(&mut world, sys);
661    }
662
663    #[test]
664    fn or_has_filter_with() {
665        fn sys(
666            _: Query<&mut C, Or<(With<A>, With<B>)>>,
667            _: Query<&mut C, (Without<A>, Without<B>)>,
668        ) {
669        }
670        let mut world = World::default();
671        run_system(&mut world, sys);
672    }
673
674    #[test]
675    fn or_expanded_with_and_without_common() {
676        fn sys(_: Query<&mut D, (With<A>, Or<(With<B>, With<C>)>)>, _: Query<&mut D, Without<A>>) {}
677        let mut world = World::default();
678        run_system(&mut world, sys);
679    }
680
681    #[test]
682    fn or_expanded_nested_with_and_without_common() {
683        fn sys(
684            _: Query<&mut E, (Or<((With<B>, With<C>), (With<C>, With<D>))>, With<A>)>,
685            _: Query<&mut E, (Without<B>, Without<D>)>,
686        ) {
687        }
688        let mut world = World::default();
689        run_system(&mut world, sys);
690    }
691
692    #[test]
693    #[should_panic = "error[B0001]"]
694    fn or_expanded_nested_with_and_disjoint_without() {
695        fn sys(
696            _: Query<&mut E, (Or<((With<B>, With<C>), (With<C>, With<D>))>, With<A>)>,
697            _: Query<&mut E, Without<D>>,
698        ) {
699        }
700        let mut world = World::default();
701        run_system(&mut world, sys);
702    }
703
704    #[test]
705    #[should_panic = "error[B0001]"]
706    fn or_expanded_nested_or_with_and_disjoint_without() {
707        fn sys(
708            _: Query<&mut D, Or<(Or<(With<A>, With<B>)>, Or<(With<A>, With<C>)>)>>,
709            _: Query<&mut D, Without<A>>,
710        ) {
711        }
712        let mut world = World::default();
713        run_system(&mut world, sys);
714    }
715
716    #[test]
717    fn or_expanded_nested_with_and_common_nested_without() {
718        fn sys(
719            _: Query<&mut D, Or<((With<A>, With<B>), (With<B>, With<C>))>>,
720            _: Query<&mut D, Or<(Without<D>, Without<B>)>>,
721        ) {
722        }
723        let mut world = World::default();
724        run_system(&mut world, sys);
725    }
726
727    #[test]
728    fn or_with_without_and_compatible_with_without() {
729        fn sys(
730            _: Query<&mut C, Or<(With<A>, Without<B>)>>,
731            _: Query<&mut C, (With<B>, Without<A>)>,
732        ) {
733        }
734        let mut world = World::default();
735        run_system(&mut world, sys);
736    }
737
738    #[test]
739    #[should_panic = "error[B0001]"]
740    fn with_and_disjoint_or_empty_without() {
741        fn sys(_: Query<&mut B, With<A>>, _: Query<&mut B, Or<((), Without<A>)>>) {}
742        let mut world = World::default();
743        run_system(&mut world, sys);
744    }
745
746    #[test]
747    #[should_panic = "error[B0001]"]
748    fn or_expanded_with_and_disjoint_nested_without() {
749        fn sys(
750            _: Query<&mut D, Or<(With<A>, With<B>)>>,
751            _: Query<&mut D, Or<(Without<A>, Without<B>)>>,
752        ) {
753        }
754        let mut world = World::default();
755        run_system(&mut world, sys);
756    }
757
758    #[test]
759    #[should_panic = "error[B0001]"]
760    fn or_expanded_nested_with_and_disjoint_nested_without() {
761        fn sys(
762            _: Query<&mut D, Or<((With<A>, With<B>), (With<B>, With<C>))>>,
763            _: Query<&mut D, Or<(Without<A>, Without<B>)>>,
764        ) {
765        }
766        let mut world = World::default();
767        run_system(&mut world, sys);
768    }
769
770    #[test]
771    fn or_doesnt_remove_unrelated_filter_with() {
772        fn sys(_: Query<&mut B, (Or<(With<A>, With<B>)>, With<A>)>, _: Query<&mut B, Without<A>>) {}
773        let mut world = World::default();
774        run_system(&mut world, sys);
775    }
776
777    #[test]
778    #[should_panic]
779    fn conflicting_query_mut_system() {
780        fn sys(_q1: Query<&mut A>, _q2: Query<&mut A>) {}
781
782        let mut world = World::default();
783        run_system(&mut world, sys);
784    }
785
786    #[test]
787    fn disjoint_query_mut_system() {
788        fn sys(_q1: Query<&mut A, With<B>>, _q2: Query<&mut A, Without<B>>) {}
789
790        let mut world = World::default();
791        run_system(&mut world, sys);
792    }
793
794    #[test]
795    fn disjoint_query_mut_read_component_system() {
796        fn sys(_q1: Query<(&mut A, &B)>, _q2: Query<&mut A, Without<B>>) {}
797
798        let mut world = World::default();
799        run_system(&mut world, sys);
800    }
801
802    #[test]
803    #[should_panic]
804    fn conflicting_query_immut_system() {
805        fn sys(_q1: Query<&A>, _q2: Query<&mut A>) {}
806
807        let mut world = World::default();
808        run_system(&mut world, sys);
809    }
810
811    #[test]
812    fn query_set_system() {
813        fn sys(mut _set: ParamSet<(Query<&mut A>, Query<&A>)>) {}
814        let mut world = World::default();
815        run_system(&mut world, sys);
816    }
817
818    #[test]
819    #[should_panic]
820    fn conflicting_query_with_query_set_system() {
821        fn sys(_query: Query<&mut A>, _set: ParamSet<(Query<&mut A>, Query<&B>)>) {}
822
823        let mut world = World::default();
824        run_system(&mut world, sys);
825    }
826
827    #[test]
828    #[should_panic]
829    fn conflicting_query_sets_system() {
830        fn sys(_set_1: ParamSet<(Query<&mut A>,)>, _set_2: ParamSet<(Query<&mut A>, Query<&B>)>) {}
831
832        let mut world = World::default();
833        run_system(&mut world, sys);
834    }
835
836    #[derive(Default, Resource)]
837    struct BufferRes {
838        _buffer: Vec<u8>,
839    }
840
841    fn test_for_conflicting_resources<Marker, S: IntoSystem<(), (), Marker>>(sys: S) {
842        let mut world = World::default();
843        world.insert_resource(BufferRes::default());
844        world.insert_resource(A);
845        world.insert_resource(B);
846        run_system(&mut world, sys);
847    }
848
849    #[test]
850    #[should_panic]
851    fn conflicting_system_resources() {
852        fn sys(_: ResMut<BufferRes>, _: Res<BufferRes>) {}
853        test_for_conflicting_resources(sys);
854    }
855
856    #[test]
857    #[should_panic]
858    fn conflicting_system_resources_reverse_order() {
859        fn sys(_: Res<BufferRes>, _: ResMut<BufferRes>) {}
860        test_for_conflicting_resources(sys);
861    }
862
863    #[test]
864    #[should_panic]
865    fn conflicting_system_resources_multiple_mutable() {
866        fn sys(_: ResMut<BufferRes>, _: ResMut<BufferRes>) {}
867        test_for_conflicting_resources(sys);
868    }
869
870    #[test]
871    fn nonconflicting_system_resources() {
872        fn sys(_: Local<BufferRes>, _: ResMut<BufferRes>, _: Local<A>, _: ResMut<A>) {}
873        test_for_conflicting_resources(sys);
874    }
875
876    #[test]
877    fn local_system() {
878        let mut world = World::default();
879        world.insert_resource(ProtoFoo { value: 1 });
880        world.insert_resource(SystemRan::No);
881
882        struct Foo {
883            value: u32,
884        }
885
886        #[derive(Resource)]
887        struct ProtoFoo {
888            value: u32,
889        }
890
891        impl FromWorld for Foo {
892            fn from_world(world: &mut World) -> Self {
893                Foo {
894                    value: world.resource::<ProtoFoo>().value + 1,
895                }
896            }
897        }
898
899        fn sys(local: Local<Foo>, mut system_ran: ResMut<SystemRan>) {
900            assert_eq!(local.value, 2);
901            *system_ran = SystemRan::Yes;
902        }
903
904        run_system(&mut world, sys);
905
906        // ensure the system actually ran
907        assert_eq!(*world.resource::<SystemRan>(), SystemRan::Yes);
908    }
909
910    #[test]
911    fn non_send_option_system() {
912        let mut world = World::default();
913
914        world.insert_resource(SystemRan::No);
915        #[allow(dead_code)]
916        struct NotSend1(std::rc::Rc<i32>);
917        #[allow(dead_code)]
918        struct NotSend2(std::rc::Rc<i32>);
919        world.insert_non_send_resource(NotSend1(std::rc::Rc::new(0)));
920
921        fn sys(
922            op: Option<NonSend<NotSend1>>,
923            mut _op2: Option<NonSendMut<NotSend2>>,
924            mut system_ran: ResMut<SystemRan>,
925        ) {
926            op.expect("NonSend should exist");
927            *system_ran = SystemRan::Yes;
928        }
929
930        run_system(&mut world, sys);
931        // ensure the system actually ran
932        assert_eq!(*world.resource::<SystemRan>(), SystemRan::Yes);
933    }
934
935    #[test]
936    fn non_send_system() {
937        let mut world = World::default();
938
939        world.insert_resource(SystemRan::No);
940        #[allow(dead_code)]
941        struct NotSend1(std::rc::Rc<i32>);
942        #[allow(dead_code)]
943        struct NotSend2(std::rc::Rc<i32>);
944
945        world.insert_non_send_resource(NotSend1(std::rc::Rc::new(1)));
946        world.insert_non_send_resource(NotSend2(std::rc::Rc::new(2)));
947
948        fn sys(
949            _op: NonSend<NotSend1>,
950            mut _op2: NonSendMut<NotSend2>,
951            mut system_ran: ResMut<SystemRan>,
952        ) {
953            *system_ran = SystemRan::Yes;
954        }
955
956        run_system(&mut world, sys);
957        assert_eq!(*world.resource::<SystemRan>(), SystemRan::Yes);
958    }
959
960    #[test]
961    fn removal_tracking() {
962        let mut world = World::new();
963
964        let entity_to_despawn = world.spawn(W(1)).id();
965        let entity_to_remove_w_from = world.spawn(W(2)).id();
966        let spurious_entity = world.spawn_empty().id();
967
968        // Track which entities we want to operate on
969        #[derive(Resource)]
970        struct Despawned(Entity);
971        world.insert_resource(Despawned(entity_to_despawn));
972
973        #[derive(Resource)]
974        struct Removed(Entity);
975        world.insert_resource(Removed(entity_to_remove_w_from));
976
977        // Verify that all the systems actually ran
978        #[derive(Default, Resource)]
979        struct NSystems(usize);
980        world.insert_resource(NSystems::default());
981
982        // First, check that removal detection is triggered if and only if we despawn an entity with the correct component
983        world.entity_mut(entity_to_despawn).despawn();
984        world.entity_mut(spurious_entity).despawn();
985
986        fn validate_despawn(
987            mut removed_i32: RemovedComponents<W<i32>>,
988            despawned: Res<Despawned>,
989            mut n_systems: ResMut<NSystems>,
990        ) {
991            assert_eq!(
992                removed_i32.read().collect::<Vec<_>>(),
993                &[despawned.0],
994                "despawning causes the correct entity to show up in the 'RemovedComponent' system parameter."
995            );
996
997            n_systems.0 += 1;
998        }
999
1000        run_system(&mut world, validate_despawn);
1001
1002        // Reset the trackers to clear the buffer of removed components
1003        // Ordinarily, this is done in a system added by MinimalPlugins
1004        world.clear_trackers();
1005
1006        // Then, try removing a component
1007        world.spawn(W(3));
1008        world.spawn(W(4));
1009        world.entity_mut(entity_to_remove_w_from).remove::<W<i32>>();
1010
1011        fn validate_remove(
1012            mut removed_i32: RemovedComponents<W<i32>>,
1013            despawned: Res<Despawned>,
1014            removed: Res<Removed>,
1015            mut n_systems: ResMut<NSystems>,
1016        ) {
1017            // The despawned entity from the previous frame was
1018            // double buffered so we now have it in this system as well.
1019            assert_eq!(
1020                removed_i32.read().collect::<Vec<_>>(),
1021                &[despawned.0, removed.0],
1022                "removing a component causes the correct entity to show up in the 'RemovedComponent' system parameter."
1023            );
1024
1025            n_systems.0 += 1;
1026        }
1027
1028        run_system(&mut world, validate_remove);
1029
1030        // Verify that both systems actually ran
1031        assert_eq!(world.resource::<NSystems>().0, 2);
1032    }
1033
1034    #[test]
1035    fn world_collections_system() {
1036        let mut world = World::default();
1037        world.insert_resource(SystemRan::No);
1038        world.spawn((W(42), W(true)));
1039        fn sys(
1040            archetypes: &Archetypes,
1041            components: &Components,
1042            entities: &Entities,
1043            bundles: &Bundles,
1044            query: Query<Entity, With<W<i32>>>,
1045            mut system_ran: ResMut<SystemRan>,
1046        ) {
1047            assert_eq!(query.iter().count(), 1, "entity exists");
1048            for entity in &query {
1049                let location = entities.get(entity).unwrap();
1050                let archetype = archetypes.get(location.archetype_id).unwrap();
1051                let archetype_components = archetype.components().collect::<Vec<_>>();
1052                let bundle_id = bundles
1053                    .get_id(TypeId::of::<(W<i32>, W<bool>)>())
1054                    .expect("Bundle used to spawn entity should exist");
1055                let bundle_info = bundles.get(bundle_id).unwrap();
1056                let mut bundle_components = bundle_info.components().to_vec();
1057                bundle_components.sort();
1058                for component_id in &bundle_components {
1059                    assert!(
1060                        components.get_info(*component_id).is_some(),
1061                        "every bundle component exists in Components"
1062                    );
1063                }
1064                assert_eq!(
1065                    bundle_components, archetype_components,
1066                    "entity's bundle components exactly match entity's archetype components"
1067                );
1068            }
1069            *system_ran = SystemRan::Yes;
1070        }
1071
1072        run_system(&mut world, sys);
1073
1074        // ensure the system actually ran
1075        assert_eq!(*world.resource::<SystemRan>(), SystemRan::Yes);
1076    }
1077
1078    #[test]
1079    fn get_system_conflicts() {
1080        fn sys_x(_: Res<A>, _: Res<B>, _: Query<(&C, &D)>) {}
1081
1082        fn sys_y(_: Res<A>, _: ResMut<B>, _: Query<(&C, &mut D)>) {}
1083
1084        let mut world = World::default();
1085        let mut x = IntoSystem::into_system(sys_x);
1086        let mut y = IntoSystem::into_system(sys_y);
1087        x.initialize(&mut world);
1088        y.initialize(&mut world);
1089
1090        let conflicts = x.component_access().get_conflicts(y.component_access());
1091        let b_id = world
1092            .components()
1093            .get_resource_id(TypeId::of::<B>())
1094            .unwrap();
1095        let d_id = world.components().get_id(TypeId::of::<D>()).unwrap();
1096        assert_eq!(conflicts, vec![b_id, d_id]);
1097    }
1098
1099    #[test]
1100    fn query_is_empty() {
1101        fn without_filter(not_empty: Query<&A>, empty: Query<&B>) {
1102            assert!(!not_empty.is_empty());
1103            assert!(empty.is_empty());
1104        }
1105
1106        fn with_filter(not_empty: Query<&A, With<C>>, empty: Query<&A, With<D>>) {
1107            assert!(!not_empty.is_empty());
1108            assert!(empty.is_empty());
1109        }
1110
1111        let mut world = World::default();
1112        world.spawn(A).insert(C);
1113
1114        let mut without_filter = IntoSystem::into_system(without_filter);
1115        without_filter.initialize(&mut world);
1116        without_filter.run((), &mut world);
1117
1118        let mut with_filter = IntoSystem::into_system(with_filter);
1119        with_filter.initialize(&mut world);
1120        with_filter.run((), &mut world);
1121    }
1122
1123    #[test]
1124    #[allow(clippy::too_many_arguments)]
1125    fn can_have_16_parameters() {
1126        fn sys_x(
1127            _: Res<A>,
1128            _: Res<B>,
1129            _: Res<C>,
1130            _: Res<D>,
1131            _: Res<E>,
1132            _: Res<F>,
1133            _: Query<&A>,
1134            _: Query<&B>,
1135            _: Query<&C>,
1136            _: Query<&D>,
1137            _: Query<&E>,
1138            _: Query<&F>,
1139            _: Query<(&A, &B)>,
1140            _: Query<(&C, &D)>,
1141            _: Query<(&E, &F)>,
1142        ) {
1143        }
1144        fn sys_y(
1145            _: (
1146                Res<A>,
1147                Res<B>,
1148                Res<C>,
1149                Res<D>,
1150                Res<E>,
1151                Res<F>,
1152                Query<&A>,
1153                Query<&B>,
1154                Query<&C>,
1155                Query<&D>,
1156                Query<&E>,
1157                Query<&F>,
1158                Query<(&A, &B)>,
1159                Query<(&C, &D)>,
1160                Query<(&E, &F)>,
1161            ),
1162        ) {
1163        }
1164        let mut world = World::default();
1165        let mut x = IntoSystem::into_system(sys_x);
1166        let mut y = IntoSystem::into_system(sys_y);
1167        x.initialize(&mut world);
1168        y.initialize(&mut world);
1169    }
1170
1171    #[test]
1172    fn read_system_state() {
1173        #[derive(Eq, PartialEq, Debug, Resource)]
1174        struct A(usize);
1175
1176        #[derive(Component, Eq, PartialEq, Debug)]
1177        struct B(usize);
1178
1179        let mut world = World::default();
1180        world.insert_resource(A(42));
1181        world.spawn(B(7));
1182
1183        let mut system_state: SystemState<(Res<A>, Query<&B>, ParamSet<(Query<&C>, Query<&D>)>)> =
1184            SystemState::new(&mut world);
1185        let (a, query, _) = system_state.get(&world);
1186        assert_eq!(*a, A(42), "returned resource matches initial value");
1187        assert_eq!(
1188            *query.single(),
1189            B(7),
1190            "returned component matches initial value"
1191        );
1192    }
1193
1194    #[test]
1195    fn write_system_state() {
1196        #[derive(Resource, Eq, PartialEq, Debug)]
1197        struct A(usize);
1198
1199        #[derive(Component, Eq, PartialEq, Debug)]
1200        struct B(usize);
1201
1202        let mut world = World::default();
1203        world.insert_resource(A(42));
1204        world.spawn(B(7));
1205
1206        let mut system_state: SystemState<(ResMut<A>, Query<&mut B>)> =
1207            SystemState::new(&mut world);
1208
1209        // The following line shouldn't compile because the parameters used are not ReadOnlySystemParam
1210        // let (a, query) = system_state.get(&world);
1211
1212        let (a, mut query) = system_state.get_mut(&mut world);
1213        assert_eq!(*a, A(42), "returned resource matches initial value");
1214        assert_eq!(
1215            *query.single_mut(),
1216            B(7),
1217            "returned component matches initial value"
1218        );
1219    }
1220
1221    #[test]
1222    fn system_state_change_detection() {
1223        #[derive(Component, Eq, PartialEq, Debug)]
1224        struct A(usize);
1225
1226        let mut world = World::default();
1227        let entity = world.spawn(A(1)).id();
1228
1229        let mut system_state: SystemState<Query<&A, Changed<A>>> = SystemState::new(&mut world);
1230        {
1231            let query = system_state.get(&world);
1232            assert_eq!(*query.single(), A(1));
1233        }
1234
1235        {
1236            let query = system_state.get(&world);
1237            assert!(query.get_single().is_err());
1238        }
1239
1240        world.entity_mut(entity).get_mut::<A>().unwrap().0 = 2;
1241        {
1242            let query = system_state.get(&world);
1243            assert_eq!(*query.single(), A(2));
1244        }
1245    }
1246
1247    #[test]
1248    #[should_panic]
1249    fn system_state_invalid_world() {
1250        let mut world = World::default();
1251        let mut system_state = SystemState::<Query<&A>>::new(&mut world);
1252        let mismatched_world = World::default();
1253        system_state.get(&mismatched_world);
1254    }
1255
1256    #[test]
1257    fn system_state_archetype_update() {
1258        #[derive(Component, Eq, PartialEq, Debug)]
1259        struct A(usize);
1260
1261        #[derive(Component, Eq, PartialEq, Debug)]
1262        struct B(usize);
1263
1264        let mut world = World::default();
1265        world.spawn(A(1));
1266
1267        let mut system_state = SystemState::<Query<&A>>::new(&mut world);
1268        {
1269            let query = system_state.get(&world);
1270            assert_eq!(
1271                query.iter().collect::<Vec<_>>(),
1272                vec![&A(1)],
1273                "exactly one component returned"
1274            );
1275        }
1276
1277        world.spawn((A(2), B(2)));
1278        {
1279            let query = system_state.get(&world);
1280            assert_eq!(
1281                query.iter().collect::<Vec<_>>(),
1282                vec![&A(1), &A(2)],
1283                "components from both archetypes returned"
1284            );
1285        }
1286    }
1287
1288    /// this test exists to show that read-only world-only queries can return data that lives as long as 'world
1289    #[test]
1290    #[allow(unused)]
1291    fn long_life_test() {
1292        struct Holder<'w> {
1293            value: &'w A,
1294        }
1295
1296        struct State {
1297            state: SystemState<Res<'static, A>>,
1298            state_q: SystemState<Query<'static, 'static, &'static A>>,
1299        }
1300
1301        impl State {
1302            fn hold_res<'w>(&mut self, world: &'w World) -> Holder<'w> {
1303                let a = self.state.get(world);
1304                Holder {
1305                    value: a.into_inner(),
1306                }
1307            }
1308            fn hold_component<'w>(&mut self, world: &'w World, entity: Entity) -> Holder<'w> {
1309                let q = self.state_q.get(world);
1310                let a = q.get_inner(entity).unwrap();
1311                Holder { value: a }
1312            }
1313            fn hold_components<'w>(&mut self, world: &'w World) -> Vec<Holder<'w>> {
1314                let mut components = Vec::new();
1315                let q = self.state_q.get(world);
1316                for a in q.iter_inner() {
1317                    components.push(Holder { value: a });
1318                }
1319                components
1320            }
1321        }
1322    }
1323
1324    #[test]
1325    fn immutable_mut_test() {
1326        #[derive(Component, Eq, PartialEq, Debug, Clone, Copy)]
1327        struct A(usize);
1328
1329        let mut world = World::default();
1330        world.spawn(A(1));
1331        world.spawn(A(2));
1332
1333        let mut system_state = SystemState::<Query<&mut A>>::new(&mut world);
1334        {
1335            let mut query = system_state.get_mut(&mut world);
1336            assert_eq!(
1337                query.iter_mut().map(|m| *m).collect::<Vec<A>>(),
1338                vec![A(1), A(2)],
1339                "both components returned by iter_mut of &mut"
1340            );
1341            assert_eq!(
1342                query.iter().collect::<Vec<&A>>(),
1343                vec![&A(1), &A(2)],
1344                "both components returned by iter of &mut"
1345            );
1346        }
1347    }
1348
1349    #[test]
1350    fn convert_mut_to_immut() {
1351        {
1352            let mut world = World::new();
1353
1354            fn mutable_query(mut query: Query<&mut A>) {
1355                for _ in &mut query {}
1356
1357                immutable_query(query.to_readonly());
1358            }
1359
1360            fn immutable_query(_: Query<&A>) {}
1361
1362            let mut sys = IntoSystem::into_system(mutable_query);
1363            sys.initialize(&mut world);
1364        }
1365
1366        {
1367            let mut world = World::new();
1368
1369            fn mutable_query(mut query: Query<Option<&mut A>>) {
1370                for _ in &mut query {}
1371
1372                immutable_query(query.to_readonly());
1373            }
1374
1375            fn immutable_query(_: Query<Option<&A>>) {}
1376
1377            let mut sys = IntoSystem::into_system(mutable_query);
1378            sys.initialize(&mut world);
1379        }
1380
1381        {
1382            let mut world = World::new();
1383
1384            fn mutable_query(mut query: Query<(&mut A, &B)>) {
1385                for _ in &mut query {}
1386
1387                immutable_query(query.to_readonly());
1388            }
1389
1390            fn immutable_query(_: Query<(&A, &B)>) {}
1391
1392            let mut sys = IntoSystem::into_system(mutable_query);
1393            sys.initialize(&mut world);
1394        }
1395
1396        {
1397            let mut world = World::new();
1398
1399            fn mutable_query(mut query: Query<(&mut A, &mut B)>) {
1400                for _ in &mut query {}
1401
1402                immutable_query(query.to_readonly());
1403            }
1404
1405            fn immutable_query(_: Query<(&A, &B)>) {}
1406
1407            let mut sys = IntoSystem::into_system(mutable_query);
1408            sys.initialize(&mut world);
1409        }
1410
1411        {
1412            let mut world = World::new();
1413
1414            fn mutable_query(mut query: Query<(&mut A, &mut B), With<C>>) {
1415                for _ in &mut query {}
1416
1417                immutable_query(query.to_readonly());
1418            }
1419
1420            fn immutable_query(_: Query<(&A, &B), With<C>>) {}
1421
1422            let mut sys = IntoSystem::into_system(mutable_query);
1423            sys.initialize(&mut world);
1424        }
1425
1426        {
1427            let mut world = World::new();
1428
1429            fn mutable_query(mut query: Query<(&mut A, &mut B), Without<C>>) {
1430                for _ in &mut query {}
1431
1432                immutable_query(query.to_readonly());
1433            }
1434
1435            fn immutable_query(_: Query<(&A, &B), Without<C>>) {}
1436
1437            let mut sys = IntoSystem::into_system(mutable_query);
1438            sys.initialize(&mut world);
1439        }
1440
1441        {
1442            let mut world = World::new();
1443
1444            fn mutable_query(mut query: Query<(&mut A, &mut B), Added<C>>) {
1445                for _ in &mut query {}
1446
1447                immutable_query(query.to_readonly());
1448            }
1449
1450            fn immutable_query(_: Query<(&A, &B), Added<C>>) {}
1451
1452            let mut sys = IntoSystem::into_system(mutable_query);
1453            sys.initialize(&mut world);
1454        }
1455
1456        {
1457            let mut world = World::new();
1458
1459            fn mutable_query(mut query: Query<(&mut A, &mut B), Changed<C>>) {
1460                for _ in &mut query {}
1461
1462                immutable_query(query.to_readonly());
1463            }
1464
1465            fn immutable_query(_: Query<(&A, &B), Changed<C>>) {}
1466
1467            let mut sys = IntoSystem::into_system(mutable_query);
1468            sys.initialize(&mut world);
1469        }
1470    }
1471
1472    #[test]
1473    fn update_archetype_component_access_works() {
1474        use std::collections::HashSet;
1475
1476        fn a_not_b_system(_query: Query<&A, Without<B>>) {}
1477
1478        let mut world = World::default();
1479        let mut system = IntoSystem::into_system(a_not_b_system);
1480        let mut expected_ids = HashSet::<ArchetypeComponentId>::new();
1481        let a_id = world.init_component::<A>();
1482
1483        // set up system and verify its access is empty
1484        system.initialize(&mut world);
1485        system.update_archetype_component_access(world.as_unsafe_world_cell());
1486        assert_eq!(
1487            system
1488                .archetype_component_access()
1489                .reads()
1490                .collect::<HashSet<_>>(),
1491            expected_ids
1492        );
1493
1494        // add some entities with archetypes that should match and save their ids
1495        expected_ids.insert(
1496            world
1497                .spawn(A)
1498                .archetype()
1499                .get_archetype_component_id(a_id)
1500                .unwrap(),
1501        );
1502        expected_ids.insert(
1503            world
1504                .spawn((A, C))
1505                .archetype()
1506                .get_archetype_component_id(a_id)
1507                .unwrap(),
1508        );
1509
1510        // add some entities with archetypes that should not match
1511        world.spawn((A, B));
1512        world.spawn((B, C));
1513
1514        // update system and verify its accesses are correct
1515        system.update_archetype_component_access(world.as_unsafe_world_cell());
1516        assert_eq!(
1517            system
1518                .archetype_component_access()
1519                .reads()
1520                .collect::<HashSet<_>>(),
1521            expected_ids
1522        );
1523
1524        // one more round
1525        expected_ids.insert(
1526            world
1527                .spawn((A, D))
1528                .archetype()
1529                .get_archetype_component_id(a_id)
1530                .unwrap(),
1531        );
1532        world.spawn((A, B, D));
1533        system.update_archetype_component_access(world.as_unsafe_world_cell());
1534        assert_eq!(
1535            system
1536                .archetype_component_access()
1537                .reads()
1538                .collect::<HashSet<_>>(),
1539            expected_ids
1540        );
1541    }
1542
1543    #[test]
1544    fn commands_param_set() {
1545        // Regression test for #4676
1546        let mut world = World::new();
1547        let entity = world.spawn_empty().id();
1548
1549        run_system(
1550            &mut world,
1551            move |mut commands_set: ParamSet<(Commands, Commands)>| {
1552                commands_set.p0().entity(entity).insert(A);
1553                commands_set.p1().entity(entity).insert(B);
1554            },
1555        );
1556
1557        let entity = world.entity(entity);
1558        assert!(entity.contains::<A>());
1559        assert!(entity.contains::<B>());
1560    }
1561
1562    #[test]
1563    fn into_iter_impl() {
1564        let mut world = World::new();
1565        world.spawn(W(42u32));
1566        run_system(&mut world, |mut q: Query<&mut W<u32>>| {
1567            for mut a in &mut q {
1568                assert_eq!(a.0, 42);
1569                a.0 = 0;
1570            }
1571            for a in &q {
1572                assert_eq!(a.0, 0);
1573            }
1574        });
1575    }
1576
1577    #[test]
1578    #[should_panic = "Encountered a mismatched World."]
1579    fn query_validates_world_id() {
1580        let mut world1 = World::new();
1581        let world2 = World::new();
1582        let qstate = world1.query::<()>();
1583        // SAFETY: doesnt access anything
1584        let query = unsafe {
1585            Query::new(
1586                world2.as_unsafe_world_cell_readonly(),
1587                &qstate,
1588                Tick::new(0),
1589                Tick::new(0),
1590            )
1591        };
1592        query.iter();
1593    }
1594
1595    #[test]
1596    #[should_panic]
1597    fn assert_system_does_not_conflict() {
1598        fn system(_query: Query<(&mut W<u32>, &mut W<u32>)>) {}
1599        super::assert_system_does_not_conflict(system);
1600    }
1601
1602    #[test]
1603    #[should_panic]
1604    fn panic_inside_system() {
1605        let mut world = World::new();
1606        run_system(&mut world, || panic!("this system panics"));
1607    }
1608
1609    #[test]
1610    fn assert_systems() {
1611        use std::str::FromStr;
1612
1613        use crate::{prelude::*, system::assert_is_system};
1614
1615        /// Mocks a system that returns a value of type `T`.
1616        fn returning<T>() -> T {
1617            unimplemented!()
1618        }
1619
1620        /// Mocks an exclusive system that takes an input and returns an output.
1621        fn exclusive_in_out<A, B>(_: In<A>, _: &mut World) -> B {
1622            unimplemented!()
1623        }
1624
1625        fn static_system_param(_: StaticSystemParam<Query<'static, 'static, &W<u32>>>) {
1626            unimplemented!()
1627        }
1628
1629        fn exclusive_with_state(
1630            _: &mut World,
1631            _: Local<bool>,
1632            _: (&mut QueryState<&W<i32>>, &mut SystemState<Query<&W<u32>>>),
1633            _: (),
1634        ) {
1635            unimplemented!()
1636        }
1637
1638        fn not(In(val): In<bool>) -> bool {
1639            !val
1640        }
1641
1642        assert_is_system(returning::<Result<u32, std::io::Error>>.map(Result::unwrap));
1643        assert_is_system(returning::<Option<()>>.map(drop));
1644        assert_is_system(returning::<&str>.map(u64::from_str).map(Result::unwrap));
1645        assert_is_system(static_system_param);
1646        assert_is_system(exclusive_in_out::<(), Result<(), std::io::Error>>.map(bevy_utils::error));
1647        assert_is_system(exclusive_with_state);
1648        assert_is_system(returning::<bool>.pipe(exclusive_in_out::<bool, ()>));
1649
1650        returning::<()>.run_if(returning::<bool>.pipe(not));
1651    }
1652
1653    #[test]
1654    fn pipe_change_detection() {
1655        #[derive(Resource, Default)]
1656        struct Flag;
1657
1658        #[derive(Default)]
1659        struct Info {
1660            // If true, the respective system will mutate `Flag`.
1661            do_first: bool,
1662            do_second: bool,
1663
1664            // Will be set to true if the respective system saw that `Flag` changed.
1665            first_flag: bool,
1666            second_flag: bool,
1667        }
1668
1669        fn first(In(mut info): In<Info>, mut flag: ResMut<Flag>) -> Info {
1670            if flag.is_changed() {
1671                info.first_flag = true;
1672            }
1673            if info.do_first {
1674                *flag = Flag;
1675            }
1676
1677            info
1678        }
1679
1680        fn second(In(mut info): In<Info>, mut flag: ResMut<Flag>) -> Info {
1681            if flag.is_changed() {
1682                info.second_flag = true;
1683            }
1684            if info.do_second {
1685                *flag = Flag;
1686            }
1687
1688            info
1689        }
1690
1691        let mut world = World::new();
1692        world.init_resource::<Flag>();
1693        let mut sys = first.pipe(second);
1694        sys.initialize(&mut world);
1695
1696        sys.run(default(), &mut world);
1697
1698        // The second system should observe a change made in the first system.
1699        let info = sys.run(
1700            Info {
1701                do_first: true,
1702                ..default()
1703            },
1704            &mut world,
1705        );
1706        assert!(!info.first_flag);
1707        assert!(info.second_flag);
1708
1709        // When a change is made in the second system, the first system
1710        // should observe it the next time they are run.
1711        let info1 = sys.run(
1712            Info {
1713                do_second: true,
1714                ..default()
1715            },
1716            &mut world,
1717        );
1718        let info2 = sys.run(default(), &mut world);
1719        assert!(!info1.first_flag);
1720        assert!(!info1.second_flag);
1721        assert!(info2.first_flag);
1722        assert!(!info2.second_flag);
1723    }
1724
1725    #[test]
1726    fn test_combinator_clone() {
1727        let mut world = World::new();
1728        #[derive(Resource)]
1729        struct A;
1730        #[derive(Resource)]
1731        struct B;
1732        #[derive(Resource, PartialEq, Eq, Debug)]
1733        struct C(i32);
1734
1735        world.insert_resource(A);
1736        world.insert_resource(C(0));
1737        let mut sched = Schedule::default();
1738        sched.add_systems(
1739            (
1740                |mut res: ResMut<C>| {
1741                    res.0 += 1;
1742                },
1743                |mut res: ResMut<C>| {
1744                    res.0 += 2;
1745                },
1746            )
1747                .distributive_run_if(resource_exists::<A>.or_else(resource_exists::<B>)),
1748        );
1749        sched.initialize(&mut world).unwrap();
1750        sched.run(&mut world);
1751        assert_eq!(world.get_resource(), Some(&C(3)));
1752    }
1753}