1mod 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::{FromWorld, World};
157
158#[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 type System: System<In = In, Out = Out>;
188
189 fn into_system(this: Self) -> Self::System;
191
192 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 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 fn with_input<T>(self, value: T) -> WithInputWrapper<Self::System, T>
254 where
255 for<'i> In: SystemInput<Inner<'i> = &'i mut T>,
256 T: Send + Sync + 'static,
257 {
258 WithInputWrapper::new(self, value)
259 }
260
261 fn with_input_from<T>(self) -> WithInputFromWrapper<Self::System, T>
295 where
296 for<'i> In: SystemInput<Inner<'i> = &'i mut T>,
297 T: FromWorld + Send + Sync + 'static,
298 {
299 WithInputFromWrapper::new(self)
300 }
301
302 #[inline]
304 fn system_type_id(&self) -> TypeId {
305 TypeId::of::<Self::System>()
306 }
307}
308
309impl<T: System> IntoSystem<T::In, T::Out, ()> for T {
311 type System = T;
312 fn into_system(this: Self) -> Self {
313 this
314 }
315}
316
317pub fn assert_is_system<In: SystemInput, Out: 'static, Marker>(
342 system: impl IntoSystem<In, Out, Marker>,
343) {
344 let mut system = IntoSystem::into_system(system);
345
346 let mut world = World::new();
348 system.initialize(&mut world);
349}
350
351pub fn assert_is_read_only_system<In, Out, Marker, S>(system: S)
375where
376 In: SystemInput,
377 Out: 'static,
378 S: IntoSystem<In, Out, Marker>,
379 S::System: ReadOnlySystem,
380{
381 assert_is_system(system);
382}
383
384pub fn assert_system_does_not_conflict<Out, Params, S: IntoSystem<(), Out, Params>>(sys: S) {
390 let mut world = World::new();
391 let mut system = IntoSystem::into_system(sys);
392 system.initialize(&mut world);
393 system.run((), &mut world).unwrap();
394}
395
396#[cfg(test)]
397#[expect(clippy::print_stdout, reason = "Allowed in tests.")]
398mod tests {
399 use alloc::{vec, vec::Vec};
400 use bevy_utils::default;
401 use core::any::TypeId;
402 use std::println;
403
404 use crate::{
405 archetype::Archetypes,
406 bundle::Bundles,
407 change_detection::DetectChanges,
408 component::{Component, Components},
409 entity::{Entities, Entity},
410 error::Result,
411 lifecycle::RemovedComponents,
412 name::Name,
413 prelude::{Add, AnyOf, EntityRef, On},
414 query::{Added, Changed, NestedQuery, Or, SpawnDetails, Spawned, With, Without},
415 resource::Resource,
416 schedule::{
417 common_conditions::resource_exists, ApplyDeferred, IntoScheduleConfigs, Schedule,
418 SystemCondition,
419 },
420 system::{
421 Commands, ExclusiveMarker, In, InMut, IntoSystem, Local, NonSend, NonSendMut, ParamSet,
422 Query, Res, ResMut, Single, StaticSystemParam, System, SystemState,
423 },
424 world::{DeferredWorld, EntityMut, FromWorld, World},
425 };
426
427 use super::ScheduleSystem;
428
429 #[derive(Resource, PartialEq, Debug)]
430 enum SystemRan {
431 Yes,
432 No,
433 }
434
435 #[derive(Component, Debug, Eq, PartialEq, Default)]
436 struct A;
437 #[derive(Component)]
438 struct B;
439 #[derive(Component)]
440 struct C;
441 #[derive(Component)]
442 struct D;
443 #[derive(Component)]
444 struct E;
445 #[derive(Component)]
446 struct F;
447
448 #[derive(Resource)]
449 struct ResA;
450 #[derive(Resource)]
451 struct ResB;
452 #[derive(Resource)]
453 struct ResC;
454 #[derive(Resource)]
455 struct ResD;
456 #[derive(Resource)]
457 struct ResE;
458 #[derive(Resource)]
459 struct ResF;
460
461 #[derive(Component, Debug)]
462 struct W<T>(T);
463
464 #[test]
465 fn simple_system() {
466 fn sys(query: Query<&A>) {
467 for a in &query {
468 println!("{a:?}");
469 }
470 }
471
472 let mut system = IntoSystem::into_system(sys);
473 let mut world = World::new();
474 world.spawn(A);
475
476 system.initialize(&mut world);
477 system.run((), &mut world).unwrap();
478 }
479
480 fn run_system<Marker, S: IntoScheduleConfigs<ScheduleSystem, Marker>>(
481 world: &mut World,
482 system: S,
483 ) {
484 let mut schedule = Schedule::default();
485 schedule.add_systems(system);
486 schedule.run(world);
487 }
488
489 #[test]
490 fn get_many_is_ordered() {
491 use crate::resource::Resource;
492 const ENTITIES_COUNT: usize = 1000;
493
494 #[derive(Resource)]
495 struct EntitiesArray(Vec<Entity>);
496
497 fn query_system(
498 mut ran: ResMut<SystemRan>,
499 entities_array: Res<EntitiesArray>,
500 q: Query<&W<usize>>,
501 ) {
502 let entities_array: [Entity; ENTITIES_COUNT] =
503 entities_array.0.clone().try_into().unwrap();
504
505 for (i, w) in (0..ENTITIES_COUNT).zip(q.get_many(entities_array).unwrap()) {
506 assert_eq!(i, w.0);
507 }
508
509 *ran = SystemRan::Yes;
510 }
511
512 fn query_system_mut(
513 mut ran: ResMut<SystemRan>,
514 entities_array: Res<EntitiesArray>,
515 mut q: Query<&mut W<usize>>,
516 ) {
517 let entities_array: [Entity; ENTITIES_COUNT] =
518 entities_array.0.clone().try_into().unwrap();
519
520 for (i, w) in (0..ENTITIES_COUNT).zip(q.get_many_mut(entities_array).unwrap()) {
521 assert_eq!(i, w.0);
522 }
523
524 *ran = SystemRan::Yes;
525 }
526
527 let mut world = World::default();
528 world.insert_resource(SystemRan::No);
529 let entity_ids = (0..ENTITIES_COUNT)
530 .map(|i| world.spawn(W(i)).id())
531 .collect();
532 world.insert_resource(EntitiesArray(entity_ids));
533
534 run_system(&mut world, query_system);
535 assert_eq!(*world.resource::<SystemRan>(), SystemRan::Yes);
536
537 world.insert_resource(SystemRan::No);
538 run_system(&mut world, query_system_mut);
539 assert_eq!(*world.resource::<SystemRan>(), SystemRan::Yes);
540 }
541
542 #[test]
543 fn or_param_set_system() {
544 fn query_system(
546 mut ran: ResMut<SystemRan>,
547 mut set: ParamSet<(
548 Query<(), Or<(Changed<A>, Changed<B>)>>,
549 Query<(), Or<(Added<A>, Added<B>)>>,
550 )>,
551 ) {
552 let changed = set.p0().iter().count();
553 let added = set.p1().iter().count();
554
555 assert_eq!(changed, 1);
556 assert_eq!(added, 1);
557
558 *ran = SystemRan::Yes;
559 }
560
561 let mut world = World::default();
562 world.insert_resource(SystemRan::No);
563 world.spawn((A, B));
564
565 run_system(&mut world, query_system);
566
567 assert_eq!(*world.resource::<SystemRan>(), SystemRan::Yes);
568 }
569
570 #[test]
571 fn changed_resource_system() {
572 use crate::resource::Resource;
573
574 #[derive(Resource)]
575 struct Flipper(bool);
576
577 #[derive(Resource)]
578 struct Added(usize);
579
580 #[derive(Resource)]
581 struct Changed(usize);
582
583 fn incr_e_on_flip(
584 value: Res<Flipper>,
585 mut changed: ResMut<Changed>,
586 mut added: ResMut<Added>,
587 ) {
588 if value.is_added() {
589 added.0 += 1;
590 }
591
592 if value.is_changed() {
593 changed.0 += 1;
594 }
595 }
596
597 let mut world = World::default();
598 world.insert_resource(Flipper(false));
599 world.insert_resource(Added(0));
600 world.insert_resource(Changed(0));
601
602 let mut schedule = Schedule::default();
603
604 schedule.add_systems((incr_e_on_flip, ApplyDeferred, World::clear_trackers).chain());
605
606 schedule.run(&mut world);
607 assert_eq!(world.resource::<Added>().0, 1);
608 assert_eq!(world.resource::<Changed>().0, 1);
609
610 schedule.run(&mut world);
611 assert_eq!(world.resource::<Added>().0, 1);
612 assert_eq!(world.resource::<Changed>().0, 1);
613
614 world.resource_mut::<Flipper>().0 = true;
615 schedule.run(&mut world);
616 assert_eq!(world.resource::<Added>().0, 1);
617 assert_eq!(world.resource::<Changed>().0, 2);
618 }
619
620 #[test]
621 #[should_panic = "error[B0001]"]
622 fn option_has_no_filter_with() {
623 fn sys(_: Query<(Option<&A>, &mut B)>, _: Query<&mut B, Without<A>>) {}
624 let mut world = World::default();
625 run_system(&mut world, sys);
626 }
627
628 #[test]
629 fn option_doesnt_remove_unrelated_filter_with() {
630 fn sys(_: Query<(Option<&A>, &mut B, &A)>, _: Query<&mut B, Without<A>>) {}
631 let mut world = World::default();
632 run_system(&mut world, sys);
633 }
634
635 #[test]
636 fn any_of_working() {
637 fn sys(_: Query<AnyOf<(&mut A, &B)>>) {}
638 let mut world = World::default();
639 run_system(&mut world, sys);
640 }
641
642 #[test]
643 fn any_of_with_and_without_common() {
644 fn sys(_: Query<(&mut D, &C, AnyOf<(&A, &B)>)>, _: Query<&mut D, Without<C>>) {}
645 let mut world = World::default();
646 run_system(&mut world, sys);
647 }
648
649 #[test]
650 #[should_panic]
651 fn any_of_with_mut_and_ref() {
652 fn sys(_: Query<AnyOf<(&mut A, &A)>>) {}
653 let mut world = World::default();
654 run_system(&mut world, sys);
655 }
656
657 #[test]
658 #[should_panic]
659 fn any_of_with_ref_and_mut() {
660 fn sys(_: Query<AnyOf<(&A, &mut A)>>) {}
661 let mut world = World::default();
662 run_system(&mut world, sys);
663 }
664
665 #[test]
666 #[should_panic]
667 fn any_of_with_mut_and_option() {
668 fn sys(_: Query<AnyOf<(&mut A, Option<&A>)>>) {}
669 let mut world = World::default();
670 run_system(&mut world, sys);
671 }
672
673 #[test]
674 fn any_of_with_entity_and_mut() {
675 fn sys(_: Query<AnyOf<(Entity, &mut A)>>) {}
676 let mut world = World::default();
677 run_system(&mut world, sys);
678 }
679
680 #[test]
681 fn any_of_with_empty_and_mut() {
682 fn sys(_: Query<AnyOf<((), &mut A)>>) {}
683 let mut world = World::default();
684 run_system(&mut world, sys);
685 }
686
687 #[test]
688 #[should_panic = "error[B0001]"]
689 fn any_of_has_no_filter_with() {
690 fn sys(_: Query<(AnyOf<(&A, ())>, &mut B)>, _: Query<&mut B, Without<A>>) {}
691 let mut world = World::default();
692 run_system(&mut world, sys);
693 }
694
695 #[test]
696 #[should_panic]
697 fn any_of_with_conflicting() {
698 fn sys(_: Query<AnyOf<(&mut A, &mut A)>>) {}
699 let mut world = World::default();
700 run_system(&mut world, sys);
701 }
702
703 #[test]
704 fn any_of_has_filter_with_when_both_have_it() {
705 fn sys(_: Query<(AnyOf<(&A, &A)>, &mut B)>, _: Query<&mut B, Without<A>>) {}
706 let mut world = World::default();
707 run_system(&mut world, sys);
708 }
709
710 #[test]
711 fn any_of_doesnt_remove_unrelated_filter_with() {
712 fn sys(_: Query<(AnyOf<(&A, ())>, &mut B, &A)>, _: Query<&mut B, Without<A>>) {}
713 let mut world = World::default();
714 run_system(&mut world, sys);
715 }
716
717 #[test]
718 fn any_of_and_without() {
719 fn sys(_: Query<(AnyOf<(&A, &B)>, &mut C)>, _: Query<&mut C, (Without<A>, Without<B>)>) {}
720 let mut world = World::default();
721 run_system(&mut world, sys);
722 }
723
724 #[test]
725 #[should_panic = "error[B0001]"]
726 fn or_has_no_filter_with() {
727 fn sys(_: Query<&mut B, Or<(With<A>, With<B>)>>, _: Query<&mut B, Without<A>>) {}
728 let mut world = World::default();
729 run_system(&mut world, sys);
730 }
731
732 #[test]
733 fn or_has_filter_with_when_both_have_it() {
734 fn sys(_: Query<&mut B, Or<(With<A>, With<A>)>>, _: Query<&mut B, Without<A>>) {}
735 let mut world = World::default();
736 run_system(&mut world, sys);
737 }
738
739 #[test]
740 fn or_has_filter_with() {
741 fn sys(
742 _: Query<&mut C, Or<(With<A>, With<B>)>>,
743 _: Query<&mut C, (Without<A>, Without<B>)>,
744 ) {
745 }
746 let mut world = World::default();
747 run_system(&mut world, sys);
748 }
749
750 #[test]
751 fn or_expanded_with_and_without_common() {
752 fn sys(_: Query<&mut D, (With<A>, Or<(With<B>, With<C>)>)>, _: Query<&mut D, Without<A>>) {}
753 let mut world = World::default();
754 run_system(&mut world, sys);
755 }
756
757 #[test]
758 fn or_expanded_nested_with_and_without_common() {
759 fn sys(
760 _: Query<&mut E, (Or<((With<B>, With<C>), (With<C>, With<D>))>, With<A>)>,
761 _: Query<&mut E, (Without<B>, Without<D>)>,
762 ) {
763 }
764 let mut world = World::default();
765 run_system(&mut world, sys);
766 }
767
768 #[test]
769 #[should_panic = "error[B0001]"]
770 fn or_expanded_nested_with_and_disjoint_without() {
771 fn sys(
772 _: Query<&mut E, (Or<((With<B>, With<C>), (With<C>, With<D>))>, With<A>)>,
773 _: Query<&mut E, Without<D>>,
774 ) {
775 }
776 let mut world = World::default();
777 run_system(&mut world, sys);
778 }
779
780 #[test]
781 #[should_panic = "error[B0001]"]
782 fn or_expanded_nested_or_with_and_disjoint_without() {
783 fn sys(
784 _: Query<&mut D, Or<(Or<(With<A>, With<B>)>, Or<(With<A>, With<C>)>)>>,
785 _: Query<&mut D, Without<A>>,
786 ) {
787 }
788 let mut world = World::default();
789 run_system(&mut world, sys);
790 }
791
792 #[test]
793 fn or_expanded_nested_with_and_common_nested_without() {
794 fn sys(
795 _: Query<&mut D, Or<((With<A>, With<B>), (With<B>, With<C>))>>,
796 _: Query<&mut D, Or<(Without<D>, Without<B>)>>,
797 ) {
798 }
799 let mut world = World::default();
800 run_system(&mut world, sys);
801 }
802
803 #[test]
804 fn or_with_without_and_compatible_with_without() {
805 fn sys(
806 _: Query<&mut C, Or<(With<A>, Without<B>)>>,
807 _: Query<&mut C, (With<B>, Without<A>)>,
808 ) {
809 }
810 let mut world = World::default();
811 run_system(&mut world, sys);
812 }
813
814 #[test]
815 #[should_panic = "error[B0001]"]
816 fn with_and_disjoint_or_empty_without() {
817 fn sys(_: Query<&mut B, With<A>>, _: Query<&mut B, Or<((), Without<A>)>>) {}
818 let mut world = World::default();
819 run_system(&mut world, sys);
820 }
821
822 #[test]
823 #[should_panic = "error[B0001]"]
824 fn or_expanded_with_and_disjoint_nested_without() {
825 fn sys(
826 _: Query<&mut D, Or<(With<A>, With<B>)>>,
827 _: Query<&mut D, Or<(Without<A>, Without<B>)>>,
828 ) {
829 }
830 let mut world = World::default();
831 run_system(&mut world, sys);
832 }
833
834 #[test]
835 #[should_panic = "error[B0001]"]
836 fn or_expanded_nested_with_and_disjoint_nested_without() {
837 fn sys(
838 _: Query<&mut D, Or<((With<A>, With<B>), (With<B>, With<C>))>>,
839 _: Query<&mut D, Or<(Without<A>, Without<B>)>>,
840 ) {
841 }
842 let mut world = World::default();
843 run_system(&mut world, sys);
844 }
845
846 #[test]
847 fn or_doesnt_remove_unrelated_filter_with() {
848 fn sys(_: Query<&mut B, (Or<(With<A>, With<B>)>, With<A>)>, _: Query<&mut B, Without<A>>) {}
849 let mut world = World::default();
850 run_system(&mut world, sys);
851 }
852
853 #[test]
854 #[should_panic]
855 fn conflicting_query_mut_system() {
856 fn sys(_q1: Query<&mut A>, _q2: Query<&mut A>) {}
857
858 let mut world = World::default();
859 run_system(&mut world, sys);
860 }
861
862 #[test]
863 fn disjoint_query_mut_system() {
864 fn sys(_q1: Query<&mut A, With<B>>, _q2: Query<&mut A, Without<B>>) {}
865
866 let mut world = World::default();
867 run_system(&mut world, sys);
868 }
869
870 #[test]
871 fn disjoint_query_mut_read_component_system() {
872 fn sys(_q1: Query<(&mut A, &B)>, _q2: Query<&mut A, Without<B>>) {}
873
874 let mut world = World::default();
875 run_system(&mut world, sys);
876 }
877
878 #[test]
879 #[should_panic]
880 fn conflicting_query_immut_system() {
881 fn sys(_q1: Query<&A>, _q2: Query<&mut A>) {}
882
883 let mut world = World::default();
884 run_system(&mut world, sys);
885 }
886
887 #[test]
888 #[should_panic]
889 fn changed_trackers_or_conflict() {
890 fn sys(_: Query<&mut A>, _: Query<(), Or<(Changed<A>,)>>) {}
891
892 let mut world = World::default();
893 run_system(&mut world, sys);
894 }
895
896 #[test]
897 #[should_panic = "error[B0001]"]
898 fn nested_query_conflicts_with_main_query() {
899 fn sys(_: Query<(&mut A, NestedQuery<&A>)>) {}
900
901 let mut world = World::default();
902 run_system(&mut world, sys);
903 }
904
905 #[test]
906 #[should_panic = "error[B0001]"]
907 fn nested_query_conflicts_with_earlier_query() {
908 fn sys(_: Query<&mut A>, _: Query<NestedQuery<&A>>) {}
909
910 let mut world = World::default();
911 run_system(&mut world, sys);
912 }
913
914 #[test]
915 #[should_panic = "error[B0001]"]
916 fn nested_query_conflicts_with_later_query() {
917 fn sys(_: Query<NestedQuery<&A>>, _: Query<&mut A>) {}
918
919 let mut world = World::default();
920 run_system(&mut world, sys);
921 }
922
923 #[test]
924 fn query_set_system() {
925 fn sys(mut _set: ParamSet<(Query<&mut A>, Query<&A>)>) {}
926 let mut world = World::default();
927 run_system(&mut world, sys);
928 }
929
930 #[test]
931 #[should_panic]
932 fn conflicting_query_with_query_set_system() {
933 fn sys(_query: Query<&mut A>, _set: ParamSet<(Query<&mut A>, Query<&B>)>) {}
934
935 let mut world = World::default();
936 run_system(&mut world, sys);
937 }
938
939 #[test]
940 #[should_panic]
941 fn conflicting_query_sets_system() {
942 fn sys(_set_1: ParamSet<(Query<&mut A>,)>, _set_2: ParamSet<(Query<&mut A>, Query<&B>)>) {}
943
944 let mut world = World::default();
945 run_system(&mut world, sys);
946 }
947
948 #[derive(Default, Resource)]
949 struct BufferRes {
950 _buffer: Vec<u8>,
951 }
952
953 fn test_for_conflicting_resources<Marker, S: IntoSystem<(), (), Marker>>(sys: S) {
954 let mut world = World::default();
955 world.insert_resource(BufferRes::default());
956 world.insert_resource(ResA);
957 world.insert_resource(ResB);
958 run_system(&mut world, sys);
959 }
960
961 #[test]
962 #[should_panic]
963 fn conflicting_system_resources() {
964 fn sys(_: ResMut<BufferRes>, _: Res<BufferRes>) {}
965 test_for_conflicting_resources(sys);
966 }
967
968 #[test]
969 #[should_panic]
970 fn conflicting_system_resources_reverse_order() {
971 fn sys(_: Res<BufferRes>, _: ResMut<BufferRes>) {}
972 test_for_conflicting_resources(sys);
973 }
974
975 #[test]
976 #[should_panic]
977 fn conflicting_system_resources_multiple_mutable() {
978 fn sys(_: ResMut<BufferRes>, _: ResMut<BufferRes>) {}
979 test_for_conflicting_resources(sys);
980 }
981
982 #[test]
983 fn nonconflicting_system_resources() {
984 fn sys(_: Local<BufferRes>, _: ResMut<BufferRes>, _: Local<A>, _: ResMut<ResA>) {}
985 test_for_conflicting_resources(sys);
986 }
987
988 #[test]
989 fn local_system() {
990 let mut world = World::default();
991 world.insert_resource(ProtoFoo { value: 1 });
992 world.insert_resource(SystemRan::No);
993
994 struct Foo {
995 value: u32,
996 }
997
998 #[derive(Resource)]
999 struct ProtoFoo {
1000 value: u32,
1001 }
1002
1003 impl FromWorld for Foo {
1004 fn from_world(world: &mut World) -> Self {
1005 Foo {
1006 value: world.resource::<ProtoFoo>().value + 1,
1007 }
1008 }
1009 }
1010
1011 fn sys(local: Local<Foo>, mut system_ran: ResMut<SystemRan>) {
1012 assert_eq!(local.value, 2);
1013 *system_ran = SystemRan::Yes;
1014 }
1015
1016 run_system(&mut world, sys);
1017
1018 assert_eq!(*world.resource::<SystemRan>(), SystemRan::Yes);
1020 }
1021
1022 #[test]
1023 #[expect(
1024 dead_code,
1025 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."
1026 )]
1027 fn non_send_option_system() {
1028 let mut world = World::default();
1029
1030 world.insert_resource(SystemRan::No);
1031 struct NotSend1(alloc::rc::Rc<i32>);
1035 struct NotSend2(alloc::rc::Rc<i32>);
1036 world.insert_non_send(NotSend1(alloc::rc::Rc::new(0)));
1037
1038 fn sys(
1039 op: Option<NonSend<NotSend1>>,
1040 mut _op2: Option<NonSendMut<NotSend2>>,
1041 mut system_ran: ResMut<SystemRan>,
1042 ) {
1043 op.expect("NonSend should exist");
1044 *system_ran = SystemRan::Yes;
1045 }
1046
1047 run_system(&mut world, sys);
1048 assert_eq!(*world.resource::<SystemRan>(), SystemRan::Yes);
1050 }
1051
1052 #[test]
1053 #[expect(
1054 dead_code,
1055 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."
1056 )]
1057 fn non_send_system() {
1058 let mut world = World::default();
1059
1060 world.insert_resource(SystemRan::No);
1061 struct NotSend1(alloc::rc::Rc<i32>);
1062 struct NotSend2(alloc::rc::Rc<i32>);
1063
1064 world.insert_non_send(NotSend1(alloc::rc::Rc::new(1)));
1065 world.insert_non_send(NotSend2(alloc::rc::Rc::new(2)));
1066
1067 fn sys(
1068 _op: NonSend<NotSend1>,
1069 mut _op2: NonSendMut<NotSend2>,
1070 mut system_ran: ResMut<SystemRan>,
1071 ) {
1072 *system_ran = SystemRan::Yes;
1073 }
1074
1075 run_system(&mut world, sys);
1076 assert_eq!(*world.resource::<SystemRan>(), SystemRan::Yes);
1077 }
1078
1079 #[test]
1080 fn function_system_as_exclusive() {
1081 let mut world = World::default();
1082
1083 world.insert_resource(SystemRan::No);
1084
1085 fn sys(_marker: ExclusiveMarker, mut system_ran: ResMut<SystemRan>) {
1086 *system_ran = SystemRan::Yes;
1087 }
1088
1089 let mut sys = IntoSystem::into_system(sys);
1090 sys.initialize(&mut world);
1091 assert!(sys.is_exclusive());
1092
1093 run_system(&mut world, sys);
1094 assert_eq!(*world.resource::<SystemRan>(), SystemRan::Yes);
1095 }
1096
1097 #[test]
1098 fn removal_tracking() {
1099 let mut world = World::new();
1100
1101 let entity_to_despawn = world.spawn(W(1)).id();
1102 let entity_to_remove_w_from = world.spawn(W(2)).id();
1103 let spurious_entity = world.spawn_empty().id();
1104
1105 #[derive(Resource)]
1107 struct Despawned(Entity);
1108 world.insert_resource(Despawned(entity_to_despawn));
1109
1110 #[derive(Resource)]
1111 struct Removed(Entity);
1112 world.insert_resource(Removed(entity_to_remove_w_from));
1113
1114 #[derive(Default, Resource)]
1116 struct NSystems(usize);
1117 world.insert_resource(NSystems::default());
1118
1119 world.entity_mut(entity_to_despawn).despawn();
1121 world.entity_mut(spurious_entity).despawn();
1122
1123 fn validate_despawn(
1124 mut removed_i32: RemovedComponents<W<i32>>,
1125 despawned: Res<Despawned>,
1126 mut n_systems: ResMut<NSystems>,
1127 ) {
1128 assert_eq!(
1129 removed_i32.read().collect::<Vec<_>>(),
1130 &[despawned.0],
1131 "despawning causes the correct entity to show up in the 'RemovedComponent' system parameter."
1132 );
1133
1134 n_systems.0 += 1;
1135 }
1136
1137 run_system(&mut world, validate_despawn);
1138
1139 world.clear_trackers();
1142
1143 world.spawn(W(3));
1145 world.spawn(W(4));
1146 world.entity_mut(entity_to_remove_w_from).remove::<W<i32>>();
1147
1148 fn validate_remove(
1149 mut removed_i32: RemovedComponents<W<i32>>,
1150 despawned: Res<Despawned>,
1151 removed: Res<Removed>,
1152 mut n_systems: ResMut<NSystems>,
1153 ) {
1154 assert_eq!(
1157 removed_i32.read().collect::<Vec<_>>(),
1158 &[despawned.0, removed.0],
1159 "removing a component causes the correct entity to show up in the 'RemovedComponent' system parameter."
1160 );
1161
1162 n_systems.0 += 1;
1163 }
1164
1165 run_system(&mut world, validate_remove);
1166
1167 assert_eq!(world.resource::<NSystems>().0, 2);
1169 }
1170
1171 #[test]
1172 fn world_collections_system() {
1173 let mut world = World::default();
1174 world.insert_resource(SystemRan::No);
1175 world.spawn((W(42), W(true)));
1176 fn sys(
1177 archetypes: &Archetypes,
1178 components: &Components,
1179 entities: &Entities,
1180 bundles: &Bundles,
1181 query: Query<Entity, With<W<i32>>>,
1182 mut system_ran: ResMut<SystemRan>,
1183 ) {
1184 assert_eq!(query.iter().count(), 1, "entity exists");
1185 for entity in &query {
1186 let location = entities.get_spawned(entity).unwrap();
1187 let archetype = archetypes.get(location.archetype_id).unwrap();
1188 let archetype_components = archetype.components();
1189 let bundle_id = bundles
1190 .get_id(TypeId::of::<(W<i32>, W<bool>)>())
1191 .expect("Bundle used to spawn entity should exist");
1192 let bundle_info = bundles.get(bundle_id).unwrap();
1193 let mut bundle_components = bundle_info.contributed_components().to_vec();
1194 bundle_components.sort();
1195 for component_id in &bundle_components {
1196 assert!(
1197 components.get_info(*component_id).is_some(),
1198 "every bundle component exists in Components"
1199 );
1200 }
1201 assert_eq!(
1202 bundle_components, archetype_components,
1203 "entity's bundle components exactly match entity's archetype components"
1204 );
1205 }
1206 *system_ran = SystemRan::Yes;
1207 }
1208
1209 run_system(&mut world, sys);
1210
1211 assert_eq!(*world.resource::<SystemRan>(), SystemRan::Yes);
1213 }
1214
1215 #[test]
1216 fn get_system_conflicts() {
1217 fn sys_x(_: Res<ResA>, _: Res<ResB>, _: Query<(&C, &D)>) {}
1218
1219 fn sys_y(_: Res<ResA>, _: ResMut<ResB>, _: Query<(&C, &mut D)>) {}
1220
1221 let mut world = World::default();
1222 let mut x = IntoSystem::into_system(sys_x);
1223 let mut y = IntoSystem::into_system(sys_y);
1224 let x_access = x.initialize(&mut world);
1225 let y_access = y.initialize(&mut world);
1226
1227 let conflicts = x_access.get_conflicts(&y_access);
1228 let b_id = world.components().get_id(TypeId::of::<ResB>()).unwrap();
1229 let d_id = world.components().get_id(TypeId::of::<D>()).unwrap();
1230 assert_eq!(conflicts, vec![b_id, d_id].into());
1231 }
1232
1233 #[test]
1234 fn query_is_empty() {
1235 fn without_filter(not_empty: Query<&A>, empty: Query<&B>) {
1236 assert!(!not_empty.is_empty());
1237 assert!(empty.is_empty());
1238 }
1239
1240 fn with_filter(not_empty: Query<&A, With<C>>, empty: Query<&A, With<D>>) {
1241 assert!(!not_empty.is_empty());
1242 assert!(empty.is_empty());
1243 }
1244
1245 let mut world = World::default();
1246 world.spawn(A).insert(C);
1247
1248 let mut without_filter = IntoSystem::into_system(without_filter);
1249 without_filter.initialize(&mut world);
1250 without_filter.run((), &mut world).unwrap();
1251
1252 let mut with_filter = IntoSystem::into_system(with_filter);
1253 with_filter.initialize(&mut world);
1254 with_filter.run((), &mut world).unwrap();
1255 }
1256
1257 #[test]
1258 fn can_have_16_parameters() {
1259 fn sys_x(
1260 _: Res<ResA>,
1261 _: Res<ResB>,
1262 _: Res<ResC>,
1263 _: Res<ResD>,
1264 _: Res<ResE>,
1265 _: Res<ResF>,
1266 _: Query<&A>,
1267 _: Query<&B>,
1268 _: Query<&C>,
1269 _: Query<&D>,
1270 _: Query<&E>,
1271 _: Query<&F>,
1272 _: Query<(&A, &B)>,
1273 _: Query<(&C, &D)>,
1274 _: Query<(&E, &F)>,
1275 ) {
1276 }
1277 fn sys_y(
1278 _: (
1279 Res<ResA>,
1280 Res<ResB>,
1281 Res<ResC>,
1282 Res<ResD>,
1283 Res<ResE>,
1284 Res<ResF>,
1285 Query<&A>,
1286 Query<&B>,
1287 Query<&C>,
1288 Query<&D>,
1289 Query<&E>,
1290 Query<&F>,
1291 Query<(&A, &B)>,
1292 Query<(&C, &D)>,
1293 Query<(&E, &F)>,
1294 ),
1295 ) {
1296 }
1297 let mut world = World::default();
1298 let mut x = IntoSystem::into_system(sys_x);
1299 let mut y = IntoSystem::into_system(sys_y);
1300 x.initialize(&mut world);
1301 y.initialize(&mut world);
1302 }
1303
1304 #[test]
1305 fn read_system_state() {
1306 #[derive(Eq, PartialEq, Debug, Resource)]
1307 struct A(usize);
1308
1309 #[derive(Component, Eq, PartialEq, Debug)]
1310 struct B(usize);
1311
1312 let mut world = World::default();
1313 world.insert_resource(A(42));
1314 world.spawn(B(7));
1315
1316 let mut system_state: SystemState<(
1317 Res<A>,
1318 Option<Single<&B>>,
1319 ParamSet<(Query<&C>, Query<&D>)>,
1320 )> = SystemState::new(&mut world);
1321 let (a, query, _) = system_state.get(&world).unwrap();
1322 assert_eq!(*a, A(42), "returned resource matches initial value");
1323 assert_eq!(
1324 **query.unwrap(),
1325 B(7),
1326 "returned component matches initial value"
1327 );
1328 }
1329
1330 #[test]
1331 fn write_system_state() {
1332 #[derive(Resource, Eq, PartialEq, Debug)]
1333 struct A(usize);
1334
1335 #[derive(Component, Eq, PartialEq, Debug)]
1336 struct B(usize);
1337
1338 let mut world = World::default();
1339 world.insert_resource(A(42));
1340 world.spawn(B(7));
1341
1342 let mut system_state: SystemState<(ResMut<A>, Option<Single<&mut B>>)> =
1343 SystemState::new(&mut world);
1344
1345 let (a, query) = system_state.get_mut(&mut world).unwrap();
1349 assert_eq!(*a, A(42), "returned resource matches initial value");
1350 assert_eq!(
1351 **query.unwrap(),
1352 B(7),
1353 "returned component matches initial value"
1354 );
1355 }
1356
1357 #[test]
1358 fn system_state_change_detection() {
1359 #[derive(Component, Eq, PartialEq, Debug)]
1360 struct A(usize);
1361
1362 let mut world = World::default();
1363 let entity = world.spawn(A(1)).id();
1364
1365 let mut system_state: SystemState<Option<Single<&A, Changed<A>>>> =
1366 SystemState::new(&mut world);
1367 {
1368 let query = system_state.get(&world).unwrap();
1369 assert_eq!(**query.unwrap(), A(1));
1370 }
1371
1372 {
1373 let query = system_state.get(&world).unwrap();
1374 assert!(query.is_none());
1375 }
1376
1377 world.entity_mut(entity).get_mut::<A>().unwrap().0 = 2;
1378 {
1379 let query = system_state.get(&world).unwrap();
1380 assert_eq!(**query.unwrap(), A(2));
1381 }
1382 }
1383
1384 #[test]
1385 fn system_state_spawned() {
1386 let mut world = World::default();
1387 world.spawn(A);
1388 let spawn_tick = world.change_tick();
1389
1390 let mut system_state: SystemState<Option<Single<(&A, SpawnDetails), Spawned>>> =
1391 SystemState::new(&mut world);
1392 {
1393 let query = system_state.get(&world).unwrap();
1394 assert_eq!(query.unwrap().1.spawn_tick(), spawn_tick);
1395 }
1396
1397 {
1398 let query = system_state.get(&world).unwrap();
1399 assert!(query.is_none());
1400 }
1401 }
1402
1403 #[test]
1404 #[should_panic]
1405 fn system_state_invalid_world() {
1406 let mut world = World::default();
1407 let mut system_state = SystemState::<Query<&A>>::new(&mut world);
1408 let mismatched_world = World::default();
1409 system_state.get(&mismatched_world).unwrap();
1410 }
1411
1412 #[test]
1413 fn system_state_archetype_update() {
1414 #[derive(Component, Eq, PartialEq, Debug)]
1415 struct A(usize);
1416
1417 #[derive(Component, Eq, PartialEq, Debug)]
1418 struct B(usize);
1419
1420 let mut world = World::default();
1421 world.spawn(A(1));
1422
1423 let mut system_state = SystemState::<Query<&A>>::new(&mut world);
1424 {
1425 let query = system_state.get(&world).unwrap();
1426 assert_eq!(
1427 query.iter().collect::<Vec<_>>(),
1428 vec![&A(1)],
1429 "exactly one component returned"
1430 );
1431 }
1432
1433 world.spawn((A(2), B(2)));
1434 {
1435 let query = system_state.get(&world).unwrap();
1436 assert_eq!(
1437 query.iter().collect::<Vec<_>>(),
1438 vec![&A(1), &A(2)],
1439 "components from both archetypes returned"
1440 );
1441 }
1442 }
1443
1444 #[test]
1445 #[expect(
1446 dead_code,
1447 reason = "This test exists to show that read-only world-only queries can return data that lives as long as `'world`."
1448 )]
1449 fn long_life_test() {
1450 struct ResourceHolder<'w> {
1451 value: &'w ResA,
1452 }
1453
1454 struct Holder<'w> {
1455 value: &'w A,
1456 }
1457
1458 struct State {
1459 state: SystemState<Res<'static, ResA>>,
1460 state_q: SystemState<Query<'static, 'static, &'static A>>,
1461 }
1462
1463 impl State {
1464 fn hold_res<'w>(&mut self, world: &'w World) -> ResourceHolder<'w> {
1465 let a = self.state.get(world).unwrap();
1466 ResourceHolder {
1467 value: a.into_inner(),
1468 }
1469 }
1470 fn hold_component<'w>(&mut self, world: &'w World, entity: Entity) -> Holder<'w> {
1471 let q = self.state_q.get(world).unwrap();
1472 let a = q.get_inner(entity).unwrap();
1473 Holder { value: a }
1474 }
1475 fn hold_components<'w>(&mut self, world: &'w World) -> Vec<Holder<'w>> {
1476 let mut components = Vec::new();
1477 let q = self.state_q.get(world).unwrap();
1478 for a in q.iter_inner() {
1479 components.push(Holder { value: a });
1480 }
1481 components
1482 }
1483 }
1484 }
1485
1486 #[test]
1487 fn immutable_mut_test() {
1488 #[derive(Component, Eq, PartialEq, Debug, Clone, Copy)]
1489 struct A(usize);
1490
1491 let mut world = World::default();
1492 world.spawn(A(1));
1493 world.spawn(A(2));
1494
1495 let mut system_state = SystemState::<Query<&mut A>>::new(&mut world);
1496 {
1497 let mut query = system_state.get_mut(&mut world).unwrap();
1498 assert_eq!(
1499 query.iter_mut().map(|m| *m).collect::<Vec<A>>(),
1500 vec![A(1), A(2)],
1501 "both components returned by iter_mut of &mut"
1502 );
1503 assert_eq!(
1504 query.iter().collect::<Vec<&A>>(),
1505 vec![&A(1), &A(2)],
1506 "both components returned by iter of &mut"
1507 );
1508 }
1509 }
1510
1511 #[test]
1512 fn convert_mut_to_immut() {
1513 {
1514 let mut world = World::new();
1515
1516 fn mutable_query(mut query: Query<&mut A>) {
1517 for _ in &mut query {}
1518
1519 immutable_query(query.as_readonly());
1520 }
1521
1522 fn immutable_query(_: Query<&A>) {}
1523
1524 let mut sys = IntoSystem::into_system(mutable_query);
1525 sys.initialize(&mut world);
1526 }
1527
1528 {
1529 let mut world = World::new();
1530
1531 fn mutable_query(mut query: Query<Option<&mut A>>) {
1532 for _ in &mut query {}
1533
1534 immutable_query(query.as_readonly());
1535 }
1536
1537 fn immutable_query(_: Query<Option<&A>>) {}
1538
1539 let mut sys = IntoSystem::into_system(mutable_query);
1540 sys.initialize(&mut world);
1541 }
1542
1543 {
1544 let mut world = World::new();
1545
1546 fn mutable_query(mut query: Query<(&mut A, &B)>) {
1547 for _ in &mut query {}
1548
1549 immutable_query(query.as_readonly());
1550 }
1551
1552 fn immutable_query(_: Query<(&A, &B)>) {}
1553
1554 let mut sys = IntoSystem::into_system(mutable_query);
1555 sys.initialize(&mut world);
1556 }
1557
1558 {
1559 let mut world = World::new();
1560
1561 fn mutable_query(mut query: Query<(&mut A, &mut B)>) {
1562 for _ in &mut query {}
1563
1564 immutable_query(query.as_readonly());
1565 }
1566
1567 fn immutable_query(_: Query<(&A, &B)>) {}
1568
1569 let mut sys = IntoSystem::into_system(mutable_query);
1570 sys.initialize(&mut world);
1571 }
1572
1573 {
1574 let mut world = World::new();
1575
1576 fn mutable_query(mut query: Query<(&mut A, &mut B), With<C>>) {
1577 for _ in &mut query {}
1578
1579 immutable_query(query.as_readonly());
1580 }
1581
1582 fn immutable_query(_: Query<(&A, &B), With<C>>) {}
1583
1584 let mut sys = IntoSystem::into_system(mutable_query);
1585 sys.initialize(&mut world);
1586 }
1587
1588 {
1589 let mut world = World::new();
1590
1591 fn mutable_query(mut query: Query<(&mut A, &mut B), Without<C>>) {
1592 for _ in &mut query {}
1593
1594 immutable_query(query.as_readonly());
1595 }
1596
1597 fn immutable_query(_: Query<(&A, &B), Without<C>>) {}
1598
1599 let mut sys = IntoSystem::into_system(mutable_query);
1600 sys.initialize(&mut world);
1601 }
1602
1603 {
1604 let mut world = World::new();
1605
1606 fn mutable_query(mut query: Query<(&mut A, &mut B), Added<C>>) {
1607 for _ in &mut query {}
1608
1609 immutable_query(query.as_readonly());
1610 }
1611
1612 fn immutable_query(_: Query<(&A, &B), Added<C>>) {}
1613
1614 let mut sys = IntoSystem::into_system(mutable_query);
1615 sys.initialize(&mut world);
1616 }
1617
1618 {
1619 let mut world = World::new();
1620
1621 fn mutable_query(mut query: Query<(&mut A, &mut B), Changed<C>>) {
1622 for _ in &mut query {}
1623
1624 immutable_query(query.as_readonly());
1625 }
1626
1627 fn immutable_query(_: Query<(&A, &B), Changed<C>>) {}
1628
1629 let mut sys = IntoSystem::into_system(mutable_query);
1630 sys.initialize(&mut world);
1631 }
1632
1633 {
1634 let mut world = World::new();
1635
1636 fn mutable_query(mut query: Query<(&mut A, &mut B, SpawnDetails), Spawned>) {
1637 for _ in &mut query {}
1638
1639 immutable_query(query.as_readonly());
1640 }
1641
1642 fn immutable_query(_: Query<(&A, &B, SpawnDetails), Spawned>) {}
1643
1644 let mut sys = IntoSystem::into_system(mutable_query);
1645 sys.initialize(&mut world);
1646 }
1647 }
1648
1649 #[test]
1650 fn commands_param_set() {
1651 let mut world = World::new();
1653 let entity = world.spawn_empty().id();
1654
1655 run_system(
1656 &mut world,
1657 move |mut commands_set: ParamSet<(Commands, Commands)>| {
1658 commands_set.p0().entity(entity).insert(A);
1659 commands_set.p1().entity(entity).insert(B);
1660 },
1661 );
1662
1663 let entity = world.entity(entity);
1664 assert!(entity.contains::<A>());
1665 assert!(entity.contains::<B>());
1666 }
1667
1668 #[test]
1669 fn into_iter_impl() {
1670 let mut world = World::new();
1671 world.spawn(W(42u32));
1672 run_system(&mut world, |mut q: Query<&mut W<u32>>| {
1673 for mut a in &mut q {
1674 assert_eq!(a.0, 42);
1675 a.0 = 0;
1676 }
1677 for a in &q {
1678 assert_eq!(a.0, 0);
1679 }
1680 });
1681 }
1682
1683 #[test]
1684 #[should_panic]
1685 fn assert_system_does_not_conflict() {
1686 fn system(_query: Query<(&mut W<u32>, &mut W<u32>)>) {}
1687 super::assert_system_does_not_conflict(system);
1688 }
1689
1690 #[test]
1691 #[should_panic]
1692 fn assert_world_and_entity_mut_system_does_conflict_first() {
1693 fn system(_query: &World, _q2: Query<EntityMut>) {}
1694 super::assert_system_does_not_conflict(system);
1695 }
1696
1697 #[test]
1698 #[should_panic]
1699 fn assert_world_and_entity_mut_system_does_conflict_second() {
1700 fn system(_: Query<EntityMut>, _: &World) {}
1701 super::assert_system_does_not_conflict(system);
1702 }
1703
1704 #[test]
1705 #[should_panic]
1706 fn assert_entity_ref_and_entity_mut_system_does_conflict() {
1707 fn system(_query: Query<EntityRef>, _q2: Query<EntityMut>) {}
1708 super::assert_system_does_not_conflict(system);
1709 }
1710
1711 #[test]
1712 #[should_panic]
1713 fn assert_entity_mut_system_does_conflict() {
1714 fn system(_query: Query<EntityMut>, _q2: Query<EntityMut>) {}
1715 super::assert_system_does_not_conflict(system);
1716 }
1717
1718 #[test]
1719 #[should_panic]
1720 fn assert_deferred_world_and_entity_ref_system_does_conflict_first() {
1721 fn system(_world: DeferredWorld, _query: Query<EntityRef>) {}
1722 super::assert_system_does_not_conflict(system);
1723 }
1724
1725 #[test]
1726 #[should_panic]
1727 fn assert_deferred_world_and_entity_ref_system_does_conflict_second() {
1728 fn system(_query: Query<EntityRef>, _world: DeferredWorld) {}
1729 super::assert_system_does_not_conflict(system);
1730 }
1731
1732 #[test]
1733 fn assert_deferred_world_and_empty_query_does_not_conflict_first() {
1734 fn system(_world: DeferredWorld, _query: Query<Entity>) {}
1735 super::assert_system_does_not_conflict(system);
1736 }
1737
1738 #[test]
1739 fn assert_deferred_world_and_empty_query_does_not_conflict_second() {
1740 fn system(_query: Query<Entity>, _world: DeferredWorld) {}
1741 super::assert_system_does_not_conflict(system);
1742 }
1743
1744 #[test]
1745 #[should_panic]
1746 fn panic_inside_system() {
1747 let mut world = World::new();
1748 let system: fn() = || {
1749 panic!("this system panics");
1750 };
1751 run_system(&mut world, system);
1752 }
1753
1754 #[test]
1755 fn assert_systems() {
1756 use core::str::FromStr;
1757
1758 use crate::{prelude::*, system::assert_is_system};
1759
1760 fn returning<T>() -> T {
1762 unimplemented!()
1763 }
1764
1765 fn exclusive_in_out<A, B>(_: In<A>, _: &mut World) -> B {
1767 unimplemented!()
1768 }
1769
1770 fn static_system_param(_: StaticSystemParam<Query<'static, 'static, &W<u32>>>) {
1771 unimplemented!()
1772 }
1773
1774 fn exclusive_with_state(
1775 _: &mut World,
1776 _: Local<bool>,
1777 _: (&mut QueryState<&W<i32>>, &mut SystemState<Query<&W<u32>>>),
1778 _: (),
1779 ) {
1780 unimplemented!()
1781 }
1782
1783 fn not(In(val): In<bool>) -> bool {
1784 !val
1785 }
1786
1787 assert_is_system(returning::<Result<u32, std::io::Error>>.map(Result::unwrap));
1788 assert_is_system(returning::<Option<()>>.map(drop));
1789 assert_is_system(returning::<&str>.map(u64::from_str).map(Result::unwrap));
1790 assert_is_system(static_system_param);
1791 assert_is_system(
1792 exclusive_in_out::<(), Result<(), std::io::Error>>.map(|_out| {
1793 #[cfg(feature = "trace")]
1794 if let Err(error) = _out {
1795 tracing::error!("{}", error);
1796 }
1797 }),
1798 );
1799 assert_is_system(exclusive_with_state);
1800 assert_is_system(returning::<bool>.pipe(exclusive_in_out::<bool, ()>));
1801
1802 returning::<()>.run_if(returning::<bool>.pipe(not));
1803 }
1804
1805 #[test]
1806 fn pipe_change_detection() {
1807 #[derive(Resource, Default)]
1808 struct Flag;
1809
1810 #[derive(Default)]
1811 struct Info {
1812 do_first: bool,
1814 do_second: bool,
1815
1816 first_flag: bool,
1818 second_flag: bool,
1819 }
1820
1821 fn first(In(mut info): In<Info>, mut flag: ResMut<Flag>) -> Info {
1822 if flag.is_changed() {
1823 info.first_flag = true;
1824 }
1825 if info.do_first {
1826 *flag = Flag;
1827 }
1828
1829 info
1830 }
1831
1832 fn second(In(mut info): In<Info>, mut flag: ResMut<Flag>) -> Info {
1833 if flag.is_changed() {
1834 info.second_flag = true;
1835 }
1836 if info.do_second {
1837 *flag = Flag;
1838 }
1839
1840 info
1841 }
1842
1843 let mut world = World::new();
1844 world.init_resource::<Flag>();
1845 let mut sys = IntoSystem::into_system(first.pipe(second));
1846 sys.initialize(&mut world);
1847
1848 sys.run(default(), &mut world).unwrap();
1849
1850 let info = sys
1852 .run(
1853 Info {
1854 do_first: true,
1855 ..default()
1856 },
1857 &mut world,
1858 )
1859 .unwrap();
1860 assert!(!info.first_flag);
1861 assert!(info.second_flag);
1862
1863 let info1 = sys
1866 .run(
1867 Info {
1868 do_second: true,
1869 ..default()
1870 },
1871 &mut world,
1872 )
1873 .unwrap();
1874 let info2 = sys.run(default(), &mut world).unwrap();
1875 assert!(!info1.first_flag);
1876 assert!(!info1.second_flag);
1877 assert!(info2.first_flag);
1878 assert!(!info2.second_flag);
1879 }
1880
1881 #[test]
1882 fn test_combinator_clone() {
1883 let mut world = World::new();
1884 #[derive(Resource)]
1885 struct A;
1886 #[derive(Resource)]
1887 struct B;
1888 #[derive(Resource, PartialEq, Eq, Debug)]
1889 struct C(i32);
1890
1891 world.insert_resource(A);
1892 world.insert_resource(C(0));
1893 let mut sched = Schedule::default();
1894 sched.add_systems(
1895 (
1896 |mut res: ResMut<C>| {
1897 res.0 += 1;
1898 },
1899 |mut res: ResMut<C>| {
1900 res.0 += 2;
1901 },
1902 )
1903 .distributive_run_if(resource_exists::<A>.or_eager(resource_exists::<B>)),
1904 );
1905 sched.initialize(&mut world).unwrap();
1906 sched.run(&mut world);
1907 assert_eq!(world.get_resource(), Some(&C(3)));
1908 }
1909
1910 #[test]
1911 #[cfg_attr(not(feature = "debug"), ignore)]
1912 #[should_panic(
1913 expected = "Encountered an error in system `bevy_ecs::system::tests::simple_fallible_system::sys`: error"
1914 )]
1915 fn simple_fallible_system() {
1916 fn sys() -> Result {
1917 Err("error")?;
1918 Ok(())
1919 }
1920
1921 let mut world = World::new();
1922 run_system(&mut world, sys);
1923 }
1924
1925 #[test]
1926 #[cfg_attr(not(feature = "debug"), ignore)]
1927 #[should_panic(
1928 expected = "Encountered an error in system `bevy_ecs::system::tests::simple_fallible_exclusive_system::sys`: error"
1929 )]
1930 fn simple_fallible_exclusive_system() {
1931 fn sys(_world: &mut World) -> Result {
1932 Err("error")?;
1933 Ok(())
1934 }
1935
1936 let mut world = World::new();
1937 run_system(&mut world, sys);
1938 }
1939
1940 #[test]
1954 fn nondiverging_never_trait_impls() {
1955 let mut world = World::new();
1960 let mut schedule = Schedule::default();
1961
1962 fn sys(_query: Query<&Name>) {
1963 todo!()
1964 }
1965
1966 schedule.add_systems(sys);
1967 schedule.add_systems(|_query: Query<&Name>| {});
1968 schedule.add_systems(|_query: Query<&Name>| todo!());
1969 schedule.add_systems(|_query: Query<&Name>| -> () { todo!() });
1970
1971 fn obs(_event: On<Add, Name>) {
1972 todo!()
1973 }
1974
1975 world.add_observer(obs);
1976 world.add_observer(|_event: On<Add, Name>| {});
1977 world.add_observer(|_event: On<Add, Name>| todo!());
1978 world.add_observer(|_event: On<Add, Name>| -> () { todo!() });
1979
1980 fn my_command(_world: &mut World) {
1981 todo!()
1982 }
1983
1984 world.commands().queue(my_command);
1985 world.commands().queue(|_world: &mut World| {});
1986 world.commands().queue(|_world: &mut World| todo!());
1987 world
1988 .commands()
1989 .queue(|_world: &mut World| -> () { todo!() });
1990 }
1991
1992 #[test]
1993 fn with_input() {
1994 fn sys(InMut(v): InMut<usize>) {
1995 *v += 1;
1996 }
1997
1998 let mut world = World::new();
1999 let mut system = IntoSystem::into_system(sys.with_input(42));
2000 system.initialize(&mut world);
2001 system.run((), &mut world).unwrap();
2002 assert_eq!(*system.value(), 43);
2003 }
2004
2005 #[test]
2006 fn with_input_from() {
2007 struct TestData(usize);
2008
2009 impl FromWorld for TestData {
2010 fn from_world(_world: &mut World) -> Self {
2011 Self(5)
2012 }
2013 }
2014
2015 fn sys(InMut(v): InMut<TestData>) {
2016 v.0 += 1;
2017 }
2018
2019 let mut world = World::new();
2020 let mut system = IntoSystem::into_system(sys.with_input_from::<TestData>());
2021 assert!(system.value().is_none());
2022 system.initialize(&mut world);
2023 assert!(system.value().is_some());
2024 system.run((), &mut world).unwrap();
2025 assert_eq!(system.value().unwrap().0, 6);
2026 }
2027}