1pub use crate::change_detection::{NonSend, NonSendMut, Res, ResMut};
2use crate::{
3 archetype::Archetypes,
4 bundle::Bundles,
5 change_detection::{ComponentTicksMut, ComponentTicksRef, Tick},
6 component::{ComponentId, Components},
7 entity::{Entities, EntityAllocator},
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::{borrow::Cow, boxed::Box, vec::Vec};
21pub use bevy_ecs_macros::SystemParam;
22use bevy_platform::cell::SyncCell;
23use bevy_ptr::UnsafeCellDeref;
24use bevy_utils::prelude::DebugName;
25use core::{
26 any::Any,
27 fmt::{Debug, Display},
28 marker::PhantomData,
29 ops::{Deref, DerefMut},
30};
31use thiserror::Error;
32
33use super::Populated;
34use variadics_please::{all_tuples, all_tuples_enumerated};
35
36pub unsafe trait SystemParam: Sized {
214 type State: Send + Sync + 'static;
216
217 type Item<'world, 'state>: SystemParam<State = Self::State>;
222
223 fn init_state(world: &mut World) -> Self::State;
225
226 fn init_access(
228 state: &Self::State,
229 system_meta: &mut SystemMeta,
230 component_access_set: &mut FilteredAccessSet,
231 world: &mut World,
232 );
233
234 #[inline]
239 #[expect(
240 unused_variables,
241 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."
242 )]
243 fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) {}
244
245 #[inline]
247 #[expect(
248 unused_variables,
249 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."
250 )]
251 fn queue(state: &mut Self::State, system_meta: &SystemMeta, world: DeferredWorld) {}
252
253 #[expect(
287 unused_variables,
288 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."
289 )]
290 unsafe fn validate_param(
291 state: &mut Self::State,
292 system_meta: &SystemMeta,
293 world: UnsafeWorldCell,
294 ) -> Result<(), SystemParamValidationError> {
295 Ok(())
296 }
297
298 unsafe fn get_param<'world, 'state>(
306 state: &'state mut Self::State,
307 system_meta: &SystemMeta,
308 world: UnsafeWorldCell<'world>,
309 change_tick: Tick,
310 ) -> Self::Item<'world, 'state>;
311}
312
313pub unsafe trait ReadOnlySystemParam: SystemParam {}
318
319pub type SystemParamItem<'w, 's, P> = <P as SystemParam>::Item<'w, 's>;
321
322unsafe impl<'w, 's, D: ReadOnlyQueryData + 'static, F: QueryFilter + 'static> ReadOnlySystemParam
324 for Query<'w, 's, D, F>
325{
326}
327
328unsafe impl<D: QueryData + 'static, F: QueryFilter + 'static> SystemParam for Query<'_, '_, D, F> {
331 type State = QueryState<D, F>;
332 type Item<'w, 's> = Query<'w, 's, D, F>;
333
334 fn init_state(world: &mut World) -> Self::State {
335 QueryState::new(world)
336 }
337
338 fn init_access(
339 state: &Self::State,
340 system_meta: &mut SystemMeta,
341 component_access_set: &mut FilteredAccessSet,
342 world: &mut World,
343 ) {
344 assert_component_access_compatibility(
345 &system_meta.name,
346 DebugName::type_name::<D>(),
347 DebugName::type_name::<F>(),
348 component_access_set,
349 &state.component_access,
350 world,
351 );
352 component_access_set.add(state.component_access.clone());
353 }
354
355 #[inline]
356 unsafe fn get_param<'w, 's>(
357 state: &'s mut Self::State,
358 system_meta: &SystemMeta,
359 world: UnsafeWorldCell<'w>,
360 change_tick: Tick,
361 ) -> Self::Item<'w, 's> {
362 unsafe { state.query_unchecked_with_ticks(world, system_meta.last_run, change_tick) }
367 }
368}
369
370fn assert_component_access_compatibility(
371 system_name: &DebugName,
372 query_type: DebugName,
373 filter_type: DebugName,
374 system_access: &FilteredAccessSet,
375 current: &FilteredAccess,
376 world: &World,
377) {
378 let conflicts = system_access.get_conflicts_single(current);
379 if conflicts.is_empty() {
380 return;
381 }
382 let mut accesses = conflicts.format_conflict_list(world);
383 if !accesses.is_empty() {
385 accesses.push(' ');
386 }
387 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());
388}
389
390unsafe impl<'a, 'b, D: QueryData + 'static, F: QueryFilter + 'static> SystemParam
393 for Single<'a, 'b, D, F>
394{
395 type State = QueryState<D, F>;
396 type Item<'w, 's> = Single<'w, 's, D, F>;
397
398 fn init_state(world: &mut World) -> Self::State {
399 Query::init_state(world)
400 }
401
402 fn init_access(
403 state: &Self::State,
404 system_meta: &mut SystemMeta,
405 component_access_set: &mut FilteredAccessSet,
406 world: &mut World,
407 ) {
408 Query::init_access(state, system_meta, component_access_set, world);
409 }
410
411 #[inline]
412 unsafe fn get_param<'w, 's>(
413 state: &'s mut Self::State,
414 system_meta: &SystemMeta,
415 world: UnsafeWorldCell<'w>,
416 change_tick: Tick,
417 ) -> Self::Item<'w, 's> {
418 let query =
421 unsafe { state.query_unchecked_with_ticks(world, system_meta.last_run, change_tick) };
422 let single = query
423 .single_inner()
424 .expect("The query was expected to contain exactly one matching entity.");
425 Single {
426 item: single,
427 _filter: PhantomData,
428 }
429 }
430
431 #[inline]
432 unsafe fn validate_param(
433 state: &mut Self::State,
434 system_meta: &SystemMeta,
435 world: UnsafeWorldCell,
436 ) -> Result<(), SystemParamValidationError> {
437 let query = unsafe {
441 state.query_unchecked_with_ticks(world, system_meta.last_run, world.change_tick())
442 };
443 match query.single_inner() {
444 Ok(_) => Ok(()),
445 Err(QuerySingleError::NoEntities(_)) => Err(
446 SystemParamValidationError::skipped::<Self>("No matching entities"),
447 ),
448 Err(QuerySingleError::MultipleEntities(_)) => Err(
449 SystemParamValidationError::skipped::<Self>("Multiple matching entities"),
450 ),
451 }
452 }
453}
454
455unsafe impl<'a, 'b, D: ReadOnlyQueryData + 'static, F: QueryFilter + 'static> ReadOnlySystemParam
457 for Single<'a, 'b, D, F>
458{
459}
460
461unsafe impl<D: QueryData + 'static, F: QueryFilter + 'static> SystemParam
464 for Populated<'_, '_, D, F>
465{
466 type State = QueryState<D, F>;
467 type Item<'w, 's> = Populated<'w, 's, D, F>;
468
469 fn init_state(world: &mut World) -> Self::State {
470 Query::init_state(world)
471 }
472
473 fn init_access(
474 state: &Self::State,
475 system_meta: &mut SystemMeta,
476 component_access_set: &mut FilteredAccessSet,
477 world: &mut World,
478 ) {
479 Query::init_access(state, system_meta, component_access_set, world);
480 }
481
482 #[inline]
483 unsafe fn get_param<'w, 's>(
484 state: &'s mut Self::State,
485 system_meta: &SystemMeta,
486 world: UnsafeWorldCell<'w>,
487 change_tick: Tick,
488 ) -> Self::Item<'w, 's> {
489 let query = unsafe { Query::get_param(state, system_meta, world, change_tick) };
491 Populated(query)
492 }
493
494 #[inline]
495 unsafe fn validate_param(
496 state: &mut Self::State,
497 system_meta: &SystemMeta,
498 world: UnsafeWorldCell,
499 ) -> Result<(), SystemParamValidationError> {
500 let query = unsafe {
504 state.query_unchecked_with_ticks(world, system_meta.last_run, world.change_tick())
505 };
506 if query.is_empty() {
507 Err(SystemParamValidationError::skipped::<Self>(
508 "No matching entities",
509 ))
510 } else {
511 Ok(())
512 }
513 }
514}
515
516unsafe impl<'w, 's, D: ReadOnlyQueryData + 'static, F: QueryFilter + 'static> ReadOnlySystemParam
518 for Populated<'w, 's, D, F>
519{
520}
521
522pub struct ParamSet<'w, 's, T: SystemParam> {
636 param_states: &'s mut T::State,
637 world: UnsafeWorldCell<'w>,
638 system_meta: SystemMeta,
639 change_tick: Tick,
640}
641
642macro_rules! impl_param_set {
643 ($(($index: tt, $param: ident, $fn_name: ident)),*) => {
644 unsafe impl<'w, 's, $($param,)*> ReadOnlySystemParam for ParamSet<'w, 's, ($($param,)*)>
646 where $($param: ReadOnlySystemParam,)*
647 { }
648
649 unsafe impl<'_w, '_s, $($param: SystemParam,)*> SystemParam for ParamSet<'_w, '_s, ($($param,)*)>
652 {
653 type State = ($($param::State,)*);
654 type Item<'w, 's> = ParamSet<'w, 's, ($($param,)*)>;
655
656 #[expect(
657 clippy::allow_attributes,
658 reason = "This is inside a macro meant for tuples; as such, `non_snake_case` won't always lint."
659 )]
660 #[allow(
661 non_snake_case,
662 reason = "Certain variable names are provided by the caller, not by us."
663 )]
664 fn init_state(world: &mut World) -> Self::State {
665 ($($param::init_state(world),)*)
666 }
667
668 #[expect(
669 clippy::allow_attributes,
670 reason = "This is inside a macro meant for tuples; as such, `non_snake_case` won't always lint."
671 )]
672 #[allow(
673 non_snake_case,
674 reason = "Certain variable names are provided by the caller, not by us."
675 )]
676 fn init_access(state: &Self::State, system_meta: &mut SystemMeta, component_access_set: &mut FilteredAccessSet, world: &mut World) {
677 let ($($param,)*) = state;
678 $(
679 let component_access_set_clone = &mut component_access_set.clone();
681 $param::init_access($param, system_meta, component_access_set_clone, world);
682 )*
683 $(
684 let mut access_set = FilteredAccessSet::new();
687 $param::init_access($param, system_meta, &mut access_set, world);
688 component_access_set.extend(access_set);
689 )*
690 }
691
692 fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) {
693 <($($param,)*) as SystemParam>::apply(state, system_meta, world);
694 }
695
696 fn queue(state: &mut Self::State, system_meta: &SystemMeta, mut world: DeferredWorld) {
697 <($($param,)*) as SystemParam>::queue(state, system_meta, world.reborrow());
698 }
699
700 #[inline]
701 unsafe fn validate_param<'w, 's>(
702 state: &'s mut Self::State,
703 system_meta: &SystemMeta,
704 world: UnsafeWorldCell<'w>,
705 ) -> Result<(), SystemParamValidationError> {
706 unsafe {
708 <($($param,)*) as SystemParam>::validate_param(state, system_meta, world)
709 }
710 }
711
712 #[inline]
713 unsafe fn get_param<'w, 's>(
714 state: &'s mut Self::State,
715 system_meta: &SystemMeta,
716 world: UnsafeWorldCell<'w>,
717 change_tick: Tick,
718 ) -> Self::Item<'w, 's> {
719 ParamSet {
720 param_states: state,
721 system_meta: system_meta.clone(),
722 world,
723 change_tick,
724 }
725 }
726 }
727
728 impl<'w, 's, $($param: SystemParam,)*> ParamSet<'w, 's, ($($param,)*)>
729 {
730 $(
731 #[doc = stringify!($index)]
733 pub fn $fn_name<'a>(&'a mut self) -> SystemParamItem<'a, 'a, $param> {
736 unsafe {
740 $param::get_param(&mut self.param_states.$index, &self.system_meta, self.world, self.change_tick)
741 }
742 }
743 )*
744 }
745 }
746}
747
748all_tuples_enumerated!(impl_param_set, 1, 8, P, p);
749
750unsafe impl<'a, T: Resource> ReadOnlySystemParam for Res<'a, T> {}
752
753unsafe impl<'a, T: Resource> SystemParam for Res<'a, T> {
756 type State = ComponentId;
757 type Item<'w, 's> = Res<'w, T>;
758
759 fn init_state(world: &mut World) -> Self::State {
760 world.components_registrator().register_resource::<T>()
761 }
762
763 fn init_access(
764 &component_id: &Self::State,
765 system_meta: &mut SystemMeta,
766 component_access_set: &mut FilteredAccessSet,
767 _world: &mut World,
768 ) {
769 let combined_access = component_access_set.combined_access();
770 assert!(
771 !combined_access.has_resource_write(component_id),
772 "error[B0002]: Res<{}> in system {} conflicts with a previous ResMut<{0}> access. Consider removing the duplicate access. See: https://bevy.org/learn/errors/b0002",
773 DebugName::type_name::<T>(),
774 system_meta.name,
775 );
776
777 component_access_set.add_unfiltered_resource_read(component_id);
778 }
779
780 #[inline]
781 unsafe fn validate_param(
782 &mut component_id: &mut Self::State,
783 _system_meta: &SystemMeta,
784 world: UnsafeWorldCell,
785 ) -> Result<(), SystemParamValidationError> {
786 if unsafe { world.storages() }
788 .resources
789 .get(component_id)
790 .is_some_and(ResourceData::is_present)
791 {
792 Ok(())
793 } else {
794 Err(SystemParamValidationError::invalid::<Self>(
795 "Resource does not exist",
796 ))
797 }
798 }
799
800 #[inline]
801 unsafe fn get_param<'w, 's>(
802 &mut component_id: &'s mut Self::State,
803 system_meta: &SystemMeta,
804 world: UnsafeWorldCell<'w>,
805 change_tick: Tick,
806 ) -> Self::Item<'w, 's> {
807 let (ptr, ticks) = world
808 .get_resource_with_ticks(component_id)
809 .unwrap_or_else(|| {
810 panic!(
811 "Resource requested by {} does not exist: {}",
812 system_meta.name,
813 DebugName::type_name::<T>()
814 );
815 });
816 Res {
817 value: ptr.deref(),
818 ticks: ComponentTicksRef {
819 added: ticks.added.deref(),
820 changed: ticks.changed.deref(),
821 changed_by: ticks.changed_by.map(|changed_by| changed_by.deref()),
822 last_run: system_meta.last_run,
823 this_run: change_tick,
824 },
825 }
826 }
827}
828
829unsafe impl<'a, T: Resource> SystemParam for ResMut<'a, T> {
832 type State = ComponentId;
833 type Item<'w, 's> = ResMut<'w, T>;
834
835 fn init_state(world: &mut World) -> Self::State {
836 world.components_registrator().register_resource::<T>()
837 }
838
839 fn init_access(
840 &component_id: &Self::State,
841 system_meta: &mut SystemMeta,
842 component_access_set: &mut FilteredAccessSet,
843 _world: &mut World,
844 ) {
845 let combined_access = component_access_set.combined_access();
846 if combined_access.has_resource_write(component_id) {
847 panic!(
848 "error[B0002]: ResMut<{}> in system {} conflicts with a previous ResMut<{0}> access. Consider removing the duplicate access. See: https://bevy.org/learn/errors/b0002",
849 DebugName::type_name::<T>(), system_meta.name);
850 } else if combined_access.has_resource_read(component_id) {
851 panic!(
852 "error[B0002]: ResMut<{}> in system {} conflicts with a previous Res<{0}> access. Consider removing the duplicate access. See: https://bevy.org/learn/errors/b0002",
853 DebugName::type_name::<T>(), system_meta.name);
854 }
855 component_access_set.add_unfiltered_resource_write(component_id);
856 }
857
858 #[inline]
859 unsafe fn validate_param(
860 &mut component_id: &mut Self::State,
861 _system_meta: &SystemMeta,
862 world: UnsafeWorldCell,
863 ) -> Result<(), SystemParamValidationError> {
864 if unsafe { world.storages() }
866 .resources
867 .get(component_id)
868 .is_some_and(ResourceData::is_present)
869 {
870 Ok(())
871 } else {
872 Err(SystemParamValidationError::invalid::<Self>(
873 "Resource does not exist",
874 ))
875 }
876 }
877
878 #[inline]
879 unsafe fn get_param<'w, 's>(
880 &mut component_id: &'s mut Self::State,
881 system_meta: &SystemMeta,
882 world: UnsafeWorldCell<'w>,
883 change_tick: Tick,
884 ) -> Self::Item<'w, 's> {
885 let value = world
886 .get_resource_mut_by_id(component_id)
887 .unwrap_or_else(|| {
888 panic!(
889 "Resource requested by {} does not exist: {}",
890 system_meta.name,
891 DebugName::type_name::<T>()
892 );
893 });
894 ResMut {
895 value: value.value.deref_mut::<T>(),
896 ticks: ComponentTicksMut {
897 added: value.ticks.added,
898 changed: value.ticks.changed,
899 changed_by: value.ticks.changed_by,
900 last_run: system_meta.last_run,
901 this_run: change_tick,
902 },
903 }
904 }
905}
906
907unsafe impl<'w> ReadOnlySystemParam for &'w World {}
909
910unsafe impl SystemParam for &'_ World {
912 type State = ();
913 type Item<'w, 's> = &'w World;
914
915 fn init_state(_world: &mut World) -> Self::State {}
916
917 fn init_access(
918 _state: &Self::State,
919 _system_meta: &mut SystemMeta,
920 component_access_set: &mut FilteredAccessSet,
921 _world: &mut World,
922 ) {
923 let mut filtered_access = FilteredAccess::default();
924
925 filtered_access.read_all();
926 if !component_access_set
927 .get_conflicts_single(&filtered_access)
928 .is_empty()
929 {
930 panic!("&World conflicts with a previous mutable system parameter. Allowing this would break Rust's mutability rules");
931 }
932 component_access_set.add(filtered_access);
933 }
934
935 #[inline]
936 unsafe fn get_param<'w, 's>(
937 _state: &'s mut Self::State,
938 _system_meta: &SystemMeta,
939 world: UnsafeWorldCell<'w>,
940 _change_tick: Tick,
941 ) -> Self::Item<'w, 's> {
942 unsafe { world.world() }
944 }
945}
946
947unsafe impl<'w> SystemParam for DeferredWorld<'w> {
949 type State = ();
950 type Item<'world, 'state> = DeferredWorld<'world>;
951
952 fn init_state(_world: &mut World) -> Self::State {}
953
954 fn init_access(
955 _state: &Self::State,
956 system_meta: &mut SystemMeta,
957 component_access_set: &mut FilteredAccessSet,
958 _world: &mut World,
959 ) {
960 assert!(
961 !component_access_set.combined_access().has_any_read(),
962 "DeferredWorld in system {} conflicts with a previous access.",
963 system_meta.name,
964 );
965 component_access_set.write_all();
966 }
967
968 unsafe fn get_param<'world, 'state>(
969 _state: &'state mut Self::State,
970 _system_meta: &SystemMeta,
971 world: UnsafeWorldCell<'world>,
972 _change_tick: Tick,
973 ) -> Self::Item<'world, 'state> {
974 unsafe { world.into_deferred() }
976 }
977}
978
979#[derive(Debug)]
1096pub struct Local<'s, T: FromWorld + Send + 'static>(pub(crate) &'s mut T);
1097
1098unsafe impl<'s, T: FromWorld + Send + 'static> ReadOnlySystemParam for Local<'s, T> {}
1100
1101impl<'s, T: FromWorld + Send + 'static> Deref for Local<'s, T> {
1102 type Target = T;
1103
1104 #[inline]
1105 fn deref(&self) -> &Self::Target {
1106 self.0
1107 }
1108}
1109
1110impl<'s, T: FromWorld + Send + 'static> DerefMut for Local<'s, T> {
1111 #[inline]
1112 fn deref_mut(&mut self) -> &mut Self::Target {
1113 self.0
1114 }
1115}
1116
1117impl<'s, 'a, T: FromWorld + Send + 'static> IntoIterator for &'a Local<'s, T>
1118where
1119 &'a T: IntoIterator,
1120{
1121 type Item = <&'a T as IntoIterator>::Item;
1122 type IntoIter = <&'a T as IntoIterator>::IntoIter;
1123
1124 fn into_iter(self) -> Self::IntoIter {
1125 self.0.into_iter()
1126 }
1127}
1128
1129impl<'s, 'a, T: FromWorld + Send + 'static> IntoIterator for &'a mut Local<'s, T>
1130where
1131 &'a mut T: IntoIterator,
1132{
1133 type Item = <&'a mut T as IntoIterator>::Item;
1134 type IntoIter = <&'a mut T as IntoIterator>::IntoIter;
1135
1136 fn into_iter(self) -> Self::IntoIter {
1137 self.0.into_iter()
1138 }
1139}
1140
1141unsafe impl<'a, T: FromWorld + Send + 'static> SystemParam for Local<'a, T> {
1143 type State = SyncCell<T>;
1144 type Item<'w, 's> = Local<'s, T>;
1145
1146 fn init_state(world: &mut World) -> Self::State {
1147 SyncCell::new(T::from_world(world))
1148 }
1149
1150 fn init_access(
1151 _state: &Self::State,
1152 _system_meta: &mut SystemMeta,
1153 _component_access_set: &mut FilteredAccessSet,
1154 _world: &mut World,
1155 ) {
1156 }
1157
1158 #[inline]
1159 unsafe fn get_param<'w, 's>(
1160 state: &'s mut Self::State,
1161 _system_meta: &SystemMeta,
1162 _world: UnsafeWorldCell<'w>,
1163 _change_tick: Tick,
1164 ) -> Self::Item<'w, 's> {
1165 Local(state.get())
1166 }
1167}
1168
1169pub trait SystemBuffer: FromWorld + Send + 'static {
1176 fn apply(&mut self, system_meta: &SystemMeta, world: &mut World);
1178 fn queue(&mut self, _system_meta: &SystemMeta, _world: DeferredWorld) {}
1180}
1181
1182pub struct Deferred<'a, T: SystemBuffer>(pub(crate) &'a mut T);
1302
1303impl<'a, T: SystemBuffer> Deref for Deferred<'a, T> {
1304 type Target = T;
1305 #[inline]
1306 fn deref(&self) -> &Self::Target {
1307 self.0
1308 }
1309}
1310
1311impl<'a, T: SystemBuffer> DerefMut for Deferred<'a, T> {
1312 #[inline]
1313 fn deref_mut(&mut self) -> &mut Self::Target {
1314 self.0
1315 }
1316}
1317
1318impl<T: SystemBuffer> Deferred<'_, T> {
1319 pub fn reborrow(&mut self) -> Deferred<'_, T> {
1322 Deferred(self.0)
1323 }
1324}
1325
1326unsafe impl<T: SystemBuffer> ReadOnlySystemParam for Deferred<'_, T> {}
1328
1329unsafe impl<T: SystemBuffer> SystemParam for Deferred<'_, T> {
1331 type State = SyncCell<T>;
1332 type Item<'w, 's> = Deferred<'s, T>;
1333
1334 fn init_state(world: &mut World) -> Self::State {
1335 SyncCell::new(T::from_world(world))
1336 }
1337
1338 fn init_access(
1339 _state: &Self::State,
1340 system_meta: &mut SystemMeta,
1341 _component_access_set: &mut FilteredAccessSet,
1342 _world: &mut World,
1343 ) {
1344 system_meta.set_has_deferred();
1345 }
1346
1347 fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) {
1348 state.get().apply(system_meta, world);
1349 }
1350
1351 fn queue(state: &mut Self::State, system_meta: &SystemMeta, world: DeferredWorld) {
1352 state.get().queue(system_meta, world);
1353 }
1354
1355 #[inline]
1356 unsafe fn get_param<'w, 's>(
1357 state: &'s mut Self::State,
1358 _system_meta: &SystemMeta,
1359 _world: UnsafeWorldCell<'w>,
1360 _change_tick: Tick,
1361 ) -> Self::Item<'w, 's> {
1362 Deferred(state.get())
1363 }
1364}
1365
1366pub struct ExclusiveMarker(PhantomData<()>);
1368
1369unsafe impl SystemParam for ExclusiveMarker {
1371 type State = ();
1372 type Item<'w, 's> = Self;
1373
1374 #[inline]
1375 fn init_state(_world: &mut World) -> Self::State {}
1376
1377 fn init_access(
1378 _state: &Self::State,
1379 system_meta: &mut SystemMeta,
1380 _component_access_set: &mut FilteredAccessSet,
1381 _world: &mut World,
1382 ) {
1383 system_meta.set_exclusive();
1384 }
1385
1386 #[inline]
1387 unsafe fn get_param<'world, 'state>(
1388 _state: &'state mut Self::State,
1389 _system_meta: &SystemMeta,
1390 _world: UnsafeWorldCell<'world>,
1391 _change_tick: Tick,
1392 ) -> Self::Item<'world, 'state> {
1393 Self(PhantomData)
1394 }
1395}
1396
1397unsafe impl ReadOnlySystemParam for ExclusiveMarker {}
1399
1400pub struct NonSendMarker(PhantomData<*mut ()>);
1402
1403unsafe impl SystemParam for NonSendMarker {
1405 type State = ();
1406 type Item<'w, 's> = Self;
1407
1408 #[inline]
1409 fn init_state(_world: &mut World) -> Self::State {}
1410
1411 fn init_access(
1412 _state: &Self::State,
1413 system_meta: &mut SystemMeta,
1414 _component_access_set: &mut FilteredAccessSet,
1415 _world: &mut World,
1416 ) {
1417 system_meta.set_non_send();
1418 }
1419
1420 #[inline]
1421 unsafe fn get_param<'world, 'state>(
1422 _state: &'state mut Self::State,
1423 _system_meta: &SystemMeta,
1424 _world: UnsafeWorldCell<'world>,
1425 _change_tick: Tick,
1426 ) -> Self::Item<'world, 'state> {
1427 Self(PhantomData)
1428 }
1429}
1430
1431unsafe impl ReadOnlySystemParam for NonSendMarker {}
1433
1434unsafe impl<'w, T> ReadOnlySystemParam for NonSend<'w, T> {}
1436
1437unsafe impl<'a, T: 'static> SystemParam for NonSend<'a, T> {
1440 type State = ComponentId;
1441 type Item<'w, 's> = NonSend<'w, T>;
1442
1443 fn init_state(world: &mut World) -> Self::State {
1444 world.components_registrator().register_non_send::<T>()
1445 }
1446
1447 fn init_access(
1448 &component_id: &Self::State,
1449 system_meta: &mut SystemMeta,
1450 component_access_set: &mut FilteredAccessSet,
1451 _world: &mut World,
1452 ) {
1453 system_meta.set_non_send();
1454
1455 let combined_access = component_access_set.combined_access();
1456 assert!(
1457 !combined_access.has_resource_write(component_id),
1458 "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",
1459 DebugName::type_name::<T>(),
1460 system_meta.name,
1461 );
1462 component_access_set.add_unfiltered_resource_read(component_id);
1463 }
1464
1465 #[inline]
1466 unsafe fn validate_param(
1467 &mut component_id: &mut Self::State,
1468 _system_meta: &SystemMeta,
1469 world: UnsafeWorldCell,
1470 ) -> Result<(), SystemParamValidationError> {
1471 if unsafe { world.storages() }
1473 .non_send_resources
1474 .get(component_id)
1475 .is_some_and(ResourceData::is_present)
1476 {
1477 Ok(())
1478 } else {
1479 Err(SystemParamValidationError::invalid::<Self>(
1480 "Non-send resource does not exist",
1481 ))
1482 }
1483 }
1484
1485 #[inline]
1486 unsafe fn get_param<'w, 's>(
1487 &mut component_id: &'s mut Self::State,
1488 system_meta: &SystemMeta,
1489 world: UnsafeWorldCell<'w>,
1490 change_tick: Tick,
1491 ) -> Self::Item<'w, 's> {
1492 let (ptr, ticks) = world
1493 .get_non_send_with_ticks(component_id)
1494 .unwrap_or_else(|| {
1495 panic!(
1496 "Non-send resource requested by {} does not exist: {}",
1497 system_meta.name,
1498 DebugName::type_name::<T>()
1499 );
1500 });
1501 NonSend {
1502 value: ptr.deref(),
1503 ticks: ComponentTicksRef::from_tick_cells(ticks, system_meta.last_run, change_tick),
1504 }
1505 }
1506}
1507
1508unsafe impl<'a, T: 'static> SystemParam for NonSendMut<'a, T> {
1511 type State = ComponentId;
1512 type Item<'w, 's> = NonSendMut<'w, T>;
1513
1514 fn init_state(world: &mut World) -> Self::State {
1515 world.components_registrator().register_non_send::<T>()
1516 }
1517
1518 fn init_access(
1519 &component_id: &Self::State,
1520 system_meta: &mut SystemMeta,
1521 component_access_set: &mut FilteredAccessSet,
1522 _world: &mut World,
1523 ) {
1524 system_meta.set_non_send();
1525
1526 let combined_access = component_access_set.combined_access();
1527 if combined_access.has_resource_write(component_id) {
1528 panic!(
1529 "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",
1530 DebugName::type_name::<T>(), system_meta.name);
1531 } else if combined_access.has_resource_read(component_id) {
1532 panic!(
1533 "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",
1534 DebugName::type_name::<T>(), system_meta.name);
1535 }
1536 component_access_set.add_unfiltered_resource_write(component_id);
1537 }
1538
1539 #[inline]
1540 unsafe fn validate_param(
1541 &mut component_id: &mut Self::State,
1542 _system_meta: &SystemMeta,
1543 world: UnsafeWorldCell,
1544 ) -> Result<(), SystemParamValidationError> {
1545 if unsafe { world.storages() }
1547 .non_send_resources
1548 .get(component_id)
1549 .is_some_and(ResourceData::is_present)
1550 {
1551 Ok(())
1552 } else {
1553 Err(SystemParamValidationError::invalid::<Self>(
1554 "Non-send resource does not exist",
1555 ))
1556 }
1557 }
1558
1559 #[inline]
1560 unsafe fn get_param<'w, 's>(
1561 &mut component_id: &'s mut Self::State,
1562 system_meta: &SystemMeta,
1563 world: UnsafeWorldCell<'w>,
1564 change_tick: Tick,
1565 ) -> Self::Item<'w, 's> {
1566 let (ptr, ticks) = world
1567 .get_non_send_with_ticks(component_id)
1568 .unwrap_or_else(|| {
1569 panic!(
1570 "Non-send resource requested by {} does not exist: {}",
1571 system_meta.name,
1572 DebugName::type_name::<T>()
1573 );
1574 });
1575 NonSendMut {
1576 value: ptr.assert_unique().deref_mut(),
1577 ticks: ComponentTicksMut::from_tick_cells(ticks, system_meta.last_run, change_tick),
1578 }
1579 }
1580}
1581
1582unsafe impl<'a> ReadOnlySystemParam for &'a Archetypes {}
1584
1585unsafe impl<'a> SystemParam for &'a Archetypes {
1587 type State = ();
1588 type Item<'w, 's> = &'w Archetypes;
1589
1590 fn init_state(_world: &mut World) -> Self::State {}
1591
1592 fn init_access(
1593 _state: &Self::State,
1594 _system_meta: &mut SystemMeta,
1595 _component_access_set: &mut FilteredAccessSet,
1596 _world: &mut World,
1597 ) {
1598 }
1599
1600 #[inline]
1601 unsafe fn get_param<'w, 's>(
1602 _state: &'s mut Self::State,
1603 _system_meta: &SystemMeta,
1604 world: UnsafeWorldCell<'w>,
1605 _change_tick: Tick,
1606 ) -> Self::Item<'w, 's> {
1607 world.archetypes()
1608 }
1609}
1610
1611unsafe impl<'a> ReadOnlySystemParam for &'a Components {}
1613
1614unsafe impl<'a> SystemParam for &'a Components {
1616 type State = ();
1617 type Item<'w, 's> = &'w Components;
1618
1619 fn init_state(_world: &mut World) -> Self::State {}
1620
1621 fn init_access(
1622 _state: &Self::State,
1623 _system_meta: &mut SystemMeta,
1624 _component_access_set: &mut FilteredAccessSet,
1625 _world: &mut World,
1626 ) {
1627 }
1628
1629 #[inline]
1630 unsafe fn get_param<'w, 's>(
1631 _state: &'s mut Self::State,
1632 _system_meta: &SystemMeta,
1633 world: UnsafeWorldCell<'w>,
1634 _change_tick: Tick,
1635 ) -> Self::Item<'w, 's> {
1636 world.components()
1637 }
1638}
1639
1640unsafe impl<'a> ReadOnlySystemParam for &'a Entities {}
1642
1643unsafe impl<'a> SystemParam for &'a Entities {
1645 type State = ();
1646 type Item<'w, 's> = &'w Entities;
1647
1648 fn init_state(_world: &mut World) -> Self::State {}
1649
1650 fn init_access(
1651 _state: &Self::State,
1652 _system_meta: &mut SystemMeta,
1653 _component_access_set: &mut FilteredAccessSet,
1654 _world: &mut World,
1655 ) {
1656 }
1657
1658 #[inline]
1659 unsafe fn get_param<'w, 's>(
1660 _state: &'s mut Self::State,
1661 _system_meta: &SystemMeta,
1662 world: UnsafeWorldCell<'w>,
1663 _change_tick: Tick,
1664 ) -> Self::Item<'w, 's> {
1665 world.entities()
1666 }
1667}
1668
1669unsafe impl<'a> ReadOnlySystemParam for &'a EntityAllocator {}
1671
1672unsafe impl<'a> SystemParam for &'a EntityAllocator {
1674 type State = ();
1675 type Item<'w, 's> = &'w EntityAllocator;
1676
1677 fn init_state(_world: &mut World) -> Self::State {}
1678
1679 fn init_access(
1680 _state: &Self::State,
1681 _system_meta: &mut SystemMeta,
1682 _component_access_set: &mut FilteredAccessSet,
1683 _world: &mut World,
1684 ) {
1685 }
1686
1687 #[inline]
1688 unsafe fn get_param<'w, 's>(
1689 _state: &'s mut Self::State,
1690 _system_meta: &SystemMeta,
1691 world: UnsafeWorldCell<'w>,
1692 _change_tick: Tick,
1693 ) -> Self::Item<'w, 's> {
1694 world.entities_allocator()
1695 }
1696}
1697
1698unsafe impl<'a> ReadOnlySystemParam for &'a Bundles {}
1700
1701unsafe impl<'a> SystemParam for &'a Bundles {
1703 type State = ();
1704 type Item<'w, 's> = &'w Bundles;
1705
1706 fn init_state(_world: &mut World) -> Self::State {}
1707
1708 fn init_access(
1709 _state: &Self::State,
1710 _system_meta: &mut SystemMeta,
1711 _component_access_set: &mut FilteredAccessSet,
1712 _world: &mut World,
1713 ) {
1714 }
1715
1716 #[inline]
1717 unsafe fn get_param<'w, 's>(
1718 _state: &'s mut Self::State,
1719 _system_meta: &SystemMeta,
1720 world: UnsafeWorldCell<'w>,
1721 _change_tick: Tick,
1722 ) -> Self::Item<'w, 's> {
1723 world.bundles()
1724 }
1725}
1726
1727#[derive(Debug, Clone, Copy)]
1737pub struct SystemChangeTick {
1738 last_run: Tick,
1739 this_run: Tick,
1740}
1741
1742impl SystemChangeTick {
1743 #[inline]
1745 pub fn this_run(&self) -> Tick {
1746 self.this_run
1747 }
1748
1749 #[inline]
1751 pub fn last_run(&self) -> Tick {
1752 self.last_run
1753 }
1754}
1755
1756unsafe impl ReadOnlySystemParam for SystemChangeTick {}
1758
1759unsafe impl SystemParam for SystemChangeTick {
1761 type State = ();
1762 type Item<'w, 's> = SystemChangeTick;
1763
1764 fn init_state(_world: &mut World) -> Self::State {}
1765
1766 fn init_access(
1767 _state: &Self::State,
1768 _system_meta: &mut SystemMeta,
1769 _component_access_set: &mut FilteredAccessSet,
1770 _world: &mut World,
1771 ) {
1772 }
1773
1774 #[inline]
1775 unsafe fn get_param<'w, 's>(
1776 _state: &'s mut Self::State,
1777 system_meta: &SystemMeta,
1778 _world: UnsafeWorldCell<'w>,
1779 change_tick: Tick,
1780 ) -> Self::Item<'w, 's> {
1781 SystemChangeTick {
1782 last_run: system_meta.last_run,
1783 this_run: change_tick,
1784 }
1785 }
1786}
1787
1788unsafe impl<T: SystemParam> SystemParam for Option<T> {
1790 type State = T::State;
1791
1792 type Item<'world, 'state> = Option<T::Item<'world, 'state>>;
1793
1794 fn init_state(world: &mut World) -> Self::State {
1795 T::init_state(world)
1796 }
1797
1798 fn init_access(
1799 state: &Self::State,
1800 system_meta: &mut SystemMeta,
1801 component_access_set: &mut FilteredAccessSet,
1802 world: &mut World,
1803 ) {
1804 T::init_access(state, system_meta, component_access_set, world);
1805 }
1806
1807 #[inline]
1808 unsafe fn get_param<'world, 'state>(
1809 state: &'state mut Self::State,
1810 system_meta: &SystemMeta,
1811 world: UnsafeWorldCell<'world>,
1812 change_tick: Tick,
1813 ) -> Self::Item<'world, 'state> {
1814 unsafe {
1816 T::validate_param(state, system_meta, world)
1817 .ok()
1818 .map(|()| T::get_param(state, system_meta, world, change_tick))
1819 }
1820 }
1821
1822 fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) {
1823 T::apply(state, system_meta, world);
1824 }
1825
1826 fn queue(state: &mut Self::State, system_meta: &SystemMeta, world: DeferredWorld) {
1827 T::queue(state, system_meta, world);
1828 }
1829}
1830
1831unsafe impl<T: ReadOnlySystemParam> ReadOnlySystemParam for Option<T> {}
1833
1834unsafe impl<T: SystemParam> SystemParam for Result<T, SystemParamValidationError> {
1836 type State = T::State;
1837
1838 type Item<'world, 'state> = Result<T::Item<'world, 'state>, SystemParamValidationError>;
1839
1840 fn init_state(world: &mut World) -> Self::State {
1841 T::init_state(world)
1842 }
1843
1844 fn init_access(
1845 state: &Self::State,
1846 system_meta: &mut SystemMeta,
1847 component_access_set: &mut FilteredAccessSet,
1848 world: &mut World,
1849 ) {
1850 T::init_access(state, system_meta, component_access_set, world);
1851 }
1852
1853 #[inline]
1854 unsafe fn get_param<'world, 'state>(
1855 state: &'state mut Self::State,
1856 system_meta: &SystemMeta,
1857 world: UnsafeWorldCell<'world>,
1858 change_tick: Tick,
1859 ) -> Self::Item<'world, 'state> {
1860 unsafe {
1862 T::validate_param(state, system_meta, world)
1863 .map(|()| T::get_param(state, system_meta, world, change_tick))
1864 }
1865 }
1866
1867 fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) {
1868 T::apply(state, system_meta, world);
1869 }
1870
1871 fn queue(state: &mut Self::State, system_meta: &SystemMeta, world: DeferredWorld) {
1872 T::queue(state, system_meta, world);
1873 }
1874}
1875
1876unsafe impl<T: ReadOnlySystemParam> ReadOnlySystemParam for Result<T, SystemParamValidationError> {}
1878
1879#[derive(Debug)]
1898pub struct If<T>(pub T);
1899
1900impl<T> If<T> {
1901 pub fn into_inner(self) -> T {
1915 self.0
1916 }
1917}
1918
1919impl<T> Deref for If<T> {
1920 type Target = T;
1921 fn deref(&self) -> &Self::Target {
1922 &self.0
1923 }
1924}
1925
1926impl<T> DerefMut for If<T> {
1927 fn deref_mut(&mut self) -> &mut Self::Target {
1928 &mut self.0
1929 }
1930}
1931
1932unsafe impl<T: SystemParam> SystemParam for If<T> {
1934 type State = T::State;
1935
1936 type Item<'world, 'state> = If<T::Item<'world, 'state>>;
1937
1938 fn init_state(world: &mut World) -> Self::State {
1939 T::init_state(world)
1940 }
1941
1942 fn init_access(
1943 state: &Self::State,
1944 system_meta: &mut SystemMeta,
1945 component_access_set: &mut FilteredAccessSet,
1946 world: &mut World,
1947 ) {
1948 T::init_access(state, system_meta, component_access_set, world);
1949 }
1950
1951 #[inline]
1952 unsafe fn validate_param(
1953 state: &mut Self::State,
1954 system_meta: &SystemMeta,
1955 world: UnsafeWorldCell,
1956 ) -> Result<(), SystemParamValidationError> {
1957 unsafe { T::validate_param(state, system_meta, world) }.map_err(|mut e| {
1959 e.skipped = true;
1960 e
1961 })
1962 }
1963
1964 #[inline]
1965 unsafe fn get_param<'world, 'state>(
1966 state: &'state mut Self::State,
1967 system_meta: &SystemMeta,
1968 world: UnsafeWorldCell<'world>,
1969 change_tick: Tick,
1970 ) -> Self::Item<'world, 'state> {
1971 If(unsafe { T::get_param(state, system_meta, world, change_tick) })
1973 }
1974
1975 fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) {
1976 T::apply(state, system_meta, world);
1977 }
1978
1979 fn queue(state: &mut Self::State, system_meta: &SystemMeta, world: DeferredWorld) {
1980 T::queue(state, system_meta, world);
1981 }
1982}
1983
1984unsafe impl<T: ReadOnlySystemParam> ReadOnlySystemParam for If<T> {}
1986
1987unsafe impl<T: SystemParam> SystemParam for Vec<T> {
1990 type State = Vec<T::State>;
1991
1992 type Item<'world, 'state> = Vec<T::Item<'world, 'state>>;
1993
1994 fn init_state(_world: &mut World) -> Self::State {
1995 Vec::new()
1996 }
1997
1998 fn init_access(
1999 state: &Self::State,
2000 system_meta: &mut SystemMeta,
2001 component_access_set: &mut FilteredAccessSet,
2002 world: &mut World,
2003 ) {
2004 for state in state {
2005 T::init_access(state, system_meta, component_access_set, world);
2006 }
2007 }
2008
2009 #[inline]
2010 unsafe fn validate_param(
2011 state: &mut Self::State,
2012 system_meta: &SystemMeta,
2013 world: UnsafeWorldCell,
2014 ) -> Result<(), SystemParamValidationError> {
2015 for state in state {
2016 unsafe { T::validate_param(state, system_meta, world)? };
2018 }
2019 Ok(())
2020 }
2021
2022 #[inline]
2023 unsafe fn get_param<'world, 'state>(
2024 state: &'state mut Self::State,
2025 system_meta: &SystemMeta,
2026 world: UnsafeWorldCell<'world>,
2027 change_tick: Tick,
2028 ) -> Self::Item<'world, 'state> {
2029 state
2030 .iter_mut()
2031 .map(|state| unsafe { T::get_param(state, system_meta, world, change_tick) })
2035 .collect()
2036 }
2037
2038 fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) {
2039 for state in state {
2040 T::apply(state, system_meta, world);
2041 }
2042 }
2043
2044 fn queue(state: &mut Self::State, system_meta: &SystemMeta, mut world: DeferredWorld) {
2045 for state in state {
2046 T::queue(state, system_meta, world.reborrow());
2047 }
2048 }
2049}
2050
2051unsafe impl<T: SystemParam> SystemParam for ParamSet<'_, '_, Vec<T>> {
2055 type State = Vec<T::State>;
2056
2057 type Item<'world, 'state> = ParamSet<'world, 'state, Vec<T>>;
2058
2059 fn init_state(_world: &mut World) -> Self::State {
2060 Vec::new()
2061 }
2062
2063 fn init_access(
2064 state: &Self::State,
2065 system_meta: &mut SystemMeta,
2066 component_access_set: &mut FilteredAccessSet,
2067 world: &mut World,
2068 ) {
2069 for state in state {
2070 let component_access_set_clone = &mut component_access_set.clone();
2072 T::init_access(state, system_meta, component_access_set_clone, world);
2073 }
2074 for state in state {
2075 let mut access_set = FilteredAccessSet::new();
2078 T::init_access(state, system_meta, &mut access_set, world);
2079 component_access_set.extend(access_set);
2080 }
2081 }
2082
2083 #[inline]
2084 unsafe fn get_param<'world, 'state>(
2085 state: &'state mut Self::State,
2086 system_meta: &SystemMeta,
2087 world: UnsafeWorldCell<'world>,
2088 change_tick: Tick,
2089 ) -> Self::Item<'world, 'state> {
2090 ParamSet {
2091 param_states: state,
2092 system_meta: system_meta.clone(),
2093 world,
2094 change_tick,
2095 }
2096 }
2097
2098 fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) {
2099 for state in state {
2100 T::apply(state, system_meta, world);
2101 }
2102 }
2103
2104 fn queue(state: &mut Self::State, system_meta: &SystemMeta, mut world: DeferredWorld) {
2105 for state in state {
2106 T::queue(state, system_meta, world.reborrow());
2107 }
2108 }
2109}
2110
2111impl<T: SystemParam> ParamSet<'_, '_, Vec<T>> {
2112 pub fn get_mut(&mut self, index: usize) -> T::Item<'_, '_> {
2115 unsafe {
2120 T::get_param(
2121 &mut self.param_states[index],
2122 &self.system_meta,
2123 self.world,
2124 self.change_tick,
2125 )
2126 }
2127 }
2128
2129 pub fn for_each(&mut self, mut f: impl FnMut(T::Item<'_, '_>)) {
2131 self.param_states.iter_mut().for_each(|state| {
2132 f(
2133 unsafe { T::get_param(state, &self.system_meta, self.world, self.change_tick) },
2138 );
2139 });
2140 }
2141}
2142
2143macro_rules! impl_system_param_tuple {
2144 ($(#[$meta:meta])* $($param: ident),*) => {
2145 $(#[$meta])*
2146 unsafe impl<$($param: ReadOnlySystemParam),*> ReadOnlySystemParam for ($($param,)*) {}
2148
2149 #[expect(
2150 clippy::allow_attributes,
2151 reason = "This is in a macro, and as such, the below lints may not always apply."
2152 )]
2153 #[allow(
2154 non_snake_case,
2155 reason = "Certain variable names are provided by the caller, not by us."
2156 )]
2157 #[allow(
2158 unused_variables,
2159 reason = "Zero-length tuples won't use some of the parameters."
2160 )]
2161 #[allow(clippy::unused_unit, reason = "Zero length tuple is unit.")]
2162 $(#[$meta])*
2163 unsafe impl<$($param: SystemParam),*> SystemParam for ($($param,)*) {
2165 type State = ($($param::State,)*);
2166 type Item<'w, 's> = ($($param::Item::<'w, 's>,)*);
2167
2168 #[inline]
2169 fn init_state(world: &mut World) -> Self::State {
2170 ($($param::init_state(world),)*)
2171 }
2172
2173 fn init_access(state: &Self::State, _system_meta: &mut SystemMeta, _component_access_set: &mut FilteredAccessSet, _world: &mut World) {
2174 let ($($param,)*) = state;
2175 $($param::init_access($param, _system_meta, _component_access_set, _world);)*
2176 }
2177
2178 #[inline]
2179 fn apply(($($param,)*): &mut Self::State, system_meta: &SystemMeta, world: &mut World) {
2180 $($param::apply($param, system_meta, world);)*
2181 }
2182
2183 #[inline]
2184 #[allow(
2185 unused_mut,
2186 reason = "The `world` parameter is unused for zero-length tuples; however, it must be mutable for other lengths of tuples."
2187 )]
2188 fn queue(($($param,)*): &mut Self::State, system_meta: &SystemMeta, mut world: DeferredWorld) {
2189 $($param::queue($param, system_meta, world.reborrow());)*
2190 }
2191
2192 #[inline]
2193 unsafe fn validate_param(
2194 state: &mut Self::State,
2195 system_meta: &SystemMeta,
2196 world: UnsafeWorldCell,
2197 ) -> Result<(), SystemParamValidationError> {
2198 let ($($param,)*) = state;
2199
2200 #[allow(
2201 unused_unsafe,
2202 reason = "Zero-length tuples won't have any params to validate."
2203 )]
2204 unsafe {
2206 $(
2207 $param::validate_param($param, system_meta, world)?;
2208 )*
2209 }
2210 Ok(())
2211 }
2212
2213 #[inline]
2214 unsafe fn get_param<'w, 's>(
2215 state: &'s mut Self::State,
2216 system_meta: &SystemMeta,
2217 world: UnsafeWorldCell<'w>,
2218 change_tick: Tick,
2219 ) -> Self::Item<'w, 's> {
2220 let ($($param,)*) = state;
2221
2222 #[allow(
2223 unused_unsafe,
2224 reason = "Zero-length tuples won't have any params to validate."
2225 )]
2226 unsafe {
2228 #[allow(
2229 clippy::unused_unit,
2230 reason = "Zero-length tuples won't have any params to get."
2231 )]
2232 ($($param::get_param($param, system_meta, world, change_tick),)*)
2233 }
2234 }
2235 }
2236 };
2237}
2238
2239all_tuples!(
2240 #[doc(fake_variadic)]
2241 impl_system_param_tuple,
2242 0,
2243 16,
2244 P
2245);
2246
2247pub mod lifetimeless {
2260 pub type SQuery<D, F = ()> = super::Query<'static, 'static, D, F>;
2262 pub type Read<T> = &'static T;
2264 pub type Write<T> = &'static mut T;
2266 pub type SRes<T> = super::Res<'static, T>;
2268 pub type SResMut<T> = super::ResMut<'static, T>;
2270 pub type SCommands = crate::system::Commands<'static, 'static>;
2272}
2273
2274pub struct StaticSystemParam<'w, 's, P: SystemParam>(SystemParamItem<'w, 's, P>);
2326
2327impl<'w, 's, P: SystemParam> Deref for StaticSystemParam<'w, 's, P> {
2328 type Target = SystemParamItem<'w, 's, P>;
2329
2330 fn deref(&self) -> &Self::Target {
2331 &self.0
2332 }
2333}
2334
2335impl<'w, 's, P: SystemParam> DerefMut for StaticSystemParam<'w, 's, P> {
2336 fn deref_mut(&mut self) -> &mut Self::Target {
2337 &mut self.0
2338 }
2339}
2340
2341impl<'w, 's, P: SystemParam> StaticSystemParam<'w, 's, P> {
2342 pub fn into_inner(self) -> SystemParamItem<'w, 's, P> {
2344 self.0
2345 }
2346}
2347
2348unsafe impl<'w, 's, P: ReadOnlySystemParam + 'static> ReadOnlySystemParam
2350 for StaticSystemParam<'w, 's, P>
2351{
2352}
2353
2354unsafe impl<P: SystemParam + 'static> SystemParam for StaticSystemParam<'_, '_, P> {
2356 type State = P::State;
2357 type Item<'world, 'state> = StaticSystemParam<'world, 'state, P>;
2358
2359 fn init_state(world: &mut World) -> Self::State {
2360 P::init_state(world)
2361 }
2362
2363 fn init_access(
2364 state: &Self::State,
2365 system_meta: &mut SystemMeta,
2366 component_access_set: &mut FilteredAccessSet,
2367 world: &mut World,
2368 ) {
2369 P::init_access(state, system_meta, component_access_set, world);
2370 }
2371
2372 fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) {
2373 P::apply(state, system_meta, world);
2374 }
2375
2376 fn queue(state: &mut Self::State, system_meta: &SystemMeta, world: DeferredWorld) {
2377 P::queue(state, system_meta, world);
2378 }
2379
2380 #[inline]
2381 unsafe fn validate_param(
2382 state: &mut Self::State,
2383 system_meta: &SystemMeta,
2384 world: UnsafeWorldCell,
2385 ) -> Result<(), SystemParamValidationError> {
2386 unsafe { P::validate_param(state, system_meta, world) }
2388 }
2389
2390 #[inline]
2391 unsafe fn get_param<'world, 'state>(
2392 state: &'state mut Self::State,
2393 system_meta: &SystemMeta,
2394 world: UnsafeWorldCell<'world>,
2395 change_tick: Tick,
2396 ) -> Self::Item<'world, 'state> {
2397 StaticSystemParam(unsafe { P::get_param(state, system_meta, world, change_tick) })
2399 }
2400}
2401
2402unsafe impl<T: ?Sized> SystemParam for PhantomData<T> {
2404 type State = ();
2405 type Item<'world, 'state> = Self;
2406
2407 fn init_state(_world: &mut World) -> Self::State {}
2408
2409 fn init_access(
2410 _state: &Self::State,
2411 _system_meta: &mut SystemMeta,
2412 _component_access_set: &mut FilteredAccessSet,
2413 _world: &mut World,
2414 ) {
2415 }
2416
2417 #[inline]
2418 unsafe fn get_param<'world, 'state>(
2419 _state: &'state mut Self::State,
2420 _system_meta: &SystemMeta,
2421 _world: UnsafeWorldCell<'world>,
2422 _change_tick: Tick,
2423 ) -> Self::Item<'world, 'state> {
2424 PhantomData
2425 }
2426}
2427
2428unsafe impl<T: ?Sized> ReadOnlySystemParam for PhantomData<T> {}
2430
2431pub struct DynSystemParam<'w, 's> {
2490 state: &'s mut dyn Any,
2492 world: UnsafeWorldCell<'w>,
2493 system_meta: SystemMeta,
2494 change_tick: Tick,
2495}
2496
2497impl<'w, 's> DynSystemParam<'w, 's> {
2498 unsafe fn new(
2505 state: &'s mut dyn Any,
2506 world: UnsafeWorldCell<'w>,
2507 system_meta: SystemMeta,
2508 change_tick: Tick,
2509 ) -> Self {
2510 Self {
2511 state,
2512 world,
2513 system_meta,
2514 change_tick,
2515 }
2516 }
2517
2518 pub fn is<T: SystemParam>(&self) -> bool
2520 where
2522 T::Item<'static, 'static>: SystemParam<Item<'w, 's> = T> + 'static,
2523 {
2524 self.state.is::<ParamState<T::Item<'static, 'static>>>()
2525 }
2526
2527 pub fn downcast<T: SystemParam>(self) -> Option<T>
2530 where
2532 T::Item<'static, 'static>: SystemParam<Item<'w, 's> = T> + 'static,
2533 {
2534 unsafe { downcast::<T>(self.state, &self.system_meta, self.world, self.change_tick) }
2539 }
2540
2541 pub fn downcast_mut<'a, T: SystemParam>(&'a mut self) -> Option<T>
2544 where
2546 T::Item<'static, 'static>: SystemParam<Item<'a, 'a> = T> + 'static,
2547 {
2548 unsafe { downcast::<T>(self.state, &self.system_meta, self.world, self.change_tick) }
2553 }
2554
2555 pub fn downcast_mut_inner<'a, T: ReadOnlySystemParam>(&'a mut self) -> Option<T>
2561 where
2563 T::Item<'static, 'static>: SystemParam<Item<'w, 'a> = T> + 'static,
2564 {
2565 unsafe { downcast::<T>(self.state, &self.system_meta, self.world, self.change_tick) }
2570 }
2571}
2572
2573unsafe fn downcast<'w, 's, T: SystemParam>(
2580 state: &'s mut dyn Any,
2581 system_meta: &SystemMeta,
2582 world: UnsafeWorldCell<'w>,
2583 change_tick: Tick,
2584) -> Option<T>
2585where
2594 T::Item<'static, 'static>: SystemParam<Item<'w, 's> = T> + 'static,
2595{
2596 state
2597 .downcast_mut::<ParamState<T::Item<'static, 'static>>>()
2598 .map(|state| {
2599 unsafe { T::Item::get_param(&mut state.0, system_meta, world, change_tick) }
2604 })
2605}
2606
2607pub struct DynSystemParamState(Box<dyn DynParamState>);
2609
2610impl DynSystemParamState {
2611 pub(crate) fn new<T: SystemParam + 'static>(state: T::State) -> Self {
2612 Self(Box::new(ParamState::<T>(state)))
2613 }
2614}
2615
2616trait DynParamState: Sync + Send + Any {
2618 fn apply(&mut self, system_meta: &SystemMeta, world: &mut World);
2623
2624 fn queue(&mut self, system_meta: &SystemMeta, world: DeferredWorld);
2626
2627 fn init_access(
2629 &self,
2630 system_meta: &mut SystemMeta,
2631 component_access_set: &mut FilteredAccessSet,
2632 world: &mut World,
2633 );
2634
2635 unsafe fn validate_param(
2640 &mut self,
2641 system_meta: &SystemMeta,
2642 world: UnsafeWorldCell,
2643 ) -> Result<(), SystemParamValidationError>;
2644}
2645
2646struct ParamState<T: SystemParam>(T::State);
2648
2649impl<T: SystemParam + 'static> DynParamState for ParamState<T> {
2650 fn apply(&mut self, system_meta: &SystemMeta, world: &mut World) {
2651 T::apply(&mut self.0, system_meta, world);
2652 }
2653
2654 fn queue(&mut self, system_meta: &SystemMeta, world: DeferredWorld) {
2655 T::queue(&mut self.0, system_meta, world);
2656 }
2657
2658 fn init_access(
2659 &self,
2660 system_meta: &mut SystemMeta,
2661 component_access_set: &mut FilteredAccessSet,
2662 world: &mut World,
2663 ) {
2664 T::init_access(&self.0, system_meta, component_access_set, world);
2665 }
2666
2667 unsafe fn validate_param(
2668 &mut self,
2669 system_meta: &SystemMeta,
2670 world: UnsafeWorldCell,
2671 ) -> Result<(), SystemParamValidationError> {
2672 unsafe { T::validate_param(&mut self.0, system_meta, world) }
2674 }
2675}
2676
2677unsafe impl SystemParam for DynSystemParam<'_, '_> {
2679 type State = DynSystemParamState;
2680
2681 type Item<'world, 'state> = DynSystemParam<'world, 'state>;
2682
2683 fn init_state(_world: &mut World) -> Self::State {
2684 DynSystemParamState::new::<()>(())
2685 }
2686
2687 fn init_access(
2688 state: &Self::State,
2689 system_meta: &mut SystemMeta,
2690 component_access_set: &mut FilteredAccessSet,
2691 world: &mut World,
2692 ) {
2693 state
2694 .0
2695 .init_access(system_meta, component_access_set, world);
2696 }
2697
2698 #[inline]
2699 unsafe fn validate_param(
2700 state: &mut Self::State,
2701 system_meta: &SystemMeta,
2702 world: UnsafeWorldCell,
2703 ) -> Result<(), SystemParamValidationError> {
2704 unsafe { state.0.validate_param(system_meta, world) }
2706 }
2707
2708 #[inline]
2709 unsafe fn get_param<'world, 'state>(
2710 state: &'state mut Self::State,
2711 system_meta: &SystemMeta,
2712 world: UnsafeWorldCell<'world>,
2713 change_tick: Tick,
2714 ) -> Self::Item<'world, 'state> {
2715 unsafe { DynSystemParam::new(state.0.as_mut(), world, system_meta.clone(), change_tick) }
2721 }
2722
2723 fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) {
2724 state.0.apply(system_meta, world);
2725 }
2726
2727 fn queue(state: &mut Self::State, system_meta: &SystemMeta, world: DeferredWorld) {
2728 state.0.queue(system_meta, world);
2729 }
2730}
2731
2732unsafe impl SystemParam for FilteredResources<'_, '_> {
2735 type State = Access;
2736
2737 type Item<'world, 'state> = FilteredResources<'world, 'state>;
2738
2739 fn init_state(_world: &mut World) -> Self::State {
2740 Access::new()
2741 }
2742
2743 fn init_access(
2744 access: &Self::State,
2745 system_meta: &mut SystemMeta,
2746 component_access_set: &mut FilteredAccessSet,
2747 world: &mut World,
2748 ) {
2749 let combined_access = component_access_set.combined_access();
2750 let conflicts = combined_access.get_conflicts(access);
2751 if !conflicts.is_empty() {
2752 let accesses = conflicts.format_conflict_list(world);
2753 let system_name = &system_meta.name;
2754 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");
2755 }
2756
2757 if access.has_read_all_resources() {
2758 component_access_set.add_unfiltered_read_all_resources();
2759 } else {
2760 for component_id in access.resource_reads_and_writes() {
2761 component_access_set.add_unfiltered_resource_read(component_id);
2762 }
2763 }
2764 }
2765
2766 unsafe fn get_param<'world, 'state>(
2767 state: &'state mut Self::State,
2768 system_meta: &SystemMeta,
2769 world: UnsafeWorldCell<'world>,
2770 change_tick: Tick,
2771 ) -> Self::Item<'world, 'state> {
2772 unsafe { FilteredResources::new(world, state, system_meta.last_run, change_tick) }
2775 }
2776}
2777
2778unsafe impl ReadOnlySystemParam for FilteredResources<'_, '_> {}
2780
2781unsafe impl SystemParam for FilteredResourcesMut<'_, '_> {
2784 type State = Access;
2785
2786 type Item<'world, 'state> = FilteredResourcesMut<'world, 'state>;
2787
2788 fn init_state(_world: &mut World) -> Self::State {
2789 Access::new()
2790 }
2791
2792 fn init_access(
2793 access: &Self::State,
2794 system_meta: &mut SystemMeta,
2795 component_access_set: &mut FilteredAccessSet,
2796 world: &mut World,
2797 ) {
2798 let combined_access = component_access_set.combined_access();
2799 let conflicts = combined_access.get_conflicts(access);
2800 if !conflicts.is_empty() {
2801 let accesses = conflicts.format_conflict_list(world);
2802 let system_name = &system_meta.name;
2803 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");
2804 }
2805
2806 if access.has_read_all_resources() {
2807 component_access_set.add_unfiltered_read_all_resources();
2808 } else {
2809 for component_id in access.resource_reads() {
2810 component_access_set.add_unfiltered_resource_read(component_id);
2811 }
2812 }
2813
2814 if access.has_write_all_resources() {
2815 component_access_set.add_unfiltered_write_all_resources();
2816 } else {
2817 for component_id in access.resource_writes() {
2818 component_access_set.add_unfiltered_resource_write(component_id);
2819 }
2820 }
2821 }
2822
2823 unsafe fn get_param<'world, 'state>(
2824 state: &'state mut Self::State,
2825 system_meta: &SystemMeta,
2826 world: UnsafeWorldCell<'world>,
2827 change_tick: Tick,
2828 ) -> Self::Item<'world, 'state> {
2829 unsafe { FilteredResourcesMut::new(world, state, system_meta.last_run, change_tick) }
2832 }
2833}
2834
2835#[derive(Debug, PartialEq, Eq, Clone, Error)]
2841pub struct SystemParamValidationError {
2842 pub skipped: bool,
2855
2856 pub message: Cow<'static, str>,
2858
2859 pub param: DebugName,
2862
2863 pub field: Cow<'static, str>,
2868}
2869
2870impl SystemParamValidationError {
2871 pub fn skipped<T>(message: impl Into<Cow<'static, str>>) -> Self {
2874 Self::new::<T>(true, message, Cow::Borrowed(""))
2875 }
2876
2877 pub fn invalid<T>(message: impl Into<Cow<'static, str>>) -> Self {
2880 Self::new::<T>(false, message, Cow::Borrowed(""))
2881 }
2882
2883 pub fn new<T>(
2886 skipped: bool,
2887 message: impl Into<Cow<'static, str>>,
2888 field: impl Into<Cow<'static, str>>,
2889 ) -> Self {
2890 Self {
2891 skipped,
2892 message: message.into(),
2893 param: DebugName::type_name::<T>(),
2894 field: field.into(),
2895 }
2896 }
2897
2898 pub(crate) const EMPTY: Self = Self {
2899 skipped: false,
2900 message: Cow::Borrowed(""),
2901 param: DebugName::borrowed(""),
2902 field: Cow::Borrowed(""),
2903 };
2904}
2905
2906impl Display for SystemParamValidationError {
2907 fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
2908 write!(
2909 fmt,
2910 "Parameter `{}{}` failed validation: {}",
2911 self.param.shortname(),
2912 self.field,
2913 self.message
2914 )?;
2915 if !self.skipped {
2916 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.")?;
2917 }
2918 Ok(())
2919 }
2920}
2921
2922#[cfg(test)]
2923mod tests {
2924 use super::*;
2925 use crate::system::assert_is_system;
2926 use core::cell::RefCell;
2927
2928 #[test]
2929 #[should_panic]
2930 fn non_send_alias() {
2931 #[derive(Resource)]
2932 struct A(usize);
2933 fn my_system(mut res0: NonSendMut<A>, mut res1: NonSendMut<A>) {
2934 res0.0 += 1;
2935 res1.0 += 1;
2936 }
2937 let mut world = World::new();
2938 world.insert_non_send_resource(A(42));
2939 let mut schedule = crate::schedule::Schedule::default();
2940 schedule.add_systems(my_system);
2941 schedule.run(&mut world);
2942 }
2943
2944 #[test]
2946 fn system_param_generic_bounds() {
2947 #[derive(SystemParam)]
2948 pub struct SpecialQuery<
2949 'w,
2950 's,
2951 D: QueryData + Send + Sync + 'static,
2952 F: QueryFilter + Send + Sync + 'static = (),
2953 > {
2954 _query: Query<'w, 's, D, F>,
2955 }
2956
2957 fn my_system(_: SpecialQuery<(), ()>) {}
2958 assert_is_system(my_system);
2959 }
2960
2961 #[test]
2963 fn system_param_flexibility() {
2964 #[derive(SystemParam)]
2965 pub struct SpecialRes<'w, T: Resource> {
2966 _res: Res<'w, T>,
2967 }
2968
2969 #[derive(SystemParam)]
2970 pub struct SpecialLocal<'s, T: FromWorld + Send + 'static> {
2971 _local: Local<'s, T>,
2972 }
2973
2974 #[derive(Resource)]
2975 struct R;
2976
2977 fn my_system(_: SpecialRes<R>, _: SpecialLocal<u32>) {}
2978 assert_is_system(my_system);
2979 }
2980
2981 #[derive(Resource)]
2982 pub struct R<const I: usize>;
2983
2984 #[test]
2986 fn system_param_const_generics() {
2987 #[expect(
2988 dead_code,
2989 reason = "This struct is used to ensure that const generics are supported as a SystemParam; thus, the inner value never needs to be read."
2990 )]
2991 #[derive(SystemParam)]
2992 pub struct ConstGenericParam<'w, const I: usize>(Res<'w, R<I>>);
2993
2994 fn my_system(_: ConstGenericParam<0>, _: ConstGenericParam<1000>) {}
2995 assert_is_system(my_system);
2996 }
2997
2998 #[test]
3000 fn system_param_field_limit() {
3001 #[derive(SystemParam)]
3002 pub struct LongParam<'w> {
3003 _r0: Res<'w, R<0>>,
3006 _r1: Res<'w, R<1>>,
3007 _r2: Res<'w, R<2>>,
3008 _r3: Res<'w, R<3>>,
3009 _r4: Res<'w, R<4>>,
3010 _r5: Res<'w, R<5>>,
3011 _r6: Res<'w, R<6>>,
3012 _r7: Res<'w, R<7>>,
3013 _r8: Res<'w, R<8>>,
3014 _r9: Res<'w, R<9>>,
3015 _r10: Res<'w, R<10>>,
3016 _r11: Res<'w, R<11>>,
3017 _r12: Res<'w, R<12>>,
3018 _r13: Res<'w, R<13>>,
3019 _r14: Res<'w, R<14>>,
3020 _r15: Res<'w, R<15>>,
3021 _r16: Res<'w, R<16>>,
3022 }
3023
3024 fn long_system(_: LongParam) {}
3025 assert_is_system(long_system);
3026 }
3027
3028 #[test]
3031 fn system_param_phantom_data() {
3032 #[derive(SystemParam)]
3033 struct PhantomParam<'w, T: Resource, Marker: 'static> {
3034 _foo: Res<'w, T>,
3035 marker: PhantomData<&'w Marker>,
3036 }
3037
3038 fn my_system(_: PhantomParam<R<0>, ()>) {}
3039 assert_is_system(my_system);
3040 }
3041
3042 #[test]
3044 fn system_param_struct_variants() {
3045 #[derive(SystemParam)]
3046 pub struct UnitParam;
3047
3048 #[expect(
3049 dead_code,
3050 reason = "This struct is used to ensure that tuple structs are supported as a SystemParam; thus, the inner values never need to be read."
3051 )]
3052 #[derive(SystemParam)]
3053 pub struct TupleParam<'w, 's, R: Resource, L: FromWorld + Send + 'static>(
3054 Res<'w, R>,
3055 Local<'s, L>,
3056 );
3057
3058 fn my_system(_: UnitParam, _: TupleParam<R<0>, u32>) {}
3059 assert_is_system(my_system);
3060 }
3061
3062 #[test]
3064 fn system_param_private_fields() {
3065 #[derive(Resource)]
3066 struct PrivateResource;
3067
3068 #[expect(
3069 dead_code,
3070 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."
3071 )]
3072 #[derive(SystemParam)]
3073 pub struct EncapsulatedParam<'w>(Res<'w, PrivateResource>);
3074
3075 fn my_system(_: EncapsulatedParam) {}
3076 assert_is_system(my_system);
3077 }
3078
3079 #[test]
3081 fn system_param_where_clause() {
3082 #[derive(SystemParam)]
3083 pub struct WhereParam<'w, 's, D>
3084 where
3085 D: 'static + QueryData,
3086 {
3087 _q: Query<'w, 's, D, ()>,
3088 }
3089
3090 fn my_system(_: WhereParam<()>) {}
3091 assert_is_system(my_system);
3092 }
3093
3094 #[test]
3096 fn system_param_name_collision() {
3097 #[derive(Resource)]
3098 pub struct FetchState;
3099
3100 #[derive(SystemParam)]
3101 pub struct Collide<'w> {
3102 _x: Res<'w, FetchState>,
3103 }
3104
3105 fn my_system(_: Collide) {}
3106 assert_is_system(my_system);
3107 }
3108
3109 #[test]
3111 fn system_param_invariant_lifetime() {
3112 #[derive(SystemParam)]
3113 pub struct InvariantParam<'w, 's> {
3114 _set: ParamSet<'w, 's, (Query<'w, 's, ()>,)>,
3115 }
3116
3117 fn my_system(_: InvariantParam) {}
3118 assert_is_system(my_system);
3119 }
3120
3121 #[test]
3123 fn non_sync_local() {
3124 fn non_sync_system(cell: Local<RefCell<u8>>) {
3125 assert_eq!(*cell.borrow(), 0);
3126 }
3127
3128 let mut world = World::new();
3129 let mut schedule = crate::schedule::Schedule::default();
3130 schedule.add_systems(non_sync_system);
3131 schedule.run(&mut world);
3132 }
3133
3134 #[test]
3136 fn param_set_non_send_first() {
3137 fn non_send_param_set(mut p: ParamSet<(NonSend<*mut u8>, ())>) {
3138 let _ = p.p0();
3139 p.p1();
3140 }
3141
3142 let mut world = World::new();
3143 world.insert_non_send_resource(core::ptr::null_mut::<u8>());
3144 let mut schedule = crate::schedule::Schedule::default();
3145 schedule.add_systems((non_send_param_set, non_send_param_set, non_send_param_set));
3146 schedule.run(&mut world);
3147 }
3148
3149 #[test]
3151 fn param_set_non_send_second() {
3152 fn non_send_param_set(mut p: ParamSet<((), NonSendMut<*mut u8>)>) {
3153 p.p0();
3154 let _ = p.p1();
3155 }
3156
3157 let mut world = World::new();
3158 world.insert_non_send_resource(core::ptr::null_mut::<u8>());
3159 let mut schedule = crate::schedule::Schedule::default();
3160 schedule.add_systems((non_send_param_set, non_send_param_set, non_send_param_set));
3161 schedule.run(&mut world);
3162 }
3163
3164 fn _dyn_system_param_type_inference(mut p: DynSystemParam) {
3165 let _query: Query<()> = p.downcast_mut().unwrap();
3168 let _query: Query<()> = p.downcast_mut_inner().unwrap();
3169 let _query: Query<()> = p.downcast().unwrap();
3170 }
3171
3172 #[test]
3173 #[should_panic]
3174 fn missing_resource_error() {
3175 #[derive(Resource)]
3176 pub struct MissingResource;
3177
3178 let mut schedule = crate::schedule::Schedule::default();
3179 schedule.add_systems(res_system);
3180 let mut world = World::new();
3181 schedule.run(&mut world);
3182
3183 fn res_system(_: Res<MissingResource>) {}
3184 }
3185
3186 #[test]
3187 #[should_panic]
3188 fn missing_message_error() {
3189 use crate::prelude::{Message, MessageReader};
3190
3191 #[derive(Message)]
3192 pub struct MissingEvent;
3193
3194 let mut schedule = crate::schedule::Schedule::default();
3195 schedule.add_systems(message_system);
3196 let mut world = World::new();
3197 schedule.run(&mut world);
3198
3199 fn message_system(_: MessageReader<MissingEvent>) {}
3200 }
3201}