1pub use crate::change_detection::{NonSendMut, Res, ResMut};
2use crate::{
3 archetype::Archetypes,
4 bundle::Bundles,
5 change_detection::{MaybeLocation, Ticks, TicksMut},
6 component::{ComponentId, ComponentTicks, Components, Tick},
7 entity::Entities,
8 query::{
9 Access, FilteredAccess, FilteredAccessSet, QueryData, QueryFilter, QuerySingleError,
10 QueryState, ReadOnlyQueryData,
11 },
12 resource::Resource,
13 storage::ResourceData,
14 system::{Query, Single, SystemMeta},
15 world::{
16 unsafe_world_cell::UnsafeWorldCell, DeferredWorld, FilteredResources, FilteredResourcesMut,
17 FromWorld, World,
18 },
19};
20use alloc::{
21 borrow::{Cow, ToOwned},
22 boxed::Box,
23 vec::Vec,
24};
25pub use bevy_ecs_macros::SystemParam;
26use bevy_platform::cell::SyncCell;
27use bevy_ptr::UnsafeCellDeref;
28use bevy_utils::prelude::DebugName;
29use core::{
30 any::Any,
31 fmt::{Debug, Display},
32 marker::PhantomData,
33 ops::{Deref, DerefMut},
34 panic::Location,
35};
36use thiserror::Error;
37
38use super::Populated;
39use variadics_please::{all_tuples, all_tuples_enumerated};
40
41pub unsafe trait SystemParam: Sized {
219 type State: Send + Sync + 'static;
221
222 type Item<'world, 'state>: SystemParam<State = Self::State>;
227
228 fn init_state(world: &mut World) -> Self::State;
230
231 fn init_access(
233 state: &Self::State,
234 system_meta: &mut SystemMeta,
235 component_access_set: &mut FilteredAccessSet,
236 world: &mut World,
237 );
238
239 #[inline]
244 #[expect(
245 unused_variables,
246 reason = "The parameters here are intentionally unused by the default implementation; however, putting underscores here will result in the underscores being copied by rust-analyzer's tab completion."
247 )]
248 fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) {}
249
250 #[inline]
252 #[expect(
253 unused_variables,
254 reason = "The parameters here are intentionally unused by the default implementation; however, putting underscores here will result in the underscores being copied by rust-analyzer's tab completion."
255 )]
256 fn queue(state: &mut Self::State, system_meta: &SystemMeta, world: DeferredWorld) {}
257
258 #[expect(
292 unused_variables,
293 reason = "The parameters here are intentionally unused by the default implementation; however, putting underscores here will result in the underscores being copied by rust-analyzer's tab completion."
294 )]
295 unsafe fn validate_param(
296 state: &mut Self::State,
297 system_meta: &SystemMeta,
298 world: UnsafeWorldCell,
299 ) -> Result<(), SystemParamValidationError> {
300 Ok(())
301 }
302
303 unsafe fn get_param<'world, 'state>(
311 state: &'state mut Self::State,
312 system_meta: &SystemMeta,
313 world: UnsafeWorldCell<'world>,
314 change_tick: Tick,
315 ) -> Self::Item<'world, 'state>;
316}
317
318pub unsafe trait ReadOnlySystemParam: SystemParam {}
323
324pub type SystemParamItem<'w, 's, P> = <P as SystemParam>::Item<'w, 's>;
326
327unsafe impl<'w, 's, D: ReadOnlyQueryData + 'static, F: QueryFilter + 'static> ReadOnlySystemParam
329 for Query<'w, 's, D, F>
330{
331}
332
333unsafe impl<D: QueryData + 'static, F: QueryFilter + 'static> SystemParam for Query<'_, '_, D, F> {
336 type State = QueryState<D, F>;
337 type Item<'w, 's> = Query<'w, 's, D, F>;
338
339 fn init_state(world: &mut World) -> Self::State {
340 QueryState::new(world)
341 }
342
343 fn init_access(
344 state: &Self::State,
345 system_meta: &mut SystemMeta,
346 component_access_set: &mut FilteredAccessSet,
347 world: &mut World,
348 ) {
349 assert_component_access_compatibility(
350 &system_meta.name,
351 DebugName::type_name::<D>(),
352 DebugName::type_name::<F>(),
353 component_access_set,
354 &state.component_access,
355 world,
356 );
357 component_access_set.add(state.component_access.clone());
358 }
359
360 #[inline]
361 unsafe fn get_param<'w, 's>(
362 state: &'s mut Self::State,
363 system_meta: &SystemMeta,
364 world: UnsafeWorldCell<'w>,
365 change_tick: Tick,
366 ) -> Self::Item<'w, 's> {
367 unsafe { state.query_unchecked_with_ticks(world, system_meta.last_run, change_tick) }
372 }
373}
374
375fn assert_component_access_compatibility(
376 system_name: &DebugName,
377 query_type: DebugName,
378 filter_type: DebugName,
379 system_access: &FilteredAccessSet,
380 current: &FilteredAccess,
381 world: &World,
382) {
383 let conflicts = system_access.get_conflicts_single(current);
384 if conflicts.is_empty() {
385 return;
386 }
387 let mut accesses = conflicts.format_conflict_list(world);
388 if !accesses.is_empty() {
390 accesses.push(' ');
391 }
392 panic!("error[B0001]: Query<{}, {}> in system {system_name} accesses component(s) {accesses}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://bevy.org/learn/errors/b0001", query_type.shortname(), filter_type.shortname());
393}
394
395unsafe impl<'a, 'b, D: QueryData + 'static, F: QueryFilter + 'static> SystemParam
398 for Single<'a, 'b, D, F>
399{
400 type State = QueryState<D, F>;
401 type Item<'w, 's> = Single<'w, 's, D, F>;
402
403 fn init_state(world: &mut World) -> Self::State {
404 Query::init_state(world)
405 }
406
407 fn init_access(
408 state: &Self::State,
409 system_meta: &mut SystemMeta,
410 component_access_set: &mut FilteredAccessSet,
411 world: &mut World,
412 ) {
413 Query::init_access(state, system_meta, component_access_set, world);
414 }
415
416 #[inline]
417 unsafe fn get_param<'w, 's>(
418 state: &'s mut Self::State,
419 system_meta: &SystemMeta,
420 world: UnsafeWorldCell<'w>,
421 change_tick: Tick,
422 ) -> Self::Item<'w, 's> {
423 let query =
426 unsafe { state.query_unchecked_with_ticks(world, system_meta.last_run, change_tick) };
427 let single = query
428 .single_inner()
429 .expect("The query was expected to contain exactly one matching entity.");
430 Single {
431 item: single,
432 _filter: PhantomData,
433 }
434 }
435
436 #[inline]
437 unsafe fn validate_param(
438 state: &mut Self::State,
439 system_meta: &SystemMeta,
440 world: UnsafeWorldCell,
441 ) -> Result<(), SystemParamValidationError> {
442 let query = unsafe {
446 state.query_unchecked_with_ticks(world, system_meta.last_run, world.change_tick())
447 };
448 match query.single_inner() {
449 Ok(_) => Ok(()),
450 Err(QuerySingleError::NoEntities(_)) => Err(
451 SystemParamValidationError::skipped::<Self>("No matching entities"),
452 ),
453 Err(QuerySingleError::MultipleEntities(_)) => Err(
454 SystemParamValidationError::skipped::<Self>("Multiple matching entities"),
455 ),
456 }
457 }
458}
459
460unsafe impl<'a, 'b, D: ReadOnlyQueryData + 'static, F: QueryFilter + 'static> ReadOnlySystemParam
462 for Single<'a, 'b, D, F>
463{
464}
465
466unsafe impl<D: QueryData + 'static, F: QueryFilter + 'static> SystemParam
469 for Populated<'_, '_, D, F>
470{
471 type State = QueryState<D, F>;
472 type Item<'w, 's> = Populated<'w, 's, D, F>;
473
474 fn init_state(world: &mut World) -> Self::State {
475 Query::init_state(world)
476 }
477
478 fn init_access(
479 state: &Self::State,
480 system_meta: &mut SystemMeta,
481 component_access_set: &mut FilteredAccessSet,
482 world: &mut World,
483 ) {
484 Query::init_access(state, system_meta, component_access_set, world);
485 }
486
487 #[inline]
488 unsafe fn get_param<'w, 's>(
489 state: &'s mut Self::State,
490 system_meta: &SystemMeta,
491 world: UnsafeWorldCell<'w>,
492 change_tick: Tick,
493 ) -> Self::Item<'w, 's> {
494 let query = unsafe { Query::get_param(state, system_meta, world, change_tick) };
496 Populated(query)
497 }
498
499 #[inline]
500 unsafe fn validate_param(
501 state: &mut Self::State,
502 system_meta: &SystemMeta,
503 world: UnsafeWorldCell,
504 ) -> Result<(), SystemParamValidationError> {
505 let query = unsafe {
509 state.query_unchecked_with_ticks(world, system_meta.last_run, world.change_tick())
510 };
511 if query.is_empty() {
512 Err(SystemParamValidationError::skipped::<Self>(
513 "No matching entities",
514 ))
515 } else {
516 Ok(())
517 }
518 }
519}
520
521unsafe impl<'w, 's, D: ReadOnlyQueryData + 'static, F: QueryFilter + 'static> ReadOnlySystemParam
523 for Populated<'w, 's, D, F>
524{
525}
526
527pub struct ParamSet<'w, 's, T: SystemParam> {
641 param_states: &'s mut T::State,
642 world: UnsafeWorldCell<'w>,
643 system_meta: SystemMeta,
644 change_tick: Tick,
645}
646
647macro_rules! impl_param_set {
648 ($(($index: tt, $param: ident, $fn_name: ident)),*) => {
649 unsafe impl<'w, 's, $($param,)*> ReadOnlySystemParam for ParamSet<'w, 's, ($($param,)*)>
651 where $($param: ReadOnlySystemParam,)*
652 { }
653
654 unsafe impl<'_w, '_s, $($param: SystemParam,)*> SystemParam for ParamSet<'_w, '_s, ($($param,)*)>
657 {
658 type State = ($($param::State,)*);
659 type Item<'w, 's> = ParamSet<'w, 's, ($($param,)*)>;
660
661 #[expect(
662 clippy::allow_attributes,
663 reason = "This is inside a macro meant for tuples; as such, `non_snake_case` won't always lint."
664 )]
665 #[allow(
666 non_snake_case,
667 reason = "Certain variable names are provided by the caller, not by us."
668 )]
669 fn init_state(world: &mut World) -> Self::State {
670 ($($param::init_state(world),)*)
671 }
672
673 #[expect(
674 clippy::allow_attributes,
675 reason = "This is inside a macro meant for tuples; as such, `non_snake_case` won't always lint."
676 )]
677 #[allow(
678 non_snake_case,
679 reason = "Certain variable names are provided by the caller, not by us."
680 )]
681 fn init_access(state: &Self::State, system_meta: &mut SystemMeta, component_access_set: &mut FilteredAccessSet, world: &mut World) {
682 let ($($param,)*) = state;
683 $(
684 let component_access_set_clone = &mut component_access_set.clone();
686 $param::init_access($param, system_meta, component_access_set_clone, world);
687 )*
688 $(
689 let mut access_set = FilteredAccessSet::new();
692 $param::init_access($param, system_meta, &mut access_set, world);
693 component_access_set.extend(access_set);
694 )*
695 }
696
697 fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) {
698 <($($param,)*) as SystemParam>::apply(state, system_meta, world);
699 }
700
701 fn queue(state: &mut Self::State, system_meta: &SystemMeta, mut world: DeferredWorld) {
702 <($($param,)*) as SystemParam>::queue(state, system_meta, world.reborrow());
703 }
704
705 #[inline]
706 unsafe fn validate_param<'w, 's>(
707 state: &'s mut Self::State,
708 system_meta: &SystemMeta,
709 world: UnsafeWorldCell<'w>,
710 ) -> Result<(), SystemParamValidationError> {
711 <($($param,)*) as SystemParam>::validate_param(state, system_meta, world)
712 }
713
714 #[inline]
715 unsafe fn get_param<'w, 's>(
716 state: &'s mut Self::State,
717 system_meta: &SystemMeta,
718 world: UnsafeWorldCell<'w>,
719 change_tick: Tick,
720 ) -> Self::Item<'w, 's> {
721 ParamSet {
722 param_states: state,
723 system_meta: system_meta.clone(),
724 world,
725 change_tick,
726 }
727 }
728 }
729
730 impl<'w, 's, $($param: SystemParam,)*> ParamSet<'w, 's, ($($param,)*)>
731 {
732 $(
733 #[doc = stringify!($index)]
735 pub fn $fn_name<'a>(&'a mut self) -> SystemParamItem<'a, 'a, $param> {
738 unsafe {
742 $param::get_param(&mut self.param_states.$index, &self.system_meta, self.world, self.change_tick)
743 }
744 }
745 )*
746 }
747 }
748}
749
750all_tuples_enumerated!(impl_param_set, 1, 8, P, p);
751
752unsafe impl<'a, T: Resource> ReadOnlySystemParam for Res<'a, T> {}
754
755unsafe impl<'a, T: Resource> SystemParam for Res<'a, T> {
758 type State = ComponentId;
759 type Item<'w, 's> = Res<'w, T>;
760
761 fn init_state(world: &mut World) -> Self::State {
762 world.components_registrator().register_resource::<T>()
763 }
764
765 fn init_access(
766 &component_id: &Self::State,
767 system_meta: &mut SystemMeta,
768 component_access_set: &mut FilteredAccessSet,
769 _world: &mut World,
770 ) {
771 let combined_access = component_access_set.combined_access();
772 assert!(
773 !combined_access.has_resource_write(component_id),
774 "error[B0002]: Res<{}> in system {} conflicts with a previous ResMut<{0}> access. Consider removing the duplicate access. See: https://bevy.org/learn/errors/b0002",
775 DebugName::type_name::<T>(),
776 system_meta.name,
777 );
778
779 component_access_set.add_unfiltered_resource_read(component_id);
780 }
781
782 #[inline]
783 unsafe fn validate_param(
784 &mut component_id: &mut Self::State,
785 _system_meta: &SystemMeta,
786 world: UnsafeWorldCell,
787 ) -> Result<(), SystemParamValidationError> {
788 if unsafe { world.storages() }
790 .resources
791 .get(component_id)
792 .is_some_and(ResourceData::is_present)
793 {
794 Ok(())
795 } else {
796 Err(SystemParamValidationError::invalid::<Self>(
797 "Resource does not exist",
798 ))
799 }
800 }
801
802 #[inline]
803 unsafe fn get_param<'w, 's>(
804 &mut component_id: &'s mut Self::State,
805 system_meta: &SystemMeta,
806 world: UnsafeWorldCell<'w>,
807 change_tick: Tick,
808 ) -> Self::Item<'w, 's> {
809 let (ptr, ticks, caller) =
810 world
811 .get_resource_with_ticks(component_id)
812 .unwrap_or_else(|| {
813 panic!(
814 "Resource requested by {} does not exist: {}",
815 system_meta.name,
816 DebugName::type_name::<T>()
817 );
818 });
819 Res {
820 value: ptr.deref(),
821 ticks: Ticks {
822 added: ticks.added.deref(),
823 changed: ticks.changed.deref(),
824 last_run: system_meta.last_run,
825 this_run: change_tick,
826 },
827 changed_by: caller.map(|caller| caller.deref()),
828 }
829 }
830}
831
832unsafe impl<'a, T: Resource> SystemParam for ResMut<'a, T> {
835 type State = ComponentId;
836 type Item<'w, 's> = ResMut<'w, T>;
837
838 fn init_state(world: &mut World) -> Self::State {
839 world.components_registrator().register_resource::<T>()
840 }
841
842 fn init_access(
843 &component_id: &Self::State,
844 system_meta: &mut SystemMeta,
845 component_access_set: &mut FilteredAccessSet,
846 _world: &mut World,
847 ) {
848 let combined_access = component_access_set.combined_access();
849 if combined_access.has_resource_write(component_id) {
850 panic!(
851 "error[B0002]: ResMut<{}> in system {} conflicts with a previous ResMut<{0}> access. Consider removing the duplicate access. See: https://bevy.org/learn/errors/b0002",
852 DebugName::type_name::<T>(), system_meta.name);
853 } else if combined_access.has_resource_read(component_id) {
854 panic!(
855 "error[B0002]: ResMut<{}> in system {} conflicts with a previous Res<{0}> access. Consider removing the duplicate access. See: https://bevy.org/learn/errors/b0002",
856 DebugName::type_name::<T>(), system_meta.name);
857 }
858 component_access_set.add_unfiltered_resource_write(component_id);
859 }
860
861 #[inline]
862 unsafe fn validate_param(
863 &mut component_id: &mut Self::State,
864 _system_meta: &SystemMeta,
865 world: UnsafeWorldCell,
866 ) -> Result<(), SystemParamValidationError> {
867 if unsafe { world.storages() }
869 .resources
870 .get(component_id)
871 .is_some_and(ResourceData::is_present)
872 {
873 Ok(())
874 } else {
875 Err(SystemParamValidationError::invalid::<Self>(
876 "Resource does not exist",
877 ))
878 }
879 }
880
881 #[inline]
882 unsafe fn get_param<'w, 's>(
883 &mut component_id: &'s mut Self::State,
884 system_meta: &SystemMeta,
885 world: UnsafeWorldCell<'w>,
886 change_tick: Tick,
887 ) -> Self::Item<'w, 's> {
888 let value = world
889 .get_resource_mut_by_id(component_id)
890 .unwrap_or_else(|| {
891 panic!(
892 "Resource requested by {} does not exist: {}",
893 system_meta.name,
894 DebugName::type_name::<T>()
895 );
896 });
897 ResMut {
898 value: value.value.deref_mut::<T>(),
899 ticks: TicksMut {
900 added: value.ticks.added,
901 changed: value.ticks.changed,
902 last_run: system_meta.last_run,
903 this_run: change_tick,
904 },
905 changed_by: value.changed_by,
906 }
907 }
908}
909
910unsafe impl<'w> ReadOnlySystemParam for &'w World {}
912
913unsafe impl SystemParam for &'_ World {
915 type State = ();
916 type Item<'w, 's> = &'w World;
917
918 fn init_state(_world: &mut World) -> Self::State {}
919
920 fn init_access(
921 _state: &Self::State,
922 _system_meta: &mut SystemMeta,
923 component_access_set: &mut FilteredAccessSet,
924 _world: &mut World,
925 ) {
926 let mut filtered_access = FilteredAccess::default();
927
928 filtered_access.read_all();
929 if !component_access_set
930 .get_conflicts_single(&filtered_access)
931 .is_empty()
932 {
933 panic!("&World conflicts with a previous mutable system parameter. Allowing this would break Rust's mutability rules");
934 }
935 component_access_set.add(filtered_access);
936 }
937
938 #[inline]
939 unsafe fn get_param<'w, 's>(
940 _state: &'s mut Self::State,
941 _system_meta: &SystemMeta,
942 world: UnsafeWorldCell<'w>,
943 _change_tick: Tick,
944 ) -> Self::Item<'w, 's> {
945 unsafe { world.world() }
947 }
948}
949
950unsafe impl<'w> SystemParam for DeferredWorld<'w> {
952 type State = ();
953 type Item<'world, 'state> = DeferredWorld<'world>;
954
955 fn init_state(_world: &mut World) -> Self::State {}
956
957 fn init_access(
958 _state: &Self::State,
959 system_meta: &mut SystemMeta,
960 component_access_set: &mut FilteredAccessSet,
961 _world: &mut World,
962 ) {
963 assert!(
964 !component_access_set.combined_access().has_any_read(),
965 "DeferredWorld in system {} conflicts with a previous access.",
966 system_meta.name,
967 );
968 component_access_set.write_all();
969 }
970
971 unsafe fn get_param<'world, 'state>(
972 _state: &'state mut Self::State,
973 _system_meta: &SystemMeta,
974 world: UnsafeWorldCell<'world>,
975 _change_tick: Tick,
976 ) -> Self::Item<'world, 'state> {
977 world.into_deferred()
978 }
979}
980
981#[derive(Debug)]
1048pub struct Local<'s, T: FromWorld + Send + 'static>(pub(crate) &'s mut T);
1049
1050unsafe impl<'s, T: FromWorld + Send + 'static> ReadOnlySystemParam for Local<'s, T> {}
1052
1053impl<'s, T: FromWorld + Send + 'static> Deref for Local<'s, T> {
1054 type Target = T;
1055
1056 #[inline]
1057 fn deref(&self) -> &Self::Target {
1058 self.0
1059 }
1060}
1061
1062impl<'s, T: FromWorld + Send + 'static> DerefMut for Local<'s, T> {
1063 #[inline]
1064 fn deref_mut(&mut self) -> &mut Self::Target {
1065 self.0
1066 }
1067}
1068
1069impl<'s, 'a, T: FromWorld + Send + 'static> IntoIterator for &'a Local<'s, T>
1070where
1071 &'a T: IntoIterator,
1072{
1073 type Item = <&'a T as IntoIterator>::Item;
1074 type IntoIter = <&'a T as IntoIterator>::IntoIter;
1075
1076 fn into_iter(self) -> Self::IntoIter {
1077 self.0.into_iter()
1078 }
1079}
1080
1081impl<'s, 'a, T: FromWorld + Send + 'static> IntoIterator for &'a mut Local<'s, T>
1082where
1083 &'a mut T: IntoIterator,
1084{
1085 type Item = <&'a mut T as IntoIterator>::Item;
1086 type IntoIter = <&'a mut T as IntoIterator>::IntoIter;
1087
1088 fn into_iter(self) -> Self::IntoIter {
1089 self.0.into_iter()
1090 }
1091}
1092
1093unsafe impl<'a, T: FromWorld + Send + 'static> SystemParam for Local<'a, T> {
1095 type State = SyncCell<T>;
1096 type Item<'w, 's> = Local<'s, T>;
1097
1098 fn init_state(world: &mut World) -> Self::State {
1099 SyncCell::new(T::from_world(world))
1100 }
1101
1102 fn init_access(
1103 _state: &Self::State,
1104 _system_meta: &mut SystemMeta,
1105 _component_access_set: &mut FilteredAccessSet,
1106 _world: &mut World,
1107 ) {
1108 }
1109
1110 #[inline]
1111 unsafe fn get_param<'w, 's>(
1112 state: &'s mut Self::State,
1113 _system_meta: &SystemMeta,
1114 _world: UnsafeWorldCell<'w>,
1115 _change_tick: Tick,
1116 ) -> Self::Item<'w, 's> {
1117 Local(state.get())
1118 }
1119}
1120
1121pub trait SystemBuffer: FromWorld + Send + 'static {
1128 fn apply(&mut self, system_meta: &SystemMeta, world: &mut World);
1130 fn queue(&mut self, _system_meta: &SystemMeta, _world: DeferredWorld) {}
1132}
1133
1134pub struct Deferred<'a, T: SystemBuffer>(pub(crate) &'a mut T);
1254
1255impl<'a, T: SystemBuffer> Deref for Deferred<'a, T> {
1256 type Target = T;
1257 #[inline]
1258 fn deref(&self) -> &Self::Target {
1259 self.0
1260 }
1261}
1262
1263impl<'a, T: SystemBuffer> DerefMut for Deferred<'a, T> {
1264 #[inline]
1265 fn deref_mut(&mut self) -> &mut Self::Target {
1266 self.0
1267 }
1268}
1269
1270impl<T: SystemBuffer> Deferred<'_, T> {
1271 pub fn reborrow(&mut self) -> Deferred<'_, T> {
1274 Deferred(self.0)
1275 }
1276}
1277
1278unsafe impl<T: SystemBuffer> ReadOnlySystemParam for Deferred<'_, T> {}
1280
1281unsafe impl<T: SystemBuffer> SystemParam for Deferred<'_, T> {
1283 type State = SyncCell<T>;
1284 type Item<'w, 's> = Deferred<'s, T>;
1285
1286 fn init_state(world: &mut World) -> Self::State {
1287 SyncCell::new(T::from_world(world))
1288 }
1289
1290 fn init_access(
1291 _state: &Self::State,
1292 system_meta: &mut SystemMeta,
1293 _component_access_set: &mut FilteredAccessSet,
1294 _world: &mut World,
1295 ) {
1296 system_meta.set_has_deferred();
1297 }
1298
1299 fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) {
1300 state.get().apply(system_meta, world);
1301 }
1302
1303 fn queue(state: &mut Self::State, system_meta: &SystemMeta, world: DeferredWorld) {
1304 state.get().queue(system_meta, world);
1305 }
1306
1307 #[inline]
1308 unsafe fn get_param<'w, 's>(
1309 state: &'s mut Self::State,
1310 _system_meta: &SystemMeta,
1311 _world: UnsafeWorldCell<'w>,
1312 _change_tick: Tick,
1313 ) -> Self::Item<'w, 's> {
1314 Deferred(state.get())
1315 }
1316}
1317
1318pub struct NonSendMarker(PhantomData<*mut ()>);
1320
1321unsafe impl SystemParam for NonSendMarker {
1323 type State = ();
1324 type Item<'w, 's> = Self;
1325
1326 #[inline]
1327 fn init_state(_world: &mut World) -> Self::State {}
1328
1329 fn init_access(
1330 _state: &Self::State,
1331 system_meta: &mut SystemMeta,
1332 _component_access_set: &mut FilteredAccessSet,
1333 _world: &mut World,
1334 ) {
1335 system_meta.set_non_send();
1336 }
1337
1338 #[inline]
1339 unsafe fn get_param<'world, 'state>(
1340 _state: &'state mut Self::State,
1341 _system_meta: &SystemMeta,
1342 _world: UnsafeWorldCell<'world>,
1343 _change_tick: Tick,
1344 ) -> Self::Item<'world, 'state> {
1345 Self(PhantomData)
1346 }
1347}
1348
1349unsafe impl ReadOnlySystemParam for NonSendMarker {}
1351
1352pub struct NonSend<'w, T: 'static> {
1364 pub(crate) value: &'w T,
1365 ticks: ComponentTicks,
1366 last_run: Tick,
1367 this_run: Tick,
1368 changed_by: MaybeLocation<&'w &'static Location<'static>>,
1369}
1370
1371unsafe impl<'w, T> ReadOnlySystemParam for NonSend<'w, T> {}
1373
1374impl<'w, T> Debug for NonSend<'w, T>
1375where
1376 T: Debug,
1377{
1378 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1379 f.debug_tuple("NonSend").field(&self.value).finish()
1380 }
1381}
1382
1383impl<'w, T: 'static> NonSend<'w, T> {
1384 pub fn is_added(&self) -> bool {
1386 self.ticks.is_added(self.last_run, self.this_run)
1387 }
1388
1389 pub fn is_changed(&self) -> bool {
1391 self.ticks.is_changed(self.last_run, self.this_run)
1392 }
1393
1394 pub fn changed_by(&self) -> MaybeLocation {
1396 self.changed_by.copied()
1397 }
1398}
1399
1400impl<'w, T> Deref for NonSend<'w, T> {
1401 type Target = T;
1402
1403 fn deref(&self) -> &Self::Target {
1404 self.value
1405 }
1406}
1407
1408impl<'a, T> From<NonSendMut<'a, T>> for NonSend<'a, T> {
1409 fn from(nsm: NonSendMut<'a, T>) -> Self {
1410 Self {
1411 value: nsm.value,
1412 ticks: ComponentTicks {
1413 added: nsm.ticks.added.to_owned(),
1414 changed: nsm.ticks.changed.to_owned(),
1415 },
1416 this_run: nsm.ticks.this_run,
1417 last_run: nsm.ticks.last_run,
1418 changed_by: nsm.changed_by.map(|changed_by| &*changed_by),
1419 }
1420 }
1421}
1422
1423unsafe impl<'a, T: 'static> SystemParam for NonSend<'a, T> {
1426 type State = ComponentId;
1427 type Item<'w, 's> = NonSend<'w, T>;
1428
1429 fn init_state(world: &mut World) -> Self::State {
1430 world.components_registrator().register_non_send::<T>()
1431 }
1432
1433 fn init_access(
1434 &component_id: &Self::State,
1435 system_meta: &mut SystemMeta,
1436 component_access_set: &mut FilteredAccessSet,
1437 _world: &mut World,
1438 ) {
1439 system_meta.set_non_send();
1440
1441 let combined_access = component_access_set.combined_access();
1442 assert!(
1443 !combined_access.has_resource_write(component_id),
1444 "error[B0002]: NonSend<{}> in system {} conflicts with a previous mutable resource access ({0}). Consider removing the duplicate access. See: https://bevy.org/learn/errors/b0002",
1445 DebugName::type_name::<T>(),
1446 system_meta.name,
1447 );
1448 component_access_set.add_unfiltered_resource_read(component_id);
1449 }
1450
1451 #[inline]
1452 unsafe fn validate_param(
1453 &mut component_id: &mut Self::State,
1454 _system_meta: &SystemMeta,
1455 world: UnsafeWorldCell,
1456 ) -> Result<(), SystemParamValidationError> {
1457 if unsafe { world.storages() }
1459 .non_send_resources
1460 .get(component_id)
1461 .is_some_and(ResourceData::is_present)
1462 {
1463 Ok(())
1464 } else {
1465 Err(SystemParamValidationError::invalid::<Self>(
1466 "Non-send resource does not exist",
1467 ))
1468 }
1469 }
1470
1471 #[inline]
1472 unsafe fn get_param<'w, 's>(
1473 &mut component_id: &'s mut Self::State,
1474 system_meta: &SystemMeta,
1475 world: UnsafeWorldCell<'w>,
1476 change_tick: Tick,
1477 ) -> Self::Item<'w, 's> {
1478 let (ptr, ticks, caller) =
1479 world
1480 .get_non_send_with_ticks(component_id)
1481 .unwrap_or_else(|| {
1482 panic!(
1483 "Non-send resource requested by {} does not exist: {}",
1484 system_meta.name,
1485 DebugName::type_name::<T>()
1486 )
1487 });
1488
1489 NonSend {
1490 value: ptr.deref(),
1491 ticks: ticks.read(),
1492 last_run: system_meta.last_run,
1493 this_run: change_tick,
1494 changed_by: caller.map(|caller| caller.deref()),
1495 }
1496 }
1497}
1498
1499unsafe impl<'a, T: 'static> SystemParam for NonSendMut<'a, T> {
1502 type State = ComponentId;
1503 type Item<'w, 's> = NonSendMut<'w, T>;
1504
1505 fn init_state(world: &mut World) -> Self::State {
1506 world.components_registrator().register_non_send::<T>()
1507 }
1508
1509 fn init_access(
1510 &component_id: &Self::State,
1511 system_meta: &mut SystemMeta,
1512 component_access_set: &mut FilteredAccessSet,
1513 _world: &mut World,
1514 ) {
1515 system_meta.set_non_send();
1516
1517 let combined_access = component_access_set.combined_access();
1518 if combined_access.has_resource_write(component_id) {
1519 panic!(
1520 "error[B0002]: NonSendMut<{}> in system {} conflicts with a previous mutable resource access ({0}). Consider removing the duplicate access. See: https://bevy.org/learn/errors/b0002",
1521 DebugName::type_name::<T>(), system_meta.name);
1522 } else if combined_access.has_resource_read(component_id) {
1523 panic!(
1524 "error[B0002]: NonSendMut<{}> in system {} conflicts with a previous immutable resource access ({0}). Consider removing the duplicate access. See: https://bevy.org/learn/errors/b0002",
1525 DebugName::type_name::<T>(), system_meta.name);
1526 }
1527 component_access_set.add_unfiltered_resource_write(component_id);
1528 }
1529
1530 #[inline]
1531 unsafe fn validate_param(
1532 &mut component_id: &mut Self::State,
1533 _system_meta: &SystemMeta,
1534 world: UnsafeWorldCell,
1535 ) -> Result<(), SystemParamValidationError> {
1536 if unsafe { world.storages() }
1538 .non_send_resources
1539 .get(component_id)
1540 .is_some_and(ResourceData::is_present)
1541 {
1542 Ok(())
1543 } else {
1544 Err(SystemParamValidationError::invalid::<Self>(
1545 "Non-send resource does not exist",
1546 ))
1547 }
1548 }
1549
1550 #[inline]
1551 unsafe fn get_param<'w, 's>(
1552 &mut component_id: &'s mut Self::State,
1553 system_meta: &SystemMeta,
1554 world: UnsafeWorldCell<'w>,
1555 change_tick: Tick,
1556 ) -> Self::Item<'w, 's> {
1557 let (ptr, ticks, caller) =
1558 world
1559 .get_non_send_with_ticks(component_id)
1560 .unwrap_or_else(|| {
1561 panic!(
1562 "Non-send resource requested by {} does not exist: {}",
1563 system_meta.name,
1564 DebugName::type_name::<T>()
1565 );
1566 });
1567 NonSendMut {
1568 value: ptr.assert_unique().deref_mut(),
1569 ticks: TicksMut::from_tick_cells(ticks, system_meta.last_run, change_tick),
1570 changed_by: caller.map(|caller| caller.deref_mut()),
1571 }
1572 }
1573}
1574
1575unsafe impl<'a> ReadOnlySystemParam for &'a Archetypes {}
1577
1578unsafe impl<'a> SystemParam for &'a Archetypes {
1580 type State = ();
1581 type Item<'w, 's> = &'w Archetypes;
1582
1583 fn init_state(_world: &mut World) -> Self::State {}
1584
1585 fn init_access(
1586 _state: &Self::State,
1587 _system_meta: &mut SystemMeta,
1588 _component_access_set: &mut FilteredAccessSet,
1589 _world: &mut World,
1590 ) {
1591 }
1592
1593 #[inline]
1594 unsafe fn get_param<'w, 's>(
1595 _state: &'s mut Self::State,
1596 _system_meta: &SystemMeta,
1597 world: UnsafeWorldCell<'w>,
1598 _change_tick: Tick,
1599 ) -> Self::Item<'w, 's> {
1600 world.archetypes()
1601 }
1602}
1603
1604unsafe impl<'a> ReadOnlySystemParam for &'a Components {}
1606
1607unsafe impl<'a> SystemParam for &'a Components {
1609 type State = ();
1610 type Item<'w, 's> = &'w Components;
1611
1612 fn init_state(_world: &mut World) -> Self::State {}
1613
1614 fn init_access(
1615 _state: &Self::State,
1616 _system_meta: &mut SystemMeta,
1617 _component_access_set: &mut FilteredAccessSet,
1618 _world: &mut World,
1619 ) {
1620 }
1621
1622 #[inline]
1623 unsafe fn get_param<'w, 's>(
1624 _state: &'s mut Self::State,
1625 _system_meta: &SystemMeta,
1626 world: UnsafeWorldCell<'w>,
1627 _change_tick: Tick,
1628 ) -> Self::Item<'w, 's> {
1629 world.components()
1630 }
1631}
1632
1633unsafe impl<'a> ReadOnlySystemParam for &'a Entities {}
1635
1636unsafe impl<'a> SystemParam for &'a Entities {
1638 type State = ();
1639 type Item<'w, 's> = &'w Entities;
1640
1641 fn init_state(_world: &mut World) -> Self::State {}
1642
1643 fn init_access(
1644 _state: &Self::State,
1645 _system_meta: &mut SystemMeta,
1646 _component_access_set: &mut FilteredAccessSet,
1647 _world: &mut World,
1648 ) {
1649 }
1650
1651 #[inline]
1652 unsafe fn get_param<'w, 's>(
1653 _state: &'s mut Self::State,
1654 _system_meta: &SystemMeta,
1655 world: UnsafeWorldCell<'w>,
1656 _change_tick: Tick,
1657 ) -> Self::Item<'w, 's> {
1658 world.entities()
1659 }
1660}
1661
1662unsafe impl<'a> ReadOnlySystemParam for &'a Bundles {}
1664
1665unsafe impl<'a> SystemParam for &'a Bundles {
1667 type State = ();
1668 type Item<'w, 's> = &'w Bundles;
1669
1670 fn init_state(_world: &mut World) -> Self::State {}
1671
1672 fn init_access(
1673 _state: &Self::State,
1674 _system_meta: &mut SystemMeta,
1675 _component_access_set: &mut FilteredAccessSet,
1676 _world: &mut World,
1677 ) {
1678 }
1679
1680 #[inline]
1681 unsafe fn get_param<'w, 's>(
1682 _state: &'s mut Self::State,
1683 _system_meta: &SystemMeta,
1684 world: UnsafeWorldCell<'w>,
1685 _change_tick: Tick,
1686 ) -> Self::Item<'w, 's> {
1687 world.bundles()
1688 }
1689}
1690
1691#[derive(Debug, Clone, Copy)]
1701pub struct SystemChangeTick {
1702 last_run: Tick,
1703 this_run: Tick,
1704}
1705
1706impl SystemChangeTick {
1707 #[inline]
1709 pub fn this_run(&self) -> Tick {
1710 self.this_run
1711 }
1712
1713 #[inline]
1715 pub fn last_run(&self) -> Tick {
1716 self.last_run
1717 }
1718}
1719
1720unsafe impl ReadOnlySystemParam for SystemChangeTick {}
1722
1723unsafe impl SystemParam for SystemChangeTick {
1725 type State = ();
1726 type Item<'w, 's> = SystemChangeTick;
1727
1728 fn init_state(_world: &mut World) -> Self::State {}
1729
1730 fn init_access(
1731 _state: &Self::State,
1732 _system_meta: &mut SystemMeta,
1733 _component_access_set: &mut FilteredAccessSet,
1734 _world: &mut World,
1735 ) {
1736 }
1737
1738 #[inline]
1739 unsafe fn get_param<'w, 's>(
1740 _state: &'s mut Self::State,
1741 system_meta: &SystemMeta,
1742 _world: UnsafeWorldCell<'w>,
1743 change_tick: Tick,
1744 ) -> Self::Item<'w, 's> {
1745 SystemChangeTick {
1746 last_run: system_meta.last_run,
1747 this_run: change_tick,
1748 }
1749 }
1750}
1751
1752unsafe impl<T: SystemParam> SystemParam for Option<T> {
1754 type State = T::State;
1755
1756 type Item<'world, 'state> = Option<T::Item<'world, 'state>>;
1757
1758 fn init_state(world: &mut World) -> Self::State {
1759 T::init_state(world)
1760 }
1761
1762 fn init_access(
1763 state: &Self::State,
1764 system_meta: &mut SystemMeta,
1765 component_access_set: &mut FilteredAccessSet,
1766 world: &mut World,
1767 ) {
1768 T::init_access(state, system_meta, component_access_set, world);
1769 }
1770
1771 #[inline]
1772 unsafe fn get_param<'world, 'state>(
1773 state: &'state mut Self::State,
1774 system_meta: &SystemMeta,
1775 world: UnsafeWorldCell<'world>,
1776 change_tick: Tick,
1777 ) -> Self::Item<'world, 'state> {
1778 T::validate_param(state, system_meta, world)
1779 .ok()
1780 .map(|()| T::get_param(state, system_meta, world, change_tick))
1781 }
1782
1783 fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) {
1784 T::apply(state, system_meta, world);
1785 }
1786
1787 fn queue(state: &mut Self::State, system_meta: &SystemMeta, world: DeferredWorld) {
1788 T::queue(state, system_meta, world);
1789 }
1790}
1791
1792unsafe impl<T: ReadOnlySystemParam> ReadOnlySystemParam for Option<T> {}
1794
1795unsafe impl<T: SystemParam> SystemParam for Result<T, SystemParamValidationError> {
1797 type State = T::State;
1798
1799 type Item<'world, 'state> = Result<T::Item<'world, 'state>, SystemParamValidationError>;
1800
1801 fn init_state(world: &mut World) -> Self::State {
1802 T::init_state(world)
1803 }
1804
1805 fn init_access(
1806 state: &Self::State,
1807 system_meta: &mut SystemMeta,
1808 component_access_set: &mut FilteredAccessSet,
1809 world: &mut World,
1810 ) {
1811 T::init_access(state, system_meta, component_access_set, world);
1812 }
1813
1814 #[inline]
1815 unsafe fn get_param<'world, 'state>(
1816 state: &'state mut Self::State,
1817 system_meta: &SystemMeta,
1818 world: UnsafeWorldCell<'world>,
1819 change_tick: Tick,
1820 ) -> Self::Item<'world, 'state> {
1821 T::validate_param(state, system_meta, world)
1822 .map(|()| T::get_param(state, system_meta, world, change_tick))
1823 }
1824
1825 fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) {
1826 T::apply(state, system_meta, world);
1827 }
1828
1829 fn queue(state: &mut Self::State, system_meta: &SystemMeta, world: DeferredWorld) {
1830 T::queue(state, system_meta, world);
1831 }
1832}
1833
1834unsafe impl<T: ReadOnlySystemParam> ReadOnlySystemParam for Result<T, SystemParamValidationError> {}
1836
1837#[derive(Debug)]
1856pub struct If<T>(pub T);
1857
1858impl<T> If<T> {
1859 pub fn into_inner(self) -> T {
1873 self.0
1874 }
1875}
1876
1877impl<T> Deref for If<T> {
1878 type Target = T;
1879 fn deref(&self) -> &Self::Target {
1880 &self.0
1881 }
1882}
1883
1884impl<T> DerefMut for If<T> {
1885 fn deref_mut(&mut self) -> &mut Self::Target {
1886 &mut self.0
1887 }
1888}
1889
1890unsafe impl<T: SystemParam> SystemParam for If<T> {
1892 type State = T::State;
1893
1894 type Item<'world, 'state> = If<T::Item<'world, 'state>>;
1895
1896 fn init_state(world: &mut World) -> Self::State {
1897 T::init_state(world)
1898 }
1899
1900 fn init_access(
1901 state: &Self::State,
1902 system_meta: &mut SystemMeta,
1903 component_access_set: &mut FilteredAccessSet,
1904 world: &mut World,
1905 ) {
1906 T::init_access(state, system_meta, component_access_set, world);
1907 }
1908
1909 #[inline]
1910 unsafe fn validate_param(
1911 state: &mut Self::State,
1912 system_meta: &SystemMeta,
1913 world: UnsafeWorldCell,
1914 ) -> Result<(), SystemParamValidationError> {
1915 T::validate_param(state, system_meta, world).map_err(|mut e| {
1916 e.skipped = true;
1917 e
1918 })
1919 }
1920
1921 #[inline]
1922 unsafe fn get_param<'world, 'state>(
1923 state: &'state mut Self::State,
1924 system_meta: &SystemMeta,
1925 world: UnsafeWorldCell<'world>,
1926 change_tick: Tick,
1927 ) -> Self::Item<'world, 'state> {
1928 If(T::get_param(state, system_meta, world, change_tick))
1929 }
1930
1931 fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) {
1932 T::apply(state, system_meta, world);
1933 }
1934
1935 fn queue(state: &mut Self::State, system_meta: &SystemMeta, world: DeferredWorld) {
1936 T::queue(state, system_meta, world);
1937 }
1938}
1939
1940unsafe impl<T: ReadOnlySystemParam> ReadOnlySystemParam for If<T> {}
1942
1943unsafe impl<T: SystemParam> SystemParam for Vec<T> {
1946 type State = Vec<T::State>;
1947
1948 type Item<'world, 'state> = Vec<T::Item<'world, 'state>>;
1949
1950 fn init_state(_world: &mut World) -> Self::State {
1951 Vec::new()
1952 }
1953
1954 fn init_access(
1955 state: &Self::State,
1956 system_meta: &mut SystemMeta,
1957 component_access_set: &mut FilteredAccessSet,
1958 world: &mut World,
1959 ) {
1960 for state in state {
1961 T::init_access(state, system_meta, component_access_set, world);
1962 }
1963 }
1964
1965 #[inline]
1966 unsafe fn validate_param(
1967 state: &mut Self::State,
1968 system_meta: &SystemMeta,
1969 world: UnsafeWorldCell,
1970 ) -> Result<(), SystemParamValidationError> {
1971 for state in state {
1972 T::validate_param(state, system_meta, world)?;
1973 }
1974 Ok(())
1975 }
1976
1977 #[inline]
1978 unsafe fn get_param<'world, 'state>(
1979 state: &'state mut Self::State,
1980 system_meta: &SystemMeta,
1981 world: UnsafeWorldCell<'world>,
1982 change_tick: Tick,
1983 ) -> Self::Item<'world, 'state> {
1984 state
1985 .iter_mut()
1986 .map(|state| unsafe { T::get_param(state, system_meta, world, change_tick) })
1990 .collect()
1991 }
1992
1993 fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) {
1994 for state in state {
1995 T::apply(state, system_meta, world);
1996 }
1997 }
1998
1999 fn queue(state: &mut Self::State, system_meta: &SystemMeta, mut world: DeferredWorld) {
2000 for state in state {
2001 T::queue(state, system_meta, world.reborrow());
2002 }
2003 }
2004}
2005
2006unsafe impl<T: SystemParam> SystemParam for ParamSet<'_, '_, Vec<T>> {
2010 type State = Vec<T::State>;
2011
2012 type Item<'world, 'state> = ParamSet<'world, 'state, Vec<T>>;
2013
2014 fn init_state(_world: &mut World) -> Self::State {
2015 Vec::new()
2016 }
2017
2018 fn init_access(
2019 state: &Self::State,
2020 system_meta: &mut SystemMeta,
2021 component_access_set: &mut FilteredAccessSet,
2022 world: &mut World,
2023 ) {
2024 for state in state {
2025 let component_access_set_clone = &mut component_access_set.clone();
2027 T::init_access(state, system_meta, component_access_set_clone, world);
2028 }
2029 for state in state {
2030 let mut access_set = FilteredAccessSet::new();
2033 T::init_access(state, system_meta, &mut access_set, world);
2034 component_access_set.extend(access_set);
2035 }
2036 }
2037
2038 #[inline]
2039 unsafe fn get_param<'world, 'state>(
2040 state: &'state mut Self::State,
2041 system_meta: &SystemMeta,
2042 world: UnsafeWorldCell<'world>,
2043 change_tick: Tick,
2044 ) -> Self::Item<'world, 'state> {
2045 ParamSet {
2046 param_states: state,
2047 system_meta: system_meta.clone(),
2048 world,
2049 change_tick,
2050 }
2051 }
2052
2053 fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) {
2054 for state in state {
2055 T::apply(state, system_meta, world);
2056 }
2057 }
2058
2059 fn queue(state: &mut Self::State, system_meta: &SystemMeta, mut world: DeferredWorld) {
2060 for state in state {
2061 T::queue(state, system_meta, world.reborrow());
2062 }
2063 }
2064}
2065
2066impl<T: SystemParam> ParamSet<'_, '_, Vec<T>> {
2067 pub fn get_mut(&mut self, index: usize) -> T::Item<'_, '_> {
2070 unsafe {
2075 T::get_param(
2076 &mut self.param_states[index],
2077 &self.system_meta,
2078 self.world,
2079 self.change_tick,
2080 )
2081 }
2082 }
2083
2084 pub fn for_each(&mut self, mut f: impl FnMut(T::Item<'_, '_>)) {
2086 self.param_states.iter_mut().for_each(|state| {
2087 f(
2088 unsafe { T::get_param(state, &self.system_meta, self.world, self.change_tick) },
2093 );
2094 });
2095 }
2096}
2097
2098macro_rules! impl_system_param_tuple {
2099 ($(#[$meta:meta])* $($param: ident),*) => {
2100 $(#[$meta])*
2101 unsafe impl<$($param: ReadOnlySystemParam),*> ReadOnlySystemParam for ($($param,)*) {}
2103
2104 #[expect(
2105 clippy::allow_attributes,
2106 reason = "This is in a macro, and as such, the below lints may not always apply."
2107 )]
2108 #[allow(
2109 non_snake_case,
2110 reason = "Certain variable names are provided by the caller, not by us."
2111 )]
2112 #[allow(
2113 unused_variables,
2114 reason = "Zero-length tuples won't use some of the parameters."
2115 )]
2116 $(#[$meta])*
2117 unsafe impl<$($param: SystemParam),*> SystemParam for ($($param,)*) {
2119 type State = ($($param::State,)*);
2120 type Item<'w, 's> = ($($param::Item::<'w, 's>,)*);
2121
2122 #[inline]
2123 fn init_state(world: &mut World) -> Self::State {
2124 (($($param::init_state(world),)*))
2125 }
2126
2127 fn init_access(state: &Self::State, _system_meta: &mut SystemMeta, _component_access_set: &mut FilteredAccessSet, _world: &mut World) {
2128 let ($($param,)*) = state;
2129 $($param::init_access($param, _system_meta, _component_access_set, _world);)*
2130 }
2131
2132 #[inline]
2133 fn apply(($($param,)*): &mut Self::State, system_meta: &SystemMeta, world: &mut World) {
2134 $($param::apply($param, system_meta, world);)*
2135 }
2136
2137 #[inline]
2138 #[allow(
2139 unused_mut,
2140 reason = "The `world` parameter is unused for zero-length tuples; however, it must be mutable for other lengths of tuples."
2141 )]
2142 fn queue(($($param,)*): &mut Self::State, system_meta: &SystemMeta, mut world: DeferredWorld) {
2143 $($param::queue($param, system_meta, world.reborrow());)*
2144 }
2145
2146 #[inline]
2147 unsafe fn validate_param(
2148 state: &mut Self::State,
2149 system_meta: &SystemMeta,
2150 world: UnsafeWorldCell,
2151 ) -> Result<(), SystemParamValidationError> {
2152 let ($($param,)*) = state;
2153 $(
2154 $param::validate_param($param, system_meta, world)?;
2155 )*
2156 Ok(())
2157 }
2158
2159 #[inline]
2160 unsafe fn get_param<'w, 's>(
2161 state: &'s mut Self::State,
2162 system_meta: &SystemMeta,
2163 world: UnsafeWorldCell<'w>,
2164 change_tick: Tick,
2165 ) -> Self::Item<'w, 's> {
2166 let ($($param,)*) = state;
2167 #[allow(
2168 clippy::unused_unit,
2169 reason = "Zero-length tuples won't have any params to get."
2170 )]
2171 ($($param::get_param($param, system_meta, world, change_tick),)*)
2172 }
2173 }
2174 };
2175}
2176
2177all_tuples!(
2178 #[doc(fake_variadic)]
2179 impl_system_param_tuple,
2180 0,
2181 16,
2182 P
2183);
2184
2185pub mod lifetimeless {
2198 pub type SQuery<D, F = ()> = super::Query<'static, 'static, D, F>;
2200 pub type Read<T> = &'static T;
2202 pub type Write<T> = &'static mut T;
2204 pub type SRes<T> = super::Res<'static, T>;
2206 pub type SResMut<T> = super::ResMut<'static, T>;
2208 pub type SCommands = crate::system::Commands<'static, 'static>;
2210}
2211
2212pub struct StaticSystemParam<'w, 's, P: SystemParam>(SystemParamItem<'w, 's, P>);
2264
2265impl<'w, 's, P: SystemParam> Deref for StaticSystemParam<'w, 's, P> {
2266 type Target = SystemParamItem<'w, 's, P>;
2267
2268 fn deref(&self) -> &Self::Target {
2269 &self.0
2270 }
2271}
2272
2273impl<'w, 's, P: SystemParam> DerefMut for StaticSystemParam<'w, 's, P> {
2274 fn deref_mut(&mut self) -> &mut Self::Target {
2275 &mut self.0
2276 }
2277}
2278
2279impl<'w, 's, P: SystemParam> StaticSystemParam<'w, 's, P> {
2280 pub fn into_inner(self) -> SystemParamItem<'w, 's, P> {
2282 self.0
2283 }
2284}
2285
2286unsafe impl<'w, 's, P: ReadOnlySystemParam + 'static> ReadOnlySystemParam
2288 for StaticSystemParam<'w, 's, P>
2289{
2290}
2291
2292unsafe impl<P: SystemParam + 'static> SystemParam for StaticSystemParam<'_, '_, P> {
2294 type State = P::State;
2295 type Item<'world, 'state> = StaticSystemParam<'world, 'state, P>;
2296
2297 fn init_state(world: &mut World) -> Self::State {
2298 P::init_state(world)
2299 }
2300
2301 fn init_access(
2302 state: &Self::State,
2303 system_meta: &mut SystemMeta,
2304 component_access_set: &mut FilteredAccessSet,
2305 world: &mut World,
2306 ) {
2307 P::init_access(state, system_meta, component_access_set, world);
2308 }
2309
2310 fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) {
2311 P::apply(state, system_meta, world);
2312 }
2313
2314 fn queue(state: &mut Self::State, system_meta: &SystemMeta, world: DeferredWorld) {
2315 P::queue(state, system_meta, world);
2316 }
2317
2318 #[inline]
2319 unsafe fn validate_param(
2320 state: &mut Self::State,
2321 system_meta: &SystemMeta,
2322 world: UnsafeWorldCell,
2323 ) -> Result<(), SystemParamValidationError> {
2324 P::validate_param(state, system_meta, world)
2325 }
2326
2327 #[inline]
2328 unsafe fn get_param<'world, 'state>(
2329 state: &'state mut Self::State,
2330 system_meta: &SystemMeta,
2331 world: UnsafeWorldCell<'world>,
2332 change_tick: Tick,
2333 ) -> Self::Item<'world, 'state> {
2334 StaticSystemParam(unsafe { P::get_param(state, system_meta, world, change_tick) })
2336 }
2337}
2338
2339unsafe impl<T: ?Sized> SystemParam for PhantomData<T> {
2341 type State = ();
2342 type Item<'world, 'state> = Self;
2343
2344 fn init_state(_world: &mut World) -> Self::State {}
2345
2346 fn init_access(
2347 _state: &Self::State,
2348 _system_meta: &mut SystemMeta,
2349 _component_access_set: &mut FilteredAccessSet,
2350 _world: &mut World,
2351 ) {
2352 }
2353
2354 #[inline]
2355 unsafe fn get_param<'world, 'state>(
2356 _state: &'state mut Self::State,
2357 _system_meta: &SystemMeta,
2358 _world: UnsafeWorldCell<'world>,
2359 _change_tick: Tick,
2360 ) -> Self::Item<'world, 'state> {
2361 PhantomData
2362 }
2363}
2364
2365unsafe impl<T: ?Sized> ReadOnlySystemParam for PhantomData<T> {}
2367
2368pub struct DynSystemParam<'w, 's> {
2427 state: &'s mut dyn Any,
2429 world: UnsafeWorldCell<'w>,
2430 system_meta: SystemMeta,
2431 change_tick: Tick,
2432}
2433
2434impl<'w, 's> DynSystemParam<'w, 's> {
2435 unsafe fn new(
2442 state: &'s mut dyn Any,
2443 world: UnsafeWorldCell<'w>,
2444 system_meta: SystemMeta,
2445 change_tick: Tick,
2446 ) -> Self {
2447 Self {
2448 state,
2449 world,
2450 system_meta,
2451 change_tick,
2452 }
2453 }
2454
2455 pub fn is<T: SystemParam>(&self) -> bool
2457 where
2459 T::Item<'static, 'static>: SystemParam<Item<'w, 's> = T> + 'static,
2460 {
2461 self.state.is::<ParamState<T::Item<'static, 'static>>>()
2462 }
2463
2464 pub fn downcast<T: SystemParam>(self) -> Option<T>
2467 where
2469 T::Item<'static, 'static>: SystemParam<Item<'w, 's> = T> + 'static,
2470 {
2471 unsafe { downcast::<T>(self.state, &self.system_meta, self.world, self.change_tick) }
2476 }
2477
2478 pub fn downcast_mut<'a, T: SystemParam>(&'a mut self) -> Option<T>
2481 where
2483 T::Item<'static, 'static>: SystemParam<Item<'a, 'a> = T> + 'static,
2484 {
2485 unsafe { downcast::<T>(self.state, &self.system_meta, self.world, self.change_tick) }
2490 }
2491
2492 pub fn downcast_mut_inner<'a, T: ReadOnlySystemParam>(&'a mut self) -> Option<T>
2498 where
2500 T::Item<'static, 'static>: SystemParam<Item<'w, 'a> = T> + 'static,
2501 {
2502 unsafe { downcast::<T>(self.state, &self.system_meta, self.world, self.change_tick) }
2507 }
2508}
2509
2510unsafe fn downcast<'w, 's, T: SystemParam>(
2517 state: &'s mut dyn Any,
2518 system_meta: &SystemMeta,
2519 world: UnsafeWorldCell<'w>,
2520 change_tick: Tick,
2521) -> Option<T>
2522where
2531 T::Item<'static, 'static>: SystemParam<Item<'w, 's> = T> + 'static,
2532{
2533 state
2534 .downcast_mut::<ParamState<T::Item<'static, 'static>>>()
2535 .map(|state| {
2536 unsafe { T::Item::get_param(&mut state.0, system_meta, world, change_tick) }
2541 })
2542}
2543
2544pub struct DynSystemParamState(Box<dyn DynParamState>);
2546
2547impl DynSystemParamState {
2548 pub(crate) fn new<T: SystemParam + 'static>(state: T::State) -> Self {
2549 Self(Box::new(ParamState::<T>(state)))
2550 }
2551}
2552
2553trait DynParamState: Sync + Send + Any {
2555 fn apply(&mut self, system_meta: &SystemMeta, world: &mut World);
2560
2561 fn queue(&mut self, system_meta: &SystemMeta, world: DeferredWorld);
2563
2564 fn init_access(
2566 &self,
2567 system_meta: &mut SystemMeta,
2568 component_access_set: &mut FilteredAccessSet,
2569 world: &mut World,
2570 );
2571
2572 unsafe fn validate_param(
2577 &mut self,
2578 system_meta: &SystemMeta,
2579 world: UnsafeWorldCell,
2580 ) -> Result<(), SystemParamValidationError>;
2581}
2582
2583struct ParamState<T: SystemParam>(T::State);
2585
2586impl<T: SystemParam + 'static> DynParamState for ParamState<T> {
2587 fn apply(&mut self, system_meta: &SystemMeta, world: &mut World) {
2588 T::apply(&mut self.0, system_meta, world);
2589 }
2590
2591 fn queue(&mut self, system_meta: &SystemMeta, world: DeferredWorld) {
2592 T::queue(&mut self.0, system_meta, world);
2593 }
2594
2595 fn init_access(
2596 &self,
2597 system_meta: &mut SystemMeta,
2598 component_access_set: &mut FilteredAccessSet,
2599 world: &mut World,
2600 ) {
2601 T::init_access(&self.0, system_meta, component_access_set, world);
2602 }
2603
2604 unsafe fn validate_param(
2605 &mut self,
2606 system_meta: &SystemMeta,
2607 world: UnsafeWorldCell,
2608 ) -> Result<(), SystemParamValidationError> {
2609 T::validate_param(&mut self.0, system_meta, world)
2610 }
2611}
2612
2613unsafe impl SystemParam for DynSystemParam<'_, '_> {
2615 type State = DynSystemParamState;
2616
2617 type Item<'world, 'state> = DynSystemParam<'world, 'state>;
2618
2619 fn init_state(_world: &mut World) -> Self::State {
2620 DynSystemParamState::new::<()>(())
2621 }
2622
2623 fn init_access(
2624 state: &Self::State,
2625 system_meta: &mut SystemMeta,
2626 component_access_set: &mut FilteredAccessSet,
2627 world: &mut World,
2628 ) {
2629 state
2630 .0
2631 .init_access(system_meta, component_access_set, world);
2632 }
2633
2634 #[inline]
2635 unsafe fn validate_param(
2636 state: &mut Self::State,
2637 system_meta: &SystemMeta,
2638 world: UnsafeWorldCell,
2639 ) -> Result<(), SystemParamValidationError> {
2640 state.0.validate_param(system_meta, world)
2641 }
2642
2643 #[inline]
2644 unsafe fn get_param<'world, 'state>(
2645 state: &'state mut Self::State,
2646 system_meta: &SystemMeta,
2647 world: UnsafeWorldCell<'world>,
2648 change_tick: Tick,
2649 ) -> Self::Item<'world, 'state> {
2650 unsafe { DynSystemParam::new(state.0.as_mut(), world, system_meta.clone(), change_tick) }
2656 }
2657
2658 fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) {
2659 state.0.apply(system_meta, world);
2660 }
2661
2662 fn queue(state: &mut Self::State, system_meta: &SystemMeta, world: DeferredWorld) {
2663 state.0.queue(system_meta, world);
2664 }
2665}
2666
2667unsafe impl SystemParam for FilteredResources<'_, '_> {
2670 type State = Access;
2671
2672 type Item<'world, 'state> = FilteredResources<'world, 'state>;
2673
2674 fn init_state(_world: &mut World) -> Self::State {
2675 Access::new()
2676 }
2677
2678 fn init_access(
2679 access: &Self::State,
2680 system_meta: &mut SystemMeta,
2681 component_access_set: &mut FilteredAccessSet,
2682 world: &mut World,
2683 ) {
2684 let combined_access = component_access_set.combined_access();
2685 let conflicts = combined_access.get_conflicts(access);
2686 if !conflicts.is_empty() {
2687 let accesses = conflicts.format_conflict_list(world);
2688 let system_name = &system_meta.name;
2689 panic!("error[B0002]: FilteredResources in system {system_name} accesses resources(s){accesses} in a way that conflicts with a previous system parameter. Consider removing the duplicate access. See: https://bevy.org/learn/errors/b0002");
2690 }
2691
2692 if access.has_read_all_resources() {
2693 component_access_set.add_unfiltered_read_all_resources();
2694 } else {
2695 for component_id in access.resource_reads_and_writes() {
2696 component_access_set.add_unfiltered_resource_read(component_id);
2697 }
2698 }
2699 }
2700
2701 unsafe fn get_param<'world, 'state>(
2702 state: &'state mut Self::State,
2703 system_meta: &SystemMeta,
2704 world: UnsafeWorldCell<'world>,
2705 change_tick: Tick,
2706 ) -> Self::Item<'world, 'state> {
2707 unsafe { FilteredResources::new(world, state, system_meta.last_run, change_tick) }
2710 }
2711}
2712
2713unsafe impl ReadOnlySystemParam for FilteredResources<'_, '_> {}
2715
2716unsafe impl SystemParam for FilteredResourcesMut<'_, '_> {
2719 type State = Access;
2720
2721 type Item<'world, 'state> = FilteredResourcesMut<'world, 'state>;
2722
2723 fn init_state(_world: &mut World) -> Self::State {
2724 Access::new()
2725 }
2726
2727 fn init_access(
2728 access: &Self::State,
2729 system_meta: &mut SystemMeta,
2730 component_access_set: &mut FilteredAccessSet,
2731 world: &mut World,
2732 ) {
2733 let combined_access = component_access_set.combined_access();
2734 let conflicts = combined_access.get_conflicts(access);
2735 if !conflicts.is_empty() {
2736 let accesses = conflicts.format_conflict_list(world);
2737 let system_name = &system_meta.name;
2738 panic!("error[B0002]: FilteredResourcesMut in system {system_name} accesses resources(s){accesses} in a way that conflicts with a previous system parameter. Consider removing the duplicate access. See: https://bevy.org/learn/errors/b0002");
2739 }
2740
2741 if access.has_read_all_resources() {
2742 component_access_set.add_unfiltered_read_all_resources();
2743 } else {
2744 for component_id in access.resource_reads() {
2745 component_access_set.add_unfiltered_resource_read(component_id);
2746 }
2747 }
2748
2749 if access.has_write_all_resources() {
2750 component_access_set.add_unfiltered_write_all_resources();
2751 } else {
2752 for component_id in access.resource_writes() {
2753 component_access_set.add_unfiltered_resource_write(component_id);
2754 }
2755 }
2756 }
2757
2758 unsafe fn get_param<'world, 'state>(
2759 state: &'state mut Self::State,
2760 system_meta: &SystemMeta,
2761 world: UnsafeWorldCell<'world>,
2762 change_tick: Tick,
2763 ) -> Self::Item<'world, 'state> {
2764 unsafe { FilteredResourcesMut::new(world, state, system_meta.last_run, change_tick) }
2767 }
2768}
2769
2770#[derive(Debug, PartialEq, Eq, Clone, Error)]
2776pub struct SystemParamValidationError {
2777 pub skipped: bool,
2790
2791 pub message: Cow<'static, str>,
2793
2794 pub param: DebugName,
2797
2798 pub field: Cow<'static, str>,
2803}
2804
2805impl SystemParamValidationError {
2806 pub fn skipped<T>(message: impl Into<Cow<'static, str>>) -> Self {
2809 Self::new::<T>(true, message, Cow::Borrowed(""))
2810 }
2811
2812 pub fn invalid<T>(message: impl Into<Cow<'static, str>>) -> Self {
2815 Self::new::<T>(false, message, Cow::Borrowed(""))
2816 }
2817
2818 pub fn new<T>(
2821 skipped: bool,
2822 message: impl Into<Cow<'static, str>>,
2823 field: impl Into<Cow<'static, str>>,
2824 ) -> Self {
2825 Self {
2826 skipped,
2827 message: message.into(),
2828 param: DebugName::type_name::<T>(),
2829 field: field.into(),
2830 }
2831 }
2832
2833 pub(crate) const EMPTY: Self = Self {
2834 skipped: false,
2835 message: Cow::Borrowed(""),
2836 param: DebugName::borrowed(""),
2837 field: Cow::Borrowed(""),
2838 };
2839}
2840
2841impl Display for SystemParamValidationError {
2842 fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
2843 write!(
2844 fmt,
2845 "Parameter `{}{}` failed validation: {}",
2846 self.param.shortname(),
2847 self.field,
2848 self.message
2849 )?;
2850 if !self.skipped {
2851 write!(fmt, "\nIf this is an expected state, wrap the parameter in `Option<T>` and handle `None` when it happens, or wrap the parameter in `If<T>` to skip the system when it happens.")?;
2852 }
2853 Ok(())
2854 }
2855}
2856
2857#[cfg(test)]
2858mod tests {
2859 use super::*;
2860 use crate::system::assert_is_system;
2861 use core::cell::RefCell;
2862
2863 #[test]
2864 #[should_panic]
2865 fn non_send_alias() {
2866 #[derive(Resource)]
2867 struct A(usize);
2868 fn my_system(mut res0: NonSendMut<A>, mut res1: NonSendMut<A>) {
2869 res0.0 += 1;
2870 res1.0 += 1;
2871 }
2872 let mut world = World::new();
2873 world.insert_non_send_resource(A(42));
2874 let mut schedule = crate::schedule::Schedule::default();
2875 schedule.add_systems(my_system);
2876 schedule.run(&mut world);
2877 }
2878
2879 #[test]
2881 fn system_param_generic_bounds() {
2882 #[derive(SystemParam)]
2883 pub struct SpecialQuery<
2884 'w,
2885 's,
2886 D: QueryData + Send + Sync + 'static,
2887 F: QueryFilter + Send + Sync + 'static = (),
2888 > {
2889 _query: Query<'w, 's, D, F>,
2890 }
2891
2892 fn my_system(_: SpecialQuery<(), ()>) {}
2893 assert_is_system(my_system);
2894 }
2895
2896 #[test]
2898 fn system_param_flexibility() {
2899 #[derive(SystemParam)]
2900 pub struct SpecialRes<'w, T: Resource> {
2901 _res: Res<'w, T>,
2902 }
2903
2904 #[derive(SystemParam)]
2905 pub struct SpecialLocal<'s, T: FromWorld + Send + 'static> {
2906 _local: Local<'s, T>,
2907 }
2908
2909 #[derive(Resource)]
2910 struct R;
2911
2912 fn my_system(_: SpecialRes<R>, _: SpecialLocal<u32>) {}
2913 assert_is_system(my_system);
2914 }
2915
2916 #[derive(Resource)]
2917 pub struct R<const I: usize>;
2918
2919 #[test]
2921 fn system_param_const_generics() {
2922 #[expect(
2923 dead_code,
2924 reason = "This struct is used to ensure that const generics are supported as a SystemParam; thus, the inner value never needs to be read."
2925 )]
2926 #[derive(SystemParam)]
2927 pub struct ConstGenericParam<'w, const I: usize>(Res<'w, R<I>>);
2928
2929 fn my_system(_: ConstGenericParam<0>, _: ConstGenericParam<1000>) {}
2930 assert_is_system(my_system);
2931 }
2932
2933 #[test]
2935 fn system_param_field_limit() {
2936 #[derive(SystemParam)]
2937 pub struct LongParam<'w> {
2938 _r0: Res<'w, R<0>>,
2941 _r1: Res<'w, R<1>>,
2942 _r2: Res<'w, R<2>>,
2943 _r3: Res<'w, R<3>>,
2944 _r4: Res<'w, R<4>>,
2945 _r5: Res<'w, R<5>>,
2946 _r6: Res<'w, R<6>>,
2947 _r7: Res<'w, R<7>>,
2948 _r8: Res<'w, R<8>>,
2949 _r9: Res<'w, R<9>>,
2950 _r10: Res<'w, R<10>>,
2951 _r11: Res<'w, R<11>>,
2952 _r12: Res<'w, R<12>>,
2953 _r13: Res<'w, R<13>>,
2954 _r14: Res<'w, R<14>>,
2955 _r15: Res<'w, R<15>>,
2956 _r16: Res<'w, R<16>>,
2957 }
2958
2959 fn long_system(_: LongParam) {}
2960 assert_is_system(long_system);
2961 }
2962
2963 #[test]
2966 fn system_param_phantom_data() {
2967 #[derive(SystemParam)]
2968 struct PhantomParam<'w, T: Resource, Marker: 'static> {
2969 _foo: Res<'w, T>,
2970 marker: PhantomData<&'w Marker>,
2971 }
2972
2973 fn my_system(_: PhantomParam<R<0>, ()>) {}
2974 assert_is_system(my_system);
2975 }
2976
2977 #[test]
2979 fn system_param_struct_variants() {
2980 #[derive(SystemParam)]
2981 pub struct UnitParam;
2982
2983 #[expect(
2984 dead_code,
2985 reason = "This struct is used to ensure that tuple structs are supported as a SystemParam; thus, the inner values never need to be read."
2986 )]
2987 #[derive(SystemParam)]
2988 pub struct TupleParam<'w, 's, R: Resource, L: FromWorld + Send + 'static>(
2989 Res<'w, R>,
2990 Local<'s, L>,
2991 );
2992
2993 fn my_system(_: UnitParam, _: TupleParam<R<0>, u32>) {}
2994 assert_is_system(my_system);
2995 }
2996
2997 #[test]
2999 fn system_param_private_fields() {
3000 #[derive(Resource)]
3001 struct PrivateResource;
3002
3003 #[expect(
3004 dead_code,
3005 reason = "This struct is used to ensure that SystemParam's derive can't leak private fields; thus, the inner values never need to be read."
3006 )]
3007 #[derive(SystemParam)]
3008 pub struct EncapsulatedParam<'w>(Res<'w, PrivateResource>);
3009
3010 fn my_system(_: EncapsulatedParam) {}
3011 assert_is_system(my_system);
3012 }
3013
3014 #[test]
3016 fn system_param_where_clause() {
3017 #[derive(SystemParam)]
3018 pub struct WhereParam<'w, 's, D>
3019 where
3020 D: 'static + QueryData,
3021 {
3022 _q: Query<'w, 's, D, ()>,
3023 }
3024
3025 fn my_system(_: WhereParam<()>) {}
3026 assert_is_system(my_system);
3027 }
3028
3029 #[test]
3031 fn system_param_name_collision() {
3032 #[derive(Resource)]
3033 pub struct FetchState;
3034
3035 #[derive(SystemParam)]
3036 pub struct Collide<'w> {
3037 _x: Res<'w, FetchState>,
3038 }
3039
3040 fn my_system(_: Collide) {}
3041 assert_is_system(my_system);
3042 }
3043
3044 #[test]
3046 fn system_param_invariant_lifetime() {
3047 #[derive(SystemParam)]
3048 pub struct InvariantParam<'w, 's> {
3049 _set: ParamSet<'w, 's, (Query<'w, 's, ()>,)>,
3050 }
3051
3052 fn my_system(_: InvariantParam) {}
3053 assert_is_system(my_system);
3054 }
3055
3056 #[test]
3058 fn non_sync_local() {
3059 fn non_sync_system(cell: Local<RefCell<u8>>) {
3060 assert_eq!(*cell.borrow(), 0);
3061 }
3062
3063 let mut world = World::new();
3064 let mut schedule = crate::schedule::Schedule::default();
3065 schedule.add_systems(non_sync_system);
3066 schedule.run(&mut world);
3067 }
3068
3069 #[test]
3071 fn param_set_non_send_first() {
3072 fn non_send_param_set(mut p: ParamSet<(NonSend<*mut u8>, ())>) {
3073 let _ = p.p0();
3074 p.p1();
3075 }
3076
3077 let mut world = World::new();
3078 world.insert_non_send_resource(core::ptr::null_mut::<u8>());
3079 let mut schedule = crate::schedule::Schedule::default();
3080 schedule.add_systems((non_send_param_set, non_send_param_set, non_send_param_set));
3081 schedule.run(&mut world);
3082 }
3083
3084 #[test]
3086 fn param_set_non_send_second() {
3087 fn non_send_param_set(mut p: ParamSet<((), NonSendMut<*mut u8>)>) {
3088 p.p0();
3089 let _ = p.p1();
3090 }
3091
3092 let mut world = World::new();
3093 world.insert_non_send_resource(core::ptr::null_mut::<u8>());
3094 let mut schedule = crate::schedule::Schedule::default();
3095 schedule.add_systems((non_send_param_set, non_send_param_set, non_send_param_set));
3096 schedule.run(&mut world);
3097 }
3098
3099 fn _dyn_system_param_type_inference(mut p: DynSystemParam) {
3100 let _query: Query<()> = p.downcast_mut().unwrap();
3103 let _query: Query<()> = p.downcast_mut_inner().unwrap();
3104 let _query: Query<()> = p.downcast().unwrap();
3105 }
3106
3107 #[test]
3108 #[should_panic]
3109 fn missing_resource_error() {
3110 #[derive(Resource)]
3111 pub struct MissingResource;
3112
3113 let mut schedule = crate::schedule::Schedule::default();
3114 schedule.add_systems(res_system);
3115 let mut world = World::new();
3116 schedule.run(&mut world);
3117
3118 fn res_system(_: Res<MissingResource>) {}
3119 }
3120
3121 #[test]
3122 #[should_panic]
3123 fn missing_message_error() {
3124 use crate::prelude::{Message, MessageReader};
3125
3126 #[derive(Message)]
3127 pub struct MissingEvent;
3128
3129 let mut schedule = crate::schedule::Schedule::default();
3130 schedule.add_systems(message_system);
3131 let mut world = World::new();
3132 schedule.run(&mut world);
3133
3134 fn message_system(_: MessageReader<MissingEvent>) {}
3135 }
3136}