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