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