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