1mod 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#[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 type System: System<In = In, Out = Out>;
173
174 fn into_system(this: Self) -> Self::System;
176
177 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 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 #[inline]
218 fn system_type_id(&self) -> TypeId {
219 TypeId::of::<Self::System>()
220 }
221}
222
223impl<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
231pub 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 let mut world = World::new();
262 system.initialize(&mut world);
263}
264
265pub 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
298pub 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 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 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 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 #[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 #[derive(Default, Resource)]
956 struct NSystems(usize);
957 world.insert_resource(NSystems::default());
958
959 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 world.clear_trackers();
982
983 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 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 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 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 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 #[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 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 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 world.spawn((A, B));
1490 world.spawn((B, C));
1491
1492 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 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 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 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 fn returning<T>() -> T {
1616 unimplemented!()
1617 }
1618
1619 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 do_first: bool,
1661 do_second: bool,
1662
1663 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 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 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}