1#![expect(
2 unsafe_op_in_unsafe_fn,
3 reason = "See #11590. To be removed once all applicable unsafe code has an unsafe block with a safety comment."
4)]
5
6pub use crate::change_detection::{NonSend, NonSendMut, Res, ResMut};
7use crate::{
8 archetype::Archetypes,
9 bundle::Bundles,
10 change_detection::{ComponentTicksMut, ComponentTicksRef, Tick},
11 component::{ComponentId, Components, Mutable},
12 entity::{Entities, EntityAllocator},
13 query::{
14 Access, FilteredAccess, IterQueryData, QueryData, QueryFilter, QuerySingleError,
15 QueryState, ReadOnlyQueryData,
16 },
17 resource::{Resource, ResourceEntities, IS_RESOURCE},
18 system::{Query, Single, SystemAccess, SystemMeta, SystemState},
19 world::{unsafe_world_cell::UnsafeWorldCell, DeferredWorld, FromWorld, World},
20};
21
22#[expect(deprecated, reason = "`FilteredResources` will be removed.")]
23use crate::world::{FilteredResources, FilteredResourcesMut};
24
25use alloc::{borrow::Cow, boxed::Box, vec::Vec};
26pub use bevy_ecs_macros::SystemParam;
27use bevy_platform::cell::SyncCell;
28use bevy_ptr::UnsafeCellDeref;
29use bevy_utils::prelude::DebugName;
30use core::{
31 any::Any,
32 fmt::{Debug, Display},
33 marker::PhantomData,
34 ops::{Deref, DerefMut},
35};
36use smallvec::SmallVec;
37use thiserror::Error;
38
39use super::Populated;
40use variadics_please::{all_tuples, all_tuples_enumerated};
41
42pub unsafe trait SystemParam: Sized {
220 type State: Send + Sync + 'static;
222
223 type Item<'world, 'state>: SystemParam<State = Self::State>;
228
229 fn init_state(world: &mut World) -> Self::State;
231
232 fn init_access(
237 state: &Self::State,
238 system_meta: &mut SystemMeta,
239 system_access: &mut SystemAccess,
240 world: &mut World,
241 );
242
243 #[inline]
248 #[expect(
249 unused_variables,
250 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."
251 )]
252 fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) {}
253
254 #[inline]
256 #[expect(
257 unused_variables,
258 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."
259 )]
260 fn queue(state: &mut Self::State, system_meta: &SystemMeta, world: DeferredWorld) {}
261
262 unsafe fn get_param<'world, 'state>(
284 state: &'state mut Self::State,
285 system_meta: &SystemMeta,
286 world: UnsafeWorldCell<'world>,
287 change_tick: Tick,
288 ) -> Result<Self::Item<'world, 'state>, SystemParamValidationError>;
289}
290
291pub unsafe trait ReadOnlySystemParam: SystemParam {}
296
297pub type SystemParamItem<'w, 's, P> = <P as SystemParam>::Item<'w, 's>;
299
300unsafe impl<'w, 's, D: ReadOnlyQueryData + 'static, F: QueryFilter + 'static> ReadOnlySystemParam
302 for Query<'w, 's, D, F>
303{
304}
305
306unsafe impl<D: QueryData + 'static, F: QueryFilter + 'static> SystemParam for Query<'_, '_, D, F> {
309 type State = QueryState<D, F>;
310 type Item<'w, 's> = Query<'w, 's, D, F>;
311
312 fn init_state(world: &mut World) -> Self::State {
313 unsafe { QueryState::new_unchecked(world) }
317 }
318
319 fn init_access(
320 state: &Self::State,
321 system_meta: &mut SystemMeta,
322 system_access: &mut SystemAccess,
323 world: &mut World,
324 ) {
325 let component_access_set = system_access.require_shared_access::<Self>(system_meta);
326 state.init_access(Some(system_meta.name()), component_access_set, world.into());
327 }
328
329 #[inline]
330 unsafe fn get_param<'w, 's>(
331 state: &'s mut Self::State,
332 system_meta: &SystemMeta,
333 world: UnsafeWorldCell<'w>,
334 change_tick: Tick,
335 ) -> Result<Self::Item<'w, 's>, SystemParamValidationError> {
336 Ok(unsafe { state.query_unchecked_with_ticks(world, system_meta.last_run, change_tick) })
341 }
342}
343
344unsafe impl<'a, 'b, D: IterQueryData + 'static, F: QueryFilter + 'static> SystemParam
347 for Single<'a, 'b, D, F>
348{
349 type State = QueryState<D, F>;
350 type Item<'w, 's> = Single<'w, 's, D, F>;
351
352 fn init_state(world: &mut World) -> Self::State {
353 Query::init_state(world)
354 }
355
356 fn init_access(
357 state: &Self::State,
358 system_meta: &mut SystemMeta,
359 system_access: &mut SystemAccess,
360 world: &mut World,
361 ) {
362 Query::init_access(state, system_meta, system_access, world);
363 }
364
365 #[inline]
366 unsafe fn get_param<'w, 's>(
367 state: &'s mut Self::State,
368 system_meta: &SystemMeta,
369 world: UnsafeWorldCell<'w>,
370 change_tick: Tick,
371 ) -> Result<Self::Item<'w, 's>, SystemParamValidationError> {
372 let query =
375 unsafe { state.query_unchecked_with_ticks(world, system_meta.last_run, change_tick) };
376 match query.single_inner() {
377 Ok(single) => Ok(Single {
378 item: single,
379 _filter: PhantomData,
380 }),
381 Err(QuerySingleError::NoEntities(_)) => Err(
382 SystemParamValidationError::skipped::<Self>("No matching entities"),
383 ),
384 Err(QuerySingleError::MultipleEntities(_)) => Err(
385 SystemParamValidationError::skipped::<Self>("Multiple matching entities"),
386 ),
387 }
388 }
389}
390
391unsafe impl<'a, 'b, D: ReadOnlyQueryData + 'static, F: QueryFilter + 'static> ReadOnlySystemParam
393 for Single<'a, 'b, D, F>
394{
395}
396
397unsafe impl<D: QueryData + 'static, F: QueryFilter + 'static> SystemParam
400 for Populated<'_, '_, D, F>
401{
402 type State = QueryState<D, F>;
403 type Item<'w, 's> = Populated<'w, 's, D, F>;
404
405 fn init_state(world: &mut World) -> Self::State {
406 Query::init_state(world)
407 }
408
409 fn init_access(
410 state: &Self::State,
411 system_meta: &mut SystemMeta,
412 system_access: &mut SystemAccess,
413 world: &mut World,
414 ) {
415 Query::init_access(state, system_meta, system_access, world);
416 }
417
418 #[inline]
419 unsafe fn get_param<'w, 's>(
420 state: &'s mut Self::State,
421 system_meta: &SystemMeta,
422 world: UnsafeWorldCell<'w>,
423 change_tick: Tick,
424 ) -> Result<Self::Item<'w, 's>, SystemParamValidationError> {
425 let query = unsafe { Query::get_param(state, system_meta, world, change_tick) }?;
427 if query.is_empty() {
428 Err(SystemParamValidationError::skipped::<Self>(
429 "No matching entities",
430 ))
431 } else {
432 Ok(Populated(query))
433 }
434 }
435}
436
437unsafe impl<'w, 's, D: ReadOnlyQueryData + 'static, F: QueryFilter + 'static> ReadOnlySystemParam
439 for Populated<'w, 's, D, F>
440{
441}
442
443pub struct ParamSet<'w, 's, T: SystemParam> {
559 param_states: &'s mut T::State,
560 world: UnsafeWorldCell<'w>,
561 system_meta: SystemMeta,
562 change_tick: Tick,
563}
564
565macro_rules! impl_param_set {
566 ($(($index: tt, $param: ident, $fn_name: ident)),*) => {
567 unsafe impl<'w, 's, $($param,)*> ReadOnlySystemParam for ParamSet<'w, 's, ($($param,)*)>
569 where $($param: ReadOnlySystemParam,)*
570 { }
571
572 unsafe impl<'_w, '_s, $($param: SystemParam,)*> SystemParam for ParamSet<'_w, '_s, ($($param,)*)>
575 {
576 type State = ($($param::State,)*);
577 type Item<'w, 's> = ParamSet<'w, 's, ($($param,)*)>;
578
579 #[expect(
580 clippy::allow_attributes,
581 reason = "This is inside a macro meant for tuples; as such, `non_snake_case` won't always lint."
582 )]
583 #[allow(
584 non_snake_case,
585 reason = "Certain variable names are provided by the caller, not by us."
586 )]
587 fn init_state(world: &mut World) -> Self::State {
588 ($($param::init_state(world),)*)
589 }
590
591 #[expect(
592 clippy::allow_attributes,
593 reason = "This is inside a macro meant for tuples; as such, `non_snake_case` won't always lint."
594 )]
595 #[allow(
596 non_snake_case,
597 reason = "Certain variable names are provided by the caller, not by us."
598 )]
599 fn init_access(state: &Self::State, system_meta: &mut SystemMeta, system_access: &mut SystemAccess, world: &mut World) {
600 let ($($param,)*) = state;
601 $(
602 let system_access_clone = &mut system_access.clone();
604 $param::init_access($param, system_meta, system_access_clone, world);
605 )*
606 $(
607 let mut param_access = SystemAccess::default();
610 $param::init_access($param, system_meta, &mut param_access, world);
611 system_access.extend(param_access);
612 )*
613 }
614
615 fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) {
616 <($($param,)*) as SystemParam>::apply(state, system_meta, world);
617 }
618
619 fn queue(state: &mut Self::State, system_meta: &SystemMeta, mut world: DeferredWorld) {
620 <($($param,)*) as SystemParam>::queue(state, system_meta, world.reborrow());
621 }
622
623 #[inline]
624 unsafe fn get_param<'w, 's>(
625 state: &'s mut Self::State,
626 system_meta: &SystemMeta,
627 world: UnsafeWorldCell<'w>,
628 change_tick: Tick,
629 ) -> Result<Self::Item<'w, 's>, SystemParamValidationError> {
630 $(
636 drop(unsafe { $param::get_param(&mut state.$index, system_meta, world, change_tick) }?);
638 )*
639
640 Ok(ParamSet {
641 param_states: state,
642 system_meta: system_meta.clone(),
643 world,
644 change_tick,
645 })
646 }
647 }
648
649 impl<'w, 's, $($param: SystemParam,)*> ParamSet<'w, 's, ($($param,)*)>
650 {
651 $(
652 #[doc = stringify!($index)]
654 pub fn $fn_name<'a>(&'a mut self) -> SystemParamItem<'a, 'a, $param> {
657 unsafe {
661 $param::get_param(&mut self.param_states.$index, &self.system_meta, self.world, self.change_tick)
662 }
663 .unwrap_or_else(|err| panic!("ParamSet parameter validation failed: {err}"))
664 }
665 )*
666 }
667 }
668}
669
670all_tuples_enumerated!(impl_param_set, 1, 8, P, p);
671
672unsafe impl<'a, T: Resource> ReadOnlySystemParam for Res<'a, T> {}
674
675unsafe impl<'a, T: Resource> SystemParam for Res<'a, T> {
678 type State = ComponentId;
679 type Item<'w, 's> = Res<'w, T>;
680
681 fn init_state(world: &mut World) -> Self::State {
682 world.components_registrator().register_component::<T>()
683 }
684
685 fn init_access(
686 &component_id: &Self::State,
687 system_meta: &mut SystemMeta,
688 system_access: &mut SystemAccess,
689 world: &mut World,
690 ) {
691 let mut filter = FilteredAccess::default();
692 filter.add_read(component_id);
693 filter.and_with(IS_RESOURCE);
694
695 if let Err(conflicts) = system_access.try_add(filter) {
696 let mut accesses = conflicts.format_conflict_list(world.as_unsafe_world_cell());
697 if !accesses.is_empty() {
699 accesses.push(' ');
700 }
701 panic!("error[B0002]: Res<{}> in system {} conflicts with a previous system parameter. Consider removing the duplicate access using `Without<IsResource>` to create disjoint Queries or merging conflicting Queries into a `ParamSet`. See: https://bevy.org/learn/errors/b0002", DebugName::type_name::<T>(), system_meta.name);
702 }
703 }
704
705 #[inline]
706 unsafe fn get_param<'w, 's>(
707 &mut component_id: &'s mut Self::State,
708 system_meta: &SystemMeta,
709 world: UnsafeWorldCell<'w>,
710 change_tick: Tick,
711 ) -> Result<Self::Item<'w, 's>, SystemParamValidationError> {
712 let (ptr, ticks) = world.get_resource_with_ticks(component_id).ok_or_else(|| {
713 SystemParamValidationError::invalid::<Self>("Resource does not exist")
714 })?;
715 Ok(Res {
716 value: ptr.deref(),
717 ticks: ComponentTicksRef {
718 added: ticks.added.deref(),
719 changed: ticks.changed.deref(),
720 changed_by: ticks.changed_by.map(|changed_by| changed_by.deref()),
721 last_run: system_meta.last_run,
722 this_run: change_tick,
723 },
724 })
725 }
726}
727
728unsafe impl<'a, T: Resource<Mutability = Mutable>> SystemParam for ResMut<'a, T> {
731 type State = ComponentId;
732 type Item<'w, 's> = ResMut<'w, T>;
733
734 fn init_state(world: &mut World) -> Self::State {
735 world.components_registrator().register_component::<T>()
736 }
737
738 fn init_access(
739 &component_id: &Self::State,
740 system_meta: &mut SystemMeta,
741 system_access: &mut SystemAccess,
742 world: &mut World,
743 ) {
744 let mut filter = FilteredAccess::default();
745 filter.add_write(component_id);
746 filter.and_with(IS_RESOURCE);
747
748 if let Err(conflicts) = system_access.try_add(filter) {
749 let mut accesses = conflicts.format_conflict_list(world.as_unsafe_world_cell());
750 if !accesses.is_empty() {
752 accesses.push(' ');
753 }
754 panic!("error[B0002]: ResMut<{}> in system {} conflicts with a previous system parameter. Consider removing the duplicate access or using `Without<IsResource>` to create disjoint Queries or merging conflicting Queries into a `ParamSet`. See: https://bevy.org/learn/errors/b0002", DebugName::type_name::<T>(), system_meta.name);
755 }
756 }
757
758 #[inline]
759 unsafe fn get_param<'w, 's>(
760 &mut component_id: &'s mut Self::State,
761 system_meta: &SystemMeta,
762 world: UnsafeWorldCell<'w>,
763 change_tick: Tick,
764 ) -> Result<Self::Item<'w, 's>, SystemParamValidationError> {
765 let value = world.get_resource_mut_by_id(component_id).ok_or_else(|| {
766 SystemParamValidationError::invalid::<Self>("Resource does not exist")
767 })?;
768 Ok(ResMut {
769 value: value.value.deref_mut::<T>(),
770 ticks: ComponentTicksMut {
771 added: value.ticks.added,
772 changed: value.ticks.changed,
773 changed_by: value.ticks.changed_by,
774 last_run: system_meta.last_run,
775 this_run: change_tick,
776 summary_tick: None,
777 },
778 })
779 }
780}
781
782unsafe impl<'w> ReadOnlySystemParam for &'w World {}
784
785unsafe impl SystemParam for &'_ World {
787 type State = ();
788 type Item<'w, 's> = &'w World;
789
790 fn init_state(_world: &mut World) -> Self::State {}
791
792 fn init_access(
793 _state: &Self::State,
794 system_meta: &mut SystemMeta,
795 system_access: &mut SystemAccess,
796 _world: &mut World,
797 ) {
798 let mut filtered_access = FilteredAccess::default();
799 filtered_access.read_all();
800
801 if system_access.try_add(filtered_access).is_err() {
802 panic!(
803 "&World in system {} conflicts with a previous system parameter's access.",
804 system_meta.name,
805 );
806 }
807 }
808
809 #[inline]
810 unsafe fn get_param<'w, 's>(
811 _state: &'s mut Self::State,
812 _system_meta: &SystemMeta,
813 world: UnsafeWorldCell<'w>,
814 _change_tick: Tick,
815 ) -> Result<Self::Item<'w, 's>, SystemParamValidationError> {
816 Ok(unsafe { world.world() })
818 }
819}
820
821unsafe impl SystemParam for &'_ mut World {
823 type State = ();
824 type Item<'world, 'state> = &'world mut World;
825
826 fn init_state(_world: &mut World) -> Self::State {}
827
828 fn init_access(
829 _state: &Self::State,
830 system_meta: &mut SystemMeta,
831 system_access: &mut SystemAccess,
832 _world: &mut World,
833 ) {
834 system_meta.set_non_send();
836
837 system_access.require_exclusive_access::<Self>(system_meta);
838 }
839
840 #[inline]
841 unsafe fn get_param<'world, 'state>(
842 _state: &'state mut Self::State,
843 _system_meta: &SystemMeta,
844 world: UnsafeWorldCell<'world>,
845 _change_tick: Tick,
846 ) -> Result<Self::Item<'world, 'state>, SystemParamValidationError> {
847 Ok(unsafe { world.world_mut() })
849 }
850}
851
852unsafe impl<'w> SystemParam for DeferredWorld<'w> {
854 type State = ();
855 type Item<'world, 'state> = DeferredWorld<'world>;
856
857 fn init_state(_world: &mut World) -> Self::State {}
858
859 fn init_access(
860 _state: &Self::State,
861 system_meta: &mut SystemMeta,
862 system_access: &mut SystemAccess,
863 _world: &mut World,
864 ) {
865 let mut filtered_access = FilteredAccess::default();
866 filtered_access.write_all();
867
868 if system_access.try_add(filtered_access).is_err() {
869 panic!(
870 "DeferredWorld in system {} conflicts with a previous system parameter's access.",
871 system_meta.name,
872 );
873 }
874 }
875
876 unsafe fn get_param<'world, 'state>(
877 _state: &'state mut Self::State,
878 _system_meta: &SystemMeta,
879 world: UnsafeWorldCell<'world>,
880 _change_tick: Tick,
881 ) -> Result<Self::Item<'world, 'state>, SystemParamValidationError> {
882 Ok(unsafe { world.into_deferred() })
884 }
885}
886
887#[derive(Debug)]
1004pub struct Local<'s, T: FromWorld + Send + 'static>(pub(crate) &'s mut T);
1005
1006unsafe impl<'s, T: FromWorld + Send + 'static> ReadOnlySystemParam for Local<'s, T> {}
1008
1009impl<'s, T: FromWorld + Send + 'static> Deref for Local<'s, T> {
1010 type Target = T;
1011
1012 #[inline]
1013 fn deref(&self) -> &Self::Target {
1014 self.0
1015 }
1016}
1017
1018impl<'s, T: FromWorld + Send + 'static> DerefMut for Local<'s, T> {
1019 #[inline]
1020 fn deref_mut(&mut self) -> &mut Self::Target {
1021 self.0
1022 }
1023}
1024
1025impl<'s, 'a, T: FromWorld + Send + 'static> IntoIterator for &'a Local<'s, T>
1026where
1027 &'a T: IntoIterator,
1028{
1029 type Item = <&'a T as IntoIterator>::Item;
1030 type IntoIter = <&'a T as IntoIterator>::IntoIter;
1031
1032 fn into_iter(self) -> Self::IntoIter {
1033 self.0.into_iter()
1034 }
1035}
1036
1037impl<'s, 'a, T: FromWorld + Send + 'static> IntoIterator for &'a mut Local<'s, T>
1038where
1039 &'a mut T: IntoIterator,
1040{
1041 type Item = <&'a mut T as IntoIterator>::Item;
1042 type IntoIter = <&'a mut T as IntoIterator>::IntoIter;
1043
1044 fn into_iter(self) -> Self::IntoIter {
1045 self.0.into_iter()
1046 }
1047}
1048
1049unsafe impl<'a, T: FromWorld + Send + 'static> SystemParam for Local<'a, T> {
1051 type State = SyncCell<T>;
1052 type Item<'w, 's> = Local<'s, T>;
1053
1054 fn init_state(world: &mut World) -> Self::State {
1055 SyncCell::new(T::from_world(world))
1056 }
1057
1058 fn init_access(
1059 _state: &Self::State,
1060 _system_meta: &mut SystemMeta,
1061 _system_access: &mut SystemAccess,
1062 _world: &mut World,
1063 ) {
1064 }
1065
1066 #[inline]
1067 unsafe fn get_param<'w, 's>(
1068 state: &'s mut Self::State,
1069 _system_meta: &SystemMeta,
1070 _world: UnsafeWorldCell<'w>,
1071 _change_tick: Tick,
1072 ) -> Result<Self::Item<'w, 's>, SystemParamValidationError> {
1073 Ok(Local(state.get()))
1074 }
1075}
1076
1077pub trait SystemBuffer: FromWorld + Send + 'static {
1084 fn apply(&mut self, system_meta: &SystemMeta, world: &mut World) {
1086 self.queue(system_meta, world.into());
1087 }
1088 fn queue(&mut self, _system_meta: &SystemMeta, _world: DeferredWorld);
1093}
1094
1095pub struct Deferred<'a, T: SystemBuffer>(pub(crate) &'a mut T);
1216
1217impl<'a, T: SystemBuffer> Deref for Deferred<'a, T> {
1218 type Target = T;
1219 #[inline]
1220 fn deref(&self) -> &Self::Target {
1221 self.0
1222 }
1223}
1224
1225impl<'a, T: SystemBuffer> DerefMut for Deferred<'a, T> {
1226 #[inline]
1227 fn deref_mut(&mut self) -> &mut Self::Target {
1228 self.0
1229 }
1230}
1231
1232impl<T: SystemBuffer> Deferred<'_, T> {
1233 pub fn reborrow(&mut self) -> Deferred<'_, T> {
1236 Deferred(self.0)
1237 }
1238}
1239
1240unsafe impl<T: SystemBuffer> ReadOnlySystemParam for Deferred<'_, T> {}
1242
1243unsafe impl<T: SystemBuffer> SystemParam for Deferred<'_, T> {
1245 type State = SyncCell<T>;
1246 type Item<'w, 's> = Deferred<'s, T>;
1247
1248 #[track_caller]
1249 fn init_state(world: &mut World) -> Self::State {
1250 SyncCell::new(T::from_world(world))
1251 }
1252
1253 fn init_access(
1254 _state: &Self::State,
1255 system_meta: &mut SystemMeta,
1256 _system_access: &mut SystemAccess,
1257 _world: &mut World,
1258 ) {
1259 system_meta.set_has_deferred();
1260 }
1261
1262 fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) {
1263 state.get().apply(system_meta, world);
1264 }
1265
1266 fn queue(state: &mut Self::State, system_meta: &SystemMeta, world: DeferredWorld) {
1267 state.get().queue(system_meta, world);
1268 }
1269
1270 #[inline]
1271 unsafe fn get_param<'w, 's>(
1272 state: &'s mut Self::State,
1273 _system_meta: &SystemMeta,
1274 _world: UnsafeWorldCell<'w>,
1275 _change_tick: Tick,
1276 ) -> Result<Self::Item<'w, 's>, SystemParamValidationError> {
1277 Ok(Deferred(state.get()))
1278 }
1279}
1280
1281pub struct NonSendMarker(PhantomData<*mut ()>);
1283
1284unsafe impl SystemParam for NonSendMarker {
1286 type State = ();
1287 type Item<'w, 's> = Self;
1288
1289 #[inline]
1290 fn init_state(_world: &mut World) -> Self::State {}
1291
1292 fn init_access(
1293 _state: &Self::State,
1294 system_meta: &mut SystemMeta,
1295 _system_access: &mut SystemAccess,
1296 _world: &mut World,
1297 ) {
1298 system_meta.set_non_send();
1299 }
1300
1301 #[inline]
1302 unsafe fn get_param<'world, 'state>(
1303 _state: &'state mut Self::State,
1304 _system_meta: &SystemMeta,
1305 _world: UnsafeWorldCell<'world>,
1306 _change_tick: Tick,
1307 ) -> Result<Self::Item<'world, 'state>, SystemParamValidationError> {
1308 Ok(Self(PhantomData))
1309 }
1310}
1311
1312unsafe impl ReadOnlySystemParam for NonSendMarker {}
1314
1315unsafe impl<'w, T> ReadOnlySystemParam for NonSend<'w, T> {}
1317
1318unsafe impl<'a, T: 'static> SystemParam for NonSend<'a, T> {
1321 type State = ComponentId;
1322 type Item<'w, 's> = NonSend<'w, T>;
1323
1324 fn init_state(world: &mut World) -> Self::State {
1325 world.components_registrator().register_non_send::<T>()
1326 }
1327
1328 fn init_access(
1329 &component_id: &Self::State,
1330 system_meta: &mut SystemMeta,
1331 system_access: &mut SystemAccess,
1332 _world: &mut World,
1333 ) {
1334 system_meta.set_non_send();
1335
1336 let mut filtered_access = FilteredAccess::default();
1337 filtered_access.add_read(component_id);
1338
1339 if system_access.try_add(filtered_access).is_err() {
1340 panic!(
1341 "error[B0002]: NonSend<{}> in system {} conflicts with a previous system parameter's access. Consider removing the duplicate access. See: https://bevy.org/learn/errors/b0002",
1342 DebugName::type_name::<T>(), system_meta.name,
1343 );
1344 }
1345 }
1346
1347 #[inline]
1348 unsafe fn get_param<'w, 's>(
1349 &mut component_id: &'s mut Self::State,
1350 system_meta: &SystemMeta,
1351 world: UnsafeWorldCell<'w>,
1352 change_tick: Tick,
1353 ) -> Result<Self::Item<'w, 's>, SystemParamValidationError> {
1354 let (ptr, ticks) = world.get_non_send_with_ticks(component_id).ok_or_else(|| {
1355 SystemParamValidationError::invalid::<Self>("Non-send data not found")
1356 })?;
1357 Ok(NonSend {
1358 value: ptr.deref(),
1359 ticks: ComponentTicksRef::from_tick_cells(ticks, system_meta.last_run, change_tick),
1360 })
1361 }
1362}
1363
1364unsafe impl<'a, T: 'static> SystemParam for NonSendMut<'a, T> {
1367 type State = ComponentId;
1368 type Item<'w, 's> = NonSendMut<'w, T>;
1369
1370 fn init_state(world: &mut World) -> Self::State {
1371 world.components_registrator().register_non_send::<T>()
1372 }
1373
1374 fn init_access(
1375 &component_id: &Self::State,
1376 system_meta: &mut SystemMeta,
1377 system_access: &mut SystemAccess,
1378 _world: &mut World,
1379 ) {
1380 system_meta.set_non_send();
1381
1382 let mut filtered_access = FilteredAccess::default();
1383 filtered_access.add_write(component_id);
1384
1385 if system_access.try_add(filtered_access).is_err() {
1386 panic!(
1387 "error[B0002]: NonSendMut<{}> in system {} conflicts with a previous system parameter's access. Consider removing the duplicate access. See: https://bevy.org/learn/errors/b0002",
1388 DebugName::type_name::<T>(), system_meta.name,
1389 );
1390 }
1391 }
1392
1393 #[inline]
1394 unsafe fn get_param<'w, 's>(
1395 &mut component_id: &'s mut Self::State,
1396 system_meta: &SystemMeta,
1397 world: UnsafeWorldCell<'w>,
1398 change_tick: Tick,
1399 ) -> Result<Self::Item<'w, 's>, SystemParamValidationError> {
1400 let (ptr, ticks) = world.get_non_send_with_ticks(component_id).ok_or_else(|| {
1401 SystemParamValidationError::invalid::<Self>("Non-send data not found")
1402 })?;
1403 Ok(NonSendMut {
1404 value: ptr.assert_unique().deref_mut(),
1405 ticks: ComponentTicksMut::from_tick_cells(ticks, system_meta.last_run, change_tick),
1406 })
1407 }
1408}
1409
1410unsafe impl<'a> ReadOnlySystemParam for &'a Archetypes {}
1412
1413unsafe impl<'a> SystemParam for &'a Archetypes {
1415 type State = ();
1416 type Item<'w, 's> = &'w Archetypes;
1417
1418 fn init_state(_world: &mut World) -> Self::State {}
1419
1420 fn init_access(
1421 _state: &Self::State,
1422 system_meta: &mut SystemMeta,
1423 system_access: &mut SystemAccess,
1424 _world: &mut World,
1425 ) {
1426 system_access.require_shared_access::<Self>(system_meta);
1427 }
1428
1429 #[inline]
1430 unsafe fn get_param<'w, 's>(
1431 _state: &'s mut Self::State,
1432 _system_meta: &SystemMeta,
1433 world: UnsafeWorldCell<'w>,
1434 _change_tick: Tick,
1435 ) -> Result<Self::Item<'w, 's>, SystemParamValidationError> {
1436 Ok(world.archetypes())
1437 }
1438}
1439
1440unsafe impl<'a> ReadOnlySystemParam for &'a ResourceEntities {}
1442
1443unsafe impl<'a> SystemParam for &'a ResourceEntities {
1445 type State = ();
1446 type Item<'w, 's> = &'w ResourceEntities;
1447
1448 fn init_state(_world: &mut World) -> Self::State {}
1449
1450 fn init_access(
1451 _state: &Self::State,
1452 system_meta: &mut SystemMeta,
1453 system_access: &mut SystemAccess,
1454 _world: &mut World,
1455 ) {
1456 system_access.require_shared_access::<Self>(system_meta);
1457 }
1458
1459 #[inline]
1460 unsafe fn get_param<'w, 's>(
1461 _state: &'s mut Self::State,
1462 _system_meta: &SystemMeta,
1463 world: UnsafeWorldCell<'w>,
1464 _change_tick: Tick,
1465 ) -> Result<Self::Item<'w, 's>, SystemParamValidationError> {
1466 Ok(world.resource_entities())
1467 }
1468}
1469
1470unsafe impl<'a> ReadOnlySystemParam for &'a Components {}
1472
1473unsafe impl<'a> SystemParam for &'a Components {
1475 type State = ();
1476 type Item<'w, 's> = &'w Components;
1477
1478 fn init_state(_world: &mut World) -> Self::State {}
1479
1480 fn init_access(
1481 _state: &Self::State,
1482 system_meta: &mut SystemMeta,
1483 system_access: &mut SystemAccess,
1484 _world: &mut World,
1485 ) {
1486 system_access.require_shared_access::<Self>(system_meta);
1487 }
1488
1489 #[inline]
1490 unsafe fn get_param<'w, 's>(
1491 _state: &'s mut Self::State,
1492 _system_meta: &SystemMeta,
1493 world: UnsafeWorldCell<'w>,
1494 _change_tick: Tick,
1495 ) -> Result<Self::Item<'w, 's>, SystemParamValidationError> {
1496 Ok(world.components())
1497 }
1498}
1499
1500unsafe impl<'a> ReadOnlySystemParam for &'a Entities {}
1502
1503unsafe impl<'a> SystemParam for &'a Entities {
1505 type State = ();
1506 type Item<'w, 's> = &'w Entities;
1507
1508 fn init_state(_world: &mut World) -> Self::State {}
1509
1510 fn init_access(
1511 _state: &Self::State,
1512 system_meta: &mut SystemMeta,
1513 system_access: &mut SystemAccess,
1514 _world: &mut World,
1515 ) {
1516 system_access.require_shared_access::<Self>(system_meta);
1517 }
1518
1519 #[inline]
1520 unsafe fn get_param<'w, 's>(
1521 _state: &'s mut Self::State,
1522 _system_meta: &SystemMeta,
1523 world: UnsafeWorldCell<'w>,
1524 _change_tick: Tick,
1525 ) -> Result<Self::Item<'w, 's>, SystemParamValidationError> {
1526 Ok(world.entities())
1527 }
1528}
1529
1530unsafe impl<'a> ReadOnlySystemParam for &'a EntityAllocator {}
1532
1533unsafe impl<'a> SystemParam for &'a EntityAllocator {
1535 type State = ();
1536 type Item<'w, 's> = &'w EntityAllocator;
1537
1538 fn init_state(_world: &mut World) -> Self::State {}
1539
1540 fn init_access(
1541 _state: &Self::State,
1542 system_meta: &mut SystemMeta,
1543 system_access: &mut SystemAccess,
1544 _world: &mut World,
1545 ) {
1546 system_access.require_shared_access::<Self>(system_meta);
1547 }
1548
1549 #[inline]
1550 unsafe fn get_param<'w, 's>(
1551 _state: &'s mut Self::State,
1552 _system_meta: &SystemMeta,
1553 world: UnsafeWorldCell<'w>,
1554 _change_tick: Tick,
1555 ) -> Result<Self::Item<'w, 's>, SystemParamValidationError> {
1556 Ok(world.entity_allocator())
1557 }
1558}
1559
1560unsafe impl<'a> ReadOnlySystemParam for &'a Bundles {}
1562
1563unsafe impl<'a> SystemParam for &'a Bundles {
1565 type State = ();
1566 type Item<'w, 's> = &'w Bundles;
1567
1568 fn init_state(_world: &mut World) -> Self::State {}
1569
1570 fn init_access(
1571 _state: &Self::State,
1572 system_meta: &mut SystemMeta,
1573 system_access: &mut SystemAccess,
1574 _world: &mut World,
1575 ) {
1576 system_access.require_shared_access::<Self>(system_meta);
1577 }
1578
1579 #[inline]
1580 unsafe fn get_param<'w, 's>(
1581 _state: &'s mut Self::State,
1582 _system_meta: &SystemMeta,
1583 world: UnsafeWorldCell<'w>,
1584 _change_tick: Tick,
1585 ) -> Result<Self::Item<'w, 's>, SystemParamValidationError> {
1586 Ok(world.bundles())
1587 }
1588}
1589
1590#[derive(Debug, Clone, Copy)]
1600pub struct SystemChangeTick {
1601 last_run: Tick,
1602 this_run: Tick,
1603}
1604
1605impl SystemChangeTick {
1606 #[inline]
1608 pub fn this_run(&self) -> Tick {
1609 self.this_run
1610 }
1611
1612 #[inline]
1614 pub fn last_run(&self) -> Tick {
1615 self.last_run
1616 }
1617}
1618
1619unsafe impl ReadOnlySystemParam for SystemChangeTick {}
1621
1622unsafe impl SystemParam for SystemChangeTick {
1624 type State = ();
1625 type Item<'w, 's> = SystemChangeTick;
1626
1627 fn init_state(_world: &mut World) -> Self::State {}
1628
1629 fn init_access(
1630 _state: &Self::State,
1631 _system_meta: &mut SystemMeta,
1632 _system_access: &mut SystemAccess,
1633 _world: &mut World,
1634 ) {
1635 }
1636
1637 #[inline]
1638 unsafe fn get_param<'w, 's>(
1639 _state: &'s mut Self::State,
1640 system_meta: &SystemMeta,
1641 _world: UnsafeWorldCell<'w>,
1642 change_tick: Tick,
1643 ) -> Result<Self::Item<'w, 's>, SystemParamValidationError> {
1644 Ok(SystemChangeTick {
1645 last_run: system_meta.last_run,
1646 this_run: change_tick,
1647 })
1648 }
1649}
1650
1651unsafe impl<T: SystemParam> SystemParam for Option<T> {
1653 type State = T::State;
1654
1655 type Item<'world, 'state> = Option<T::Item<'world, 'state>>;
1656
1657 fn init_state(world: &mut World) -> Self::State {
1658 T::init_state(world)
1659 }
1660
1661 fn init_access(
1662 state: &Self::State,
1663 system_meta: &mut SystemMeta,
1664 system_access: &mut SystemAccess,
1665 world: &mut World,
1666 ) {
1667 T::init_access(state, system_meta, system_access, world);
1668 }
1669
1670 #[inline]
1671 unsafe fn get_param<'world, 'state>(
1672 state: &'state mut Self::State,
1673 system_meta: &SystemMeta,
1674 world: UnsafeWorldCell<'world>,
1675 change_tick: Tick,
1676 ) -> Result<Self::Item<'world, 'state>, SystemParamValidationError> {
1677 Ok(unsafe { T::get_param(state, system_meta, world, change_tick) }.ok())
1679 }
1680
1681 fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) {
1682 T::apply(state, system_meta, world);
1683 }
1684
1685 fn queue(state: &mut Self::State, system_meta: &SystemMeta, world: DeferredWorld) {
1686 T::queue(state, system_meta, world);
1687 }
1688}
1689
1690unsafe impl<T: ReadOnlySystemParam> ReadOnlySystemParam for Option<T> {}
1692
1693unsafe impl<T: SystemParam> SystemParam for Result<T, SystemParamValidationError> {
1695 type State = T::State;
1696
1697 type Item<'world, 'state> = Result<T::Item<'world, 'state>, SystemParamValidationError>;
1698
1699 fn init_state(world: &mut World) -> Self::State {
1700 T::init_state(world)
1701 }
1702
1703 fn init_access(
1704 state: &Self::State,
1705 system_meta: &mut SystemMeta,
1706 system_access: &mut SystemAccess,
1707 world: &mut World,
1708 ) {
1709 T::init_access(state, system_meta, system_access, world);
1710 }
1711
1712 #[inline]
1713 unsafe fn get_param<'world, 'state>(
1714 state: &'state mut Self::State,
1715 system_meta: &SystemMeta,
1716 world: UnsafeWorldCell<'world>,
1717 change_tick: Tick,
1718 ) -> Result<Self::Item<'world, 'state>, SystemParamValidationError> {
1719 Ok(unsafe { T::get_param(state, system_meta, world, change_tick) })
1721 }
1722
1723 fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) {
1724 T::apply(state, system_meta, world);
1725 }
1726
1727 fn queue(state: &mut Self::State, system_meta: &SystemMeta, world: DeferredWorld) {
1728 T::queue(state, system_meta, world);
1729 }
1730}
1731
1732unsafe impl<T: ReadOnlySystemParam> ReadOnlySystemParam for Result<T, SystemParamValidationError> {}
1734
1735#[derive(Debug)]
1754pub struct If<T>(pub T);
1755
1756impl<T> If<T> {
1757 pub fn into_inner(self) -> T {
1771 self.0
1772 }
1773}
1774
1775impl<T> Deref for If<T> {
1776 type Target = T;
1777 fn deref(&self) -> &Self::Target {
1778 &self.0
1779 }
1780}
1781
1782impl<T> DerefMut for If<T> {
1783 fn deref_mut(&mut self) -> &mut Self::Target {
1784 &mut self.0
1785 }
1786}
1787
1788unsafe impl<T: SystemParam> SystemParam for If<T> {
1790 type State = T::State;
1791
1792 type Item<'world, 'state> = If<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 system_access: &mut SystemAccess,
1802 world: &mut World,
1803 ) {
1804 T::init_access(state, system_meta, system_access, 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 ) -> Result<Self::Item<'world, 'state>, SystemParamValidationError> {
1814 unsafe { T::get_param(state, system_meta, world, change_tick) }
1816 .map(If)
1817 .map_err(|mut e| {
1818 e.skipped = true;
1819 e
1820 })
1821 }
1822
1823 fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) {
1824 T::apply(state, system_meta, world);
1825 }
1826
1827 fn queue(state: &mut Self::State, system_meta: &SystemMeta, world: DeferredWorld) {
1828 T::queue(state, system_meta, world);
1829 }
1830}
1831
1832unsafe impl<T: ReadOnlySystemParam> ReadOnlySystemParam for If<T> {}
1834
1835unsafe impl<T: SystemParam> SystemParam for Vec<T> {
1838 type State = Vec<T::State>;
1839
1840 type Item<'world, 'state> = Vec<T::Item<'world, 'state>>;
1841
1842 fn init_state(_world: &mut World) -> Self::State {
1843 Vec::new()
1844 }
1845
1846 fn init_access(
1847 state: &Self::State,
1848 system_meta: &mut SystemMeta,
1849 system_access: &mut SystemAccess,
1850 world: &mut World,
1851 ) {
1852 for state in state {
1853 T::init_access(state, system_meta, system_access, world);
1854 }
1855 }
1856
1857 #[inline]
1858 unsafe fn get_param<'world, 'state>(
1859 state: &'state mut Self::State,
1860 system_meta: &SystemMeta,
1861 world: UnsafeWorldCell<'world>,
1862 change_tick: Tick,
1863 ) -> Result<Self::Item<'world, 'state>, SystemParamValidationError> {
1864 state
1865 .iter_mut()
1866 .map(|state| unsafe { T::get_param(state, system_meta, world, change_tick) })
1870 .collect()
1871 }
1872
1873 fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) {
1874 for state in state {
1875 T::apply(state, system_meta, world);
1876 }
1877 }
1878
1879 fn queue(state: &mut Self::State, system_meta: &SystemMeta, mut world: DeferredWorld) {
1880 for state in state {
1881 T::queue(state, system_meta, world.reborrow());
1882 }
1883 }
1884}
1885
1886unsafe impl<T: SystemParam> SystemParam for ParamSet<'_, '_, Vec<T>> {
1890 type State = Vec<T::State>;
1891
1892 type Item<'world, 'state> = ParamSet<'world, 'state, Vec<T>>;
1893
1894 fn init_state(_world: &mut World) -> Self::State {
1895 Vec::new()
1896 }
1897
1898 fn init_access(
1899 state: &Self::State,
1900 system_meta: &mut SystemMeta,
1901 system_access: &mut SystemAccess,
1902 world: &mut World,
1903 ) {
1904 for state in state {
1905 let system_access_clone = &mut system_access.clone();
1907 T::init_access(state, system_meta, system_access_clone, world);
1908 }
1909 for state in state {
1910 let mut param_access = SystemAccess::default();
1913 T::init_access(state, system_meta, &mut param_access, world);
1914 system_access.extend(param_access);
1915 }
1916 }
1917
1918 #[inline]
1919 unsafe fn get_param<'world, 'state>(
1920 state: &'state mut Self::State,
1921 system_meta: &SystemMeta,
1922 world: UnsafeWorldCell<'world>,
1923 change_tick: Tick,
1924 ) -> Result<Self::Item<'world, 'state>, SystemParamValidationError> {
1925 for s in state.iter_mut() {
1931 drop(unsafe { T::get_param(s, system_meta, world, change_tick) }?);
1933 }
1934
1935 Ok(ParamSet {
1936 param_states: state,
1937 system_meta: system_meta.clone(),
1938 world,
1939 change_tick,
1940 })
1941 }
1942
1943 fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) {
1944 for state in state {
1945 T::apply(state, system_meta, world);
1946 }
1947 }
1948
1949 fn queue(state: &mut Self::State, system_meta: &SystemMeta, mut world: DeferredWorld) {
1950 for state in state {
1951 T::queue(state, system_meta, world.reborrow());
1952 }
1953 }
1954}
1955
1956impl<T: SystemParam> ParamSet<'_, '_, Vec<T>> {
1957 pub fn get_mut(&mut self, index: usize) -> T::Item<'_, '_> {
1960 unsafe {
1965 T::get_param(
1966 &mut self.param_states[index],
1967 &self.system_meta,
1968 self.world,
1969 self.change_tick,
1970 )
1971 .unwrap()
1972 }
1973 }
1974
1975 pub fn for_each(&mut self, mut f: impl FnMut(T::Item<'_, '_>)) {
1977 self.param_states.iter_mut().for_each(|state| {
1978 f(
1979 unsafe { T::get_param(state, &self.system_meta, self.world, self.change_tick) }
1984 .unwrap_or_else(|err| panic!("ParamSet parameter validation failed: {err}")),
1985 );
1986 });
1987 }
1988}
1989
1990unsafe impl<T: SystemParam, const N: usize> SystemParam for SmallVec<[T; N]> {
1993 type State = SmallVec<[T::State; N]>;
1994
1995 type Item<'world, 'state> = SmallVec<[T::Item<'world, 'state>; N]>;
1996
1997 fn init_state(_world: &mut World) -> Self::State {
1998 SmallVec::new()
1999 }
2000
2001 fn init_access(
2002 state: &Self::State,
2003 system_meta: &mut SystemMeta,
2004 system_access: &mut SystemAccess,
2005 world: &mut World,
2006 ) {
2007 for state in state {
2008 T::init_access(state, system_meta, system_access, world);
2009 }
2010 }
2011
2012 #[inline]
2013 unsafe fn get_param<'world, 'state>(
2014 state: &'state mut Self::State,
2015 system_meta: &SystemMeta,
2016 world: UnsafeWorldCell<'world>,
2017 change_tick: Tick,
2018 ) -> Result<Self::Item<'world, 'state>, SystemParamValidationError> {
2019 state
2020 .iter_mut()
2021 .map(|state| unsafe { T::get_param(state, system_meta, world, change_tick) })
2025 .collect()
2026 }
2027
2028 fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) {
2029 for state in state {
2030 T::apply(state, system_meta, world);
2031 }
2032 }
2033
2034 fn queue(state: &mut Self::State, system_meta: &SystemMeta, mut world: DeferredWorld) {
2035 for state in state {
2036 T::queue(state, system_meta, world.reborrow());
2037 }
2038 }
2039}
2040
2041macro_rules! impl_system_param_tuple {
2042 ($(#[$meta:meta])* $($param: ident),*) => {
2043 $(#[$meta])*
2044 unsafe impl<$($param: ReadOnlySystemParam),*> ReadOnlySystemParam for ($($param,)*) {}
2046
2047 #[expect(
2048 clippy::allow_attributes,
2049 reason = "This is in a macro, and as such, the below lints may not always apply."
2050 )]
2051 #[allow(
2052 non_snake_case,
2053 reason = "Certain variable names are provided by the caller, not by us."
2054 )]
2055 #[allow(
2056 unused_variables,
2057 reason = "Zero-length tuples won't use some of the parameters."
2058 )]
2059 #[allow(clippy::unused_unit, reason = "Zero length tuple is unit.")]
2060 $(#[$meta])*
2061 unsafe impl<$($param: SystemParam),*> SystemParam for ($($param,)*) {
2063 type State = ($($param::State,)*);
2064 type Item<'w, 's> = ($($param::Item::<'w, 's>,)*);
2065
2066 #[inline]
2067 #[track_caller]
2068 fn init_state(world: &mut World) -> Self::State {
2069 ($($param::init_state(world),)*)
2070 }
2071
2072 fn init_access(state: &Self::State, _system_meta: &mut SystemMeta, _system_access: &mut SystemAccess, _world: &mut World) {
2073 let ($($param,)*) = state;
2074 $($param::init_access($param, _system_meta, _system_access, _world);)*
2075 }
2076
2077
2078 #[inline]
2079 fn apply(($($param,)*): &mut Self::State, system_meta: &SystemMeta, world: &mut World) {
2080 $($param::apply($param, system_meta, world);)*
2081 }
2082
2083 #[inline]
2084 #[allow(
2085 unused_mut,
2086 reason = "The `world` parameter is unused for zero-length tuples; however, it must be mutable for other lengths of tuples."
2087 )]
2088 fn queue(($($param,)*): &mut Self::State, system_meta: &SystemMeta, mut world: DeferredWorld) {
2089 $($param::queue($param, system_meta, world.reborrow());)*
2090 }
2091
2092 #[inline]
2093 #[track_caller]
2094 unsafe fn get_param<'w, 's>(
2095 state: &'s mut Self::State,
2096 system_meta: &SystemMeta,
2097 world: UnsafeWorldCell<'w>,
2098 change_tick: Tick,
2099 ) -> Result<Self::Item<'w, 's>, SystemParamValidationError> {
2100 let ($($param,)*) = state;
2101
2102 #[allow(
2103 unused_unsafe,
2104 reason = "Zero-length tuples won't have any params to validate."
2105 )]
2106 unsafe {
2108 #[allow(
2109 clippy::unused_unit,
2110 reason = "Zero-length tuples won't have any params to get."
2111 )]
2112 Ok(($($param::get_param($param, system_meta, world, change_tick)?,)*))
2113 }
2114 }
2115 }
2116 };
2117}
2118
2119all_tuples!(
2120 #[doc(fake_variadic)]
2121 impl_system_param_tuple,
2122 0,
2123 16,
2124 P
2125);
2126
2127pub mod lifetimeless {
2140 pub type SQuery<D, F = ()> = super::Query<'static, 'static, D, F>;
2142 pub type Read<T> = &'static T;
2144 pub type Write<T> = &'static mut T;
2146 pub type SRes<T> = super::Res<'static, T>;
2148 pub type SResMut<T> = super::ResMut<'static, T>;
2150 pub type SCommands = crate::system::Commands<'static, 'static>;
2152}
2153
2154pub struct StaticSystemParam<'w, 's, P: SystemParam>(SystemParamItem<'w, 's, P>);
2206
2207impl<'w, 's, P: SystemParam> Deref for StaticSystemParam<'w, 's, P> {
2208 type Target = SystemParamItem<'w, 's, P>;
2209
2210 fn deref(&self) -> &Self::Target {
2211 &self.0
2212 }
2213}
2214
2215impl<'w, 's, P: SystemParam> DerefMut for StaticSystemParam<'w, 's, P> {
2216 fn deref_mut(&mut self) -> &mut Self::Target {
2217 &mut self.0
2218 }
2219}
2220
2221impl<'w, 's, P: SystemParam> StaticSystemParam<'w, 's, P> {
2222 pub fn into_inner(self) -> SystemParamItem<'w, 's, P> {
2224 self.0
2225 }
2226}
2227
2228unsafe impl<'w, 's, P: ReadOnlySystemParam + 'static> ReadOnlySystemParam
2230 for StaticSystemParam<'w, 's, P>
2231{
2232}
2233
2234unsafe impl<P: SystemParam + 'static> SystemParam for StaticSystemParam<'_, '_, P> {
2236 type State = P::State;
2237 type Item<'world, 'state> = StaticSystemParam<'world, 'state, P>;
2238
2239 fn init_state(world: &mut World) -> Self::State {
2240 P::init_state(world)
2241 }
2242
2243 fn init_access(
2244 state: &Self::State,
2245 system_meta: &mut SystemMeta,
2246 system_access: &mut SystemAccess,
2247 world: &mut World,
2248 ) {
2249 P::init_access(state, system_meta, system_access, world);
2250 }
2251
2252 fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) {
2253 P::apply(state, system_meta, world);
2254 }
2255
2256 fn queue(state: &mut Self::State, system_meta: &SystemMeta, world: DeferredWorld) {
2257 P::queue(state, system_meta, world);
2258 }
2259
2260 #[inline]
2261 unsafe fn get_param<'world, 'state>(
2262 state: &'state mut Self::State,
2263 system_meta: &SystemMeta,
2264 world: UnsafeWorldCell<'world>,
2265 change_tick: Tick,
2266 ) -> Result<Self::Item<'world, 'state>, SystemParamValidationError> {
2267 unsafe { P::get_param(state, system_meta, world, change_tick) }.map(StaticSystemParam)
2269 }
2270}
2271
2272unsafe impl<T: ?Sized> SystemParam for PhantomData<T> {
2274 type State = ();
2275 type Item<'world, 'state> = Self;
2276
2277 fn init_state(_world: &mut World) -> Self::State {}
2278
2279 fn init_access(
2280 _state: &Self::State,
2281 _system_meta: &mut SystemMeta,
2282 _system_access: &mut SystemAccess,
2283 _world: &mut World,
2284 ) {
2285 }
2286
2287 #[inline]
2288 unsafe fn get_param<'world, 'state>(
2289 _state: &'state mut Self::State,
2290 _system_meta: &SystemMeta,
2291 _world: UnsafeWorldCell<'world>,
2292 _change_tick: Tick,
2293 ) -> Result<Self::Item<'world, 'state>, SystemParamValidationError> {
2294 Ok(PhantomData)
2295 }
2296}
2297
2298unsafe impl<T: ?Sized> ReadOnlySystemParam for PhantomData<T> {}
2300
2301unsafe impl<D: QueryData + 'static, F: QueryFilter + 'static> SystemParam
2303 for &'_ mut QueryState<D, F>
2304{
2305 type State = QueryState<D, F>;
2306 type Item<'world, 'state> = &'state mut QueryState<D, F>;
2307
2308 fn init_state(world: &mut World) -> Self::State {
2309 QueryState::new(world)
2310 }
2311
2312 fn init_access(
2313 _state: &Self::State,
2314 _system_meta: &mut SystemMeta,
2315 _system_access: &mut SystemAccess,
2316 _world: &mut World,
2317 ) {
2318 }
2319
2320 unsafe fn get_param<'world, 'state>(
2321 state: &'state mut Self::State,
2322 _system_meta: &SystemMeta,
2323 _world: UnsafeWorldCell<'world>,
2324 _change_tick: Tick,
2325 ) -> Result<Self::Item<'world, 'state>, SystemParamValidationError> {
2326 Ok(state)
2327 }
2328}
2329
2330unsafe impl<D: QueryData + 'static, F: QueryFilter + 'static> ReadOnlySystemParam
2332 for &'_ mut QueryState<D, F>
2333{
2334}
2335
2336unsafe impl<P: SystemParam + 'static> SystemParam for &'_ mut SystemState<P> {
2338 type State = SystemState<P>;
2339 type Item<'world, 'state> = &'state mut SystemState<P>;
2340
2341 fn init_state(world: &mut World) -> Self::State {
2342 SystemState::new(world)
2343 }
2344
2345 fn init_access(
2346 _state: &Self::State,
2347 _system_meta: &mut SystemMeta,
2348 _system_access: &mut SystemAccess,
2349 _world: &mut World,
2350 ) {
2351 }
2352
2353 unsafe fn get_param<'world, 'state>(
2354 state: &'state mut Self::State,
2355 _system_meta: &SystemMeta,
2356 _world: UnsafeWorldCell<'world>,
2357 _change_tick: Tick,
2358 ) -> Result<Self::Item<'world, 'state>, SystemParamValidationError> {
2359 Ok(state)
2360 }
2361}
2362
2363unsafe impl<P: SystemParam + 'static> ReadOnlySystemParam for &'_ mut SystemState<P> {}
2365
2366pub struct DynSystemParam<'w, 's> {
2425 state: &'s mut dyn Any,
2427 world: UnsafeWorldCell<'w>,
2428 system_meta: SystemMeta,
2429 change_tick: Tick,
2430}
2431
2432impl<'w, 's> DynSystemParam<'w, 's> {
2433 unsafe fn new(
2440 state: &'s mut dyn Any,
2441 world: UnsafeWorldCell<'w>,
2442 system_meta: SystemMeta,
2443 change_tick: Tick,
2444 ) -> Self {
2445 Self {
2446 state,
2447 world,
2448 system_meta,
2449 change_tick,
2450 }
2451 }
2452
2453 pub fn is<T: SystemParam>(&self) -> bool
2455 where
2457 T::Item<'static, 'static>: SystemParam<Item<'w, 's> = T> + 'static,
2458 {
2459 self.state.is::<ParamState<T::Item<'static, 'static>>>()
2460 }
2461
2462 pub fn downcast<T: SystemParam>(self) -> Option<T>
2465 where
2467 T::Item<'static, 'static>: SystemParam<Item<'w, 's> = T> + 'static,
2468 {
2469 unsafe { downcast::<T>(self.state, &self.system_meta, self.world, self.change_tick) }
2474 }
2475
2476 pub fn downcast_mut<'a, T: SystemParam>(&'a mut self) -> Option<T>
2479 where
2481 T::Item<'static, 'static>: SystemParam<Item<'a, 'a> = T> + 'static,
2482 {
2483 unsafe { downcast::<T>(self.state, &self.system_meta, self.world, self.change_tick) }
2488 }
2489
2490 pub fn downcast_mut_inner<'a, T: ReadOnlySystemParam>(&'a mut self) -> Option<T>
2496 where
2498 T::Item<'static, 'static>: SystemParam<Item<'w, 'a> = T> + 'static,
2499 {
2500 unsafe { downcast::<T>(self.state, &self.system_meta, self.world, self.change_tick) }
2505 }
2506}
2507
2508unsafe fn downcast<'w, 's, T: SystemParam>(
2515 state: &'s mut dyn Any,
2516 system_meta: &SystemMeta,
2517 world: UnsafeWorldCell<'w>,
2518 change_tick: Tick,
2519) -> Option<T>
2520where
2529 T::Item<'static, 'static>: SystemParam<Item<'w, 's> = T> + 'static,
2530{
2531 state
2532 .downcast_mut::<ParamState<T::Item<'static, 'static>>>()
2533 .and_then(|state| {
2534 unsafe { T::Item::get_param(&mut state.0, system_meta, world, change_tick) }.ok()
2539 })
2540}
2541
2542pub struct DynSystemParamState(Box<dyn DynParamState>);
2544
2545impl DynSystemParamState {
2546 pub(crate) fn new<T: SystemParam + 'static>(state: T::State) -> Self {
2547 Self(Box::new(ParamState::<T>(state)))
2548 }
2549}
2550
2551trait DynParamState: Sync + Send + Any {
2553 fn apply(&mut self, system_meta: &SystemMeta, world: &mut World);
2558
2559 fn queue(&mut self, system_meta: &SystemMeta, world: DeferredWorld);
2561
2562 fn init_access(
2564 &self,
2565 system_meta: &mut SystemMeta,
2566 system_access: &mut SystemAccess,
2567 world: &mut World,
2568 );
2569
2570 unsafe fn validate(
2575 &mut self,
2576 system_meta: &SystemMeta,
2577 world: UnsafeWorldCell,
2578 change_tick: Tick,
2579 ) -> Result<(), SystemParamValidationError>;
2580}
2581
2582struct ParamState<T: SystemParam>(T::State);
2584
2585impl<T: SystemParam + 'static> DynParamState for ParamState<T> {
2586 fn apply(&mut self, system_meta: &SystemMeta, world: &mut World) {
2587 T::apply(&mut self.0, system_meta, world);
2588 }
2589
2590 fn queue(&mut self, system_meta: &SystemMeta, world: DeferredWorld) {
2591 T::queue(&mut self.0, system_meta, world);
2592 }
2593
2594 fn init_access(
2595 &self,
2596 system_meta: &mut SystemMeta,
2597 system_access: &mut SystemAccess,
2598 world: &mut World,
2599 ) {
2600 T::init_access(&self.0, system_meta, system_access, world);
2601 }
2602
2603 unsafe fn validate(
2604 &mut self,
2605 system_meta: &SystemMeta,
2606 world: UnsafeWorldCell,
2607 change_tick: Tick,
2608 ) -> Result<(), SystemParamValidationError> {
2609 unsafe { T::get_param(&mut self.0, system_meta, world, change_tick) }.map(drop)
2611 }
2612}
2613
2614unsafe impl SystemParam for DynSystemParam<'_, '_> {
2616 type State = DynSystemParamState;
2617
2618 type Item<'world, 'state> = DynSystemParam<'world, 'state>;
2619
2620 fn init_state(_world: &mut World) -> Self::State {
2621 DynSystemParamState::new::<()>(())
2622 }
2623
2624 fn init_access(
2625 state: &Self::State,
2626 system_meta: &mut SystemMeta,
2627 system_access: &mut SystemAccess,
2628 world: &mut World,
2629 ) {
2630 state.0.init_access(system_meta, system_access, world);
2631 }
2632
2633 #[inline]
2634 unsafe fn get_param<'world, 'state>(
2635 state: &'state mut Self::State,
2636 system_meta: &SystemMeta,
2637 world: UnsafeWorldCell<'world>,
2638 change_tick: Tick,
2639 ) -> Result<Self::Item<'world, 'state>, SystemParamValidationError> {
2640 unsafe { state.0.validate(system_meta, world, change_tick) }?;
2644 Ok(unsafe {
2650 DynSystemParam::new(state.0.as_mut(), world, system_meta.clone(), change_tick)
2651 })
2652 }
2653
2654 fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) {
2655 state.0.apply(system_meta, world);
2656 }
2657
2658 fn queue(state: &mut Self::State, system_meta: &SystemMeta, world: DeferredWorld) {
2659 state.0.queue(system_meta, world);
2660 }
2661}
2662
2663#[expect(deprecated, reason = "`FilteredResources` will be removed.")]
2666unsafe impl SystemParam for FilteredResources<'_, '_> {
2667 type State = Access;
2668
2669 type Item<'world, 'state> = FilteredResources<'world, 'state>;
2670
2671 fn init_state(_world: &mut World) -> Self::State {
2672 Access::new()
2673 }
2674
2675 fn init_access(
2676 access: &Self::State,
2677 system_meta: &mut SystemMeta,
2678 system_access: &mut SystemAccess,
2679 world: &mut World,
2680 ) {
2681 let mut filtered_access = FilteredAccess::default();
2682 filtered_access.access_mut().extend(access);
2683 filtered_access.and_with(IS_RESOURCE);
2684
2685 if let Err(conflicts) = system_access.try_add(filtered_access) {
2686 let accesses = conflicts.format_conflict_list(world.into());
2687 let system_name = &system_meta.name;
2688 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");
2689 }
2690 }
2691
2692 unsafe fn get_param<'world, 'state>(
2693 state: &'state mut Self::State,
2694 system_meta: &SystemMeta,
2695 world: UnsafeWorldCell<'world>,
2696 change_tick: Tick,
2697 ) -> Result<Self::Item<'world, 'state>, SystemParamValidationError> {
2698 Ok(unsafe { FilteredResources::new(world, state, system_meta.last_run, change_tick) })
2701 }
2702}
2703
2704#[expect(deprecated, reason = "`FilteredResources` will be removed.")]
2706unsafe impl ReadOnlySystemParam for FilteredResources<'_, '_> {}
2707
2708#[expect(deprecated, reason = "`FilteredResourcesMut` will be removed.")]
2711unsafe impl SystemParam for FilteredResourcesMut<'_, '_> {
2712 type State = Access;
2713
2714 type Item<'world, 'state> = FilteredResourcesMut<'world, 'state>;
2715
2716 fn init_state(_world: &mut World) -> Self::State {
2717 Access::new()
2718 }
2719
2720 fn init_access(
2721 access: &Self::State,
2722 system_meta: &mut SystemMeta,
2723 system_access: &mut SystemAccess,
2724 world: &mut World,
2725 ) {
2726 let mut filtered_access = FilteredAccess::default();
2727 filtered_access.access_mut().extend(access);
2728 filtered_access.and_with(IS_RESOURCE);
2729
2730 if let Err(conflicts) = system_access.try_add(filtered_access) {
2731 let accesses = conflicts.format_conflict_list(world.into());
2732 let system_name = &system_meta.name;
2733 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");
2734 }
2735 }
2736
2737 unsafe fn get_param<'world, 'state>(
2738 state: &'state mut Self::State,
2739 system_meta: &SystemMeta,
2740 world: UnsafeWorldCell<'world>,
2741 change_tick: Tick,
2742 ) -> Result<Self::Item<'world, 'state>, SystemParamValidationError> {
2743 Ok(unsafe { FilteredResourcesMut::new(world, state, system_meta.last_run, change_tick) })
2746 }
2747}
2748
2749#[derive(Debug, PartialEq, Eq, Clone, Error)]
2755pub struct SystemParamValidationError {
2756 pub skipped: bool,
2769
2770 pub message: Cow<'static, str>,
2772
2773 pub param: DebugName,
2776
2777 pub field: Cow<'static, str>,
2782}
2783
2784impl SystemParamValidationError {
2785 pub fn skipped<T>(message: impl Into<Cow<'static, str>>) -> Self {
2788 Self::new::<T>(true, message, Cow::Borrowed(""))
2789 }
2790
2791 pub fn invalid<T>(message: impl Into<Cow<'static, str>>) -> Self {
2794 Self::new::<T>(false, message, Cow::Borrowed(""))
2795 }
2796
2797 pub fn new<T>(
2800 skipped: bool,
2801 message: impl Into<Cow<'static, str>>,
2802 field: impl Into<Cow<'static, str>>,
2803 ) -> Self {
2804 Self {
2805 skipped,
2806 message: message.into(),
2807 param: DebugName::type_name::<T>(),
2808 field: field.into(),
2809 }
2810 }
2811
2812 pub(crate) const EMPTY: Self = Self {
2813 skipped: false,
2814 message: Cow::Borrowed(""),
2815 param: DebugName::borrowed(""),
2816 field: Cow::Borrowed(""),
2817 };
2818}
2819
2820impl Display for SystemParamValidationError {
2821 fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
2822 write!(
2823 fmt,
2824 "Parameter `{}{}` failed validation: {}",
2825 self.param.shortname(),
2826 self.field,
2827 self.message
2828 )?;
2829 if !self.skipped {
2830 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.")?;
2831 }
2832 Ok(())
2833 }
2834}
2835
2836#[cfg(test)]
2837mod tests {
2838 use bevy_ecs_macros::Component;
2839
2840 use super::*;
2841 use crate::query::Without;
2842 use crate::resource::IsResource;
2843 use crate::schedule::Schedule;
2844 use crate::system::{assert_is_system, Commands, IntoSystem, System};
2845 use crate::world::EntityMut;
2846 use core::cell::RefCell;
2847
2848 #[test]
2849 #[should_panic]
2850 fn non_send_alias() {
2851 #[derive(Resource)]
2852 struct A(usize);
2853 fn my_system(mut res0: NonSendMut<A>, mut res1: NonSendMut<A>) {
2854 res0.0 += 1;
2855 res1.0 += 1;
2856 }
2857 let mut world = World::new();
2858 world.insert_non_send(A(42));
2859 let mut schedule = Schedule::default();
2860 schedule.add_systems(my_system);
2861 schedule.run(&mut world);
2862 }
2863
2864 #[test]
2865 #[should_panic]
2866 fn non_send_and_entities() {
2867 #[derive(Resource)]
2868 struct A(usize);
2869 fn my_system(mut ns: NonSendMut<A>, _: Query<EntityMut>) {
2870 ns.0 += 1;
2871 }
2872 assert_is_system(my_system);
2873 }
2874
2875 #[test]
2876 #[should_panic]
2877 fn res_and_entities() {
2878 #[derive(Resource)]
2879 struct A(usize);
2880 fn my_system(mut res: ResMut<A>, _: Query<EntityMut>) {
2881 res.0 += 1;
2882 }
2883 assert_is_system(my_system);
2884 }
2885
2886 #[test]
2887 fn res_and_entities_filtered() {
2888 #[derive(Resource)]
2889 struct A(usize);
2890 fn res_system(mut res: ResMut<A>, _: Query<EntityMut, Without<IsResource>>) {
2891 res.0 += 1;
2892 }
2893 assert_is_system(res_system);
2894
2895 fn non_send_system(mut ns: NonSendMut<A>, _: Query<EntityMut, Without<A>>) {
2896 ns.0 += 1;
2897 }
2898
2899 assert_is_system(non_send_system);
2900 }
2901
2902 #[test]
2904 fn system_param_generic_bounds() {
2905 #[derive(SystemParam)]
2906 pub struct SpecialQuery<
2907 'w,
2908 's,
2909 D: QueryData + Send + Sync + 'static,
2910 F: QueryFilter + Send + Sync + 'static = (),
2911 > {
2912 _query: Query<'w, 's, D, F>,
2913 }
2914
2915 fn my_system(_: SpecialQuery<(), ()>) {}
2916 assert_is_system(my_system);
2917 }
2918
2919 #[test]
2921 fn system_param_flexibility() {
2922 #[derive(SystemParam)]
2923 pub struct SpecialRes<'w, T: Resource> {
2924 _res: Res<'w, T>,
2925 }
2926
2927 #[derive(SystemParam)]
2928 pub struct SpecialLocal<'s, T: FromWorld + Send + 'static> {
2929 _local: Local<'s, T>,
2930 }
2931
2932 #[derive(Resource)]
2933 struct R;
2934
2935 fn my_system(_: SpecialRes<R>, _: SpecialLocal<u32>) {}
2936 assert_is_system(my_system);
2937 }
2938
2939 #[derive(Resource)]
2940 pub struct R<const I: usize>;
2941
2942 #[test]
2944 fn system_param_const_generics() {
2945 #[expect(
2946 dead_code,
2947 reason = "This struct is used to ensure that const generics are supported as a SystemParam; thus, the inner value never needs to be read."
2948 )]
2949 #[derive(SystemParam)]
2950 pub struct ConstGenericParam<'w, const I: usize>(Res<'w, R<I>>);
2951
2952 fn my_system(_: ConstGenericParam<0>, _: ConstGenericParam<1000>) {}
2953 assert_is_system(my_system);
2954 }
2955
2956 #[test]
2958 fn system_param_field_limit() {
2959 #[derive(SystemParam)]
2960 pub struct LongParam<'w> {
2961 _r0: Res<'w, R<0>>,
2964 _r1: Res<'w, R<1>>,
2965 _r2: Res<'w, R<2>>,
2966 _r3: Res<'w, R<3>>,
2967 _r4: Res<'w, R<4>>,
2968 _r5: Res<'w, R<5>>,
2969 _r6: Res<'w, R<6>>,
2970 _r7: Res<'w, R<7>>,
2971 _r8: Res<'w, R<8>>,
2972 _r9: Res<'w, R<9>>,
2973 _r10: Res<'w, R<10>>,
2974 _r11: Res<'w, R<11>>,
2975 _r12: Res<'w, R<12>>,
2976 _r13: Res<'w, R<13>>,
2977 _r14: Res<'w, R<14>>,
2978 _r15: Res<'w, R<15>>,
2979 _r16: Res<'w, R<16>>,
2980 }
2981
2982 fn long_system(_: LongParam) {}
2983 assert_is_system(long_system);
2984 }
2985
2986 #[test]
2989 fn system_param_phantom_data() {
2990 #[derive(SystemParam)]
2991 struct PhantomParam<'w, T: Resource, Marker: 'static> {
2992 _foo: Res<'w, T>,
2993 marker: PhantomData<&'w Marker>,
2994 }
2995
2996 fn my_system(_: PhantomParam<R<0>, ()>) {}
2997 assert_is_system(my_system);
2998 }
2999
3000 #[test]
3002 fn system_param_struct_variants() {
3003 #[derive(SystemParam)]
3004 pub struct UnitParam;
3005
3006 #[expect(
3007 dead_code,
3008 reason = "This struct is used to ensure that tuple structs are supported as a SystemParam; thus, the inner values never need to be read."
3009 )]
3010 #[derive(SystemParam)]
3011 pub struct TupleParam<'w, 's, R: Resource, L: FromWorld + Send + 'static>(
3012 Res<'w, R>,
3013 Local<'s, L>,
3014 );
3015
3016 fn my_system(_: UnitParam, _: TupleParam<R<0>, u32>) {}
3017 assert_is_system(my_system);
3018 }
3019
3020 #[test]
3022 fn system_param_private_fields() {
3023 #[derive(Resource)]
3024 struct PrivateResource;
3025
3026 #[expect(
3027 dead_code,
3028 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."
3029 )]
3030 #[derive(SystemParam)]
3031 pub struct EncapsulatedParam<'w>(Res<'w, PrivateResource>);
3032
3033 fn my_system(_: EncapsulatedParam) {}
3034 assert_is_system(my_system);
3035 }
3036
3037 #[test]
3039 fn system_param_where_clause() {
3040 #[derive(SystemParam)]
3041 pub struct WhereParam<'w, 's, D>
3042 where
3043 D: 'static + QueryData,
3044 {
3045 _q: Query<'w, 's, D, ()>,
3046 }
3047
3048 fn my_system(_: WhereParam<()>) {}
3049 assert_is_system(my_system);
3050 }
3051
3052 #[test]
3054 fn system_param_name_collision() {
3055 #[derive(Resource)]
3056 pub struct FetchState;
3057
3058 #[derive(SystemParam)]
3059 pub struct Collide<'w> {
3060 _x: Res<'w, FetchState>,
3061 }
3062
3063 fn my_system(_: Collide) {}
3064 assert_is_system(my_system);
3065 }
3066
3067 #[test]
3069 fn system_param_invariant_lifetime() {
3070 #[derive(SystemParam)]
3071 pub struct InvariantParam<'w, 's> {
3072 _set: ParamSet<'w, 's, (Query<'w, 's, ()>,)>,
3073 }
3074
3075 fn my_system(_: InvariantParam) {}
3076 assert_is_system(my_system);
3077 }
3078
3079 #[test]
3081 fn non_sync_local() {
3082 fn non_sync_system(cell: Local<RefCell<u8>>) {
3083 assert_eq!(*cell.borrow(), 0);
3084 }
3085
3086 let mut world = World::new();
3087 let mut schedule = Schedule::default();
3088 schedule.add_systems(non_sync_system);
3089 schedule.run(&mut world);
3090 }
3091
3092 #[test]
3094 fn param_set_non_send_first() {
3095 fn non_send_param_set(mut p: ParamSet<(NonSend<*mut u8>, ())>) {
3096 let _ = p.p0();
3097 p.p1();
3098 }
3099
3100 let mut world = World::new();
3101 world.insert_non_send(core::ptr::null_mut::<u8>());
3102 let mut schedule = Schedule::default();
3103 schedule.add_systems((non_send_param_set, non_send_param_set, non_send_param_set));
3104 schedule.run(&mut world);
3105 }
3106
3107 #[test]
3109 fn param_set_non_send_second() {
3110 fn non_send_param_set(mut p: ParamSet<((), NonSendMut<*mut u8>)>) {
3111 p.p0();
3112 let _ = p.p1();
3113 }
3114
3115 let mut world = World::new();
3116 world.insert_non_send(core::ptr::null_mut::<u8>());
3117 let mut schedule = Schedule::default();
3118 schedule.add_systems((non_send_param_set, non_send_param_set, non_send_param_set));
3119 schedule.run(&mut world);
3120 }
3121
3122 fn _dyn_system_param_type_inference(mut p: DynSystemParam) {
3123 let _query: Query<()> = p.downcast_mut().unwrap();
3126 let _query: Query<()> = p.downcast_mut_inner().unwrap();
3127 let _query: Query<()> = p.downcast().unwrap();
3128 }
3129
3130 #[test]
3131 #[should_panic]
3132 fn missing_resource_error() {
3133 #[derive(Resource)]
3134 pub struct MissingResource;
3135
3136 let mut schedule = Schedule::default();
3137 schedule.add_systems(res_system);
3138 let mut world = World::new();
3139 schedule.run(&mut world);
3140
3141 fn res_system(_: Res<MissingResource>) {}
3142 }
3143
3144 #[test]
3145 #[should_panic]
3146 fn missing_message_error() {
3147 use crate::prelude::{Message, MessageReader};
3148
3149 #[derive(Message)]
3150 pub struct MissingEvent;
3151
3152 let mut schedule = Schedule::default();
3153 schedule.add_systems(message_system);
3154 let mut world = World::new();
3155 schedule.run(&mut world);
3156
3157 fn message_system(_: MessageReader<MissingEvent>) {}
3158 }
3159
3160 #[test]
3161 fn test_exclusive_system_params() {
3162 #[derive(Resource, Default)]
3163 struct Res {
3164 test_value: u32,
3165 }
3166
3167 fn my_system(world: &mut World, mut local: Local<u32>, _phantom: PhantomData<Vec<u32>>) {
3168 assert_eq!(world.resource::<Res>().test_value, *local);
3169 *local += 1;
3170 world.resource_mut::<Res>().test_value += 1;
3171 }
3172
3173 let mut schedule = Schedule::default();
3174 schedule.add_systems(my_system);
3175
3176 let mut world = World::default();
3177 world.init_resource::<Res>();
3178
3179 schedule.run(&mut world);
3180 schedule.run(&mut world);
3181
3182 assert_eq!(2, world.get_resource::<Res>().unwrap().test_value);
3183 }
3184
3185 #[test]
3186 #[should_panic(expected = "World")]
3187 fn mutable_world_conflicts_with_commands_first() {
3188 fn system(_: Commands, _: &mut World) {}
3189 assert_is_system(system);
3190 }
3191
3192 #[test]
3193 #[should_panic(expected = "Entities")]
3194 fn mutable_world_conflicts_with_commands_second() {
3195 fn system(_: &mut World, _: Commands) {}
3196 assert_is_system(system);
3197 }
3198
3199 #[test]
3200 #[should_panic(expected = "World")]
3201 fn mutable_world_conflicts_with_entities_first() {
3202 fn system(_: &Entities, _: &mut World) {}
3203 assert_is_system(system);
3204 }
3205
3206 #[test]
3207 #[should_panic(expected = "Entities")]
3208 fn mutable_world_conflicts_with_entities_second() {
3209 fn system(_: &mut World, _: &Entities) {}
3210 assert_is_system(system);
3211 }
3212
3213 #[test]
3214 #[should_panic(expected = "Archetypes")]
3215 fn mutable_world_conflicts_with_archetypes() {
3216 fn system(_: &mut World, _: &Archetypes) {}
3217 assert_is_system(system);
3218 }
3219
3220 #[test]
3221 #[should_panic(expected = "Components")]
3222 fn mutable_world_conflicts_with_components() {
3223 fn system(_: &mut World, _: &Components) {}
3224 assert_is_system(system);
3225 }
3226
3227 #[test]
3228 #[should_panic(expected = "EntityAllocator")]
3229 fn mutable_world_conflicts_with_entity_allocator() {
3230 fn system(_: &mut World, _: &EntityAllocator) {}
3231 assert_is_system(system);
3232 }
3233
3234 #[test]
3235 #[should_panic(expected = "Bundles")]
3236 fn mutable_world_conflicts_with_bundles() {
3237 fn system(_: &mut World, _: &Bundles) {}
3238 assert_is_system(system);
3239 }
3240
3241 #[test]
3242 #[should_panic(expected = "World")]
3243 fn mutable_world_conflicts_with_immutable_world() {
3244 fn system(_: &mut World, _: &World) {}
3245 assert_is_system(system);
3246 }
3247
3248 #[test]
3249 #[should_panic(expected = "DeferredWorld")]
3250 fn mutable_world_conflicts_with_deferred_world() {
3251 fn system(_: &mut World, _: DeferredWorld) {}
3252 assert_is_system(system);
3253 }
3254
3255 #[test]
3256 fn mutable_world_with_query_and_system_state_works() {
3257 fn system(_: &mut World, _: &mut QueryState<()>, _: &mut SystemState<()>) {}
3258 assert_is_system(system);
3259 }
3260
3261 #[test]
3262 fn mutable_world_param_set_works() {
3263 fn system(_: ParamSet<(&mut World, &mut World, &Entities)>) {}
3264 assert_is_system(system);
3265 }
3266
3267 #[test]
3268 #[should_panic(expected = "World")]
3269 fn mutable_world_param_set_conflicts_outside() {
3270 fn system(_: &Entities, _: ParamSet<(&mut World, &Entities)>) {}
3271 assert_is_system(system);
3272 }
3273
3274 #[test]
3275 #[should_panic(expected = "Entities")]
3276 fn mutable_world_param_set_conflicts_outside_reverse() {
3277 fn system(_: ParamSet<(&mut World, &Entities)>, _: &Entities) {}
3278 assert_is_system(system);
3279 }
3280
3281 #[test]
3282 #[should_panic(expected = "Entities")]
3283 fn mutable_world_conflicts_with_optional_entities() {
3284 fn system(_: &mut World, _: Option<&Entities>) {}
3285 assert_is_system(system);
3286 }
3287
3288 #[test]
3289 #[should_panic(expected = "error[B0002]")]
3290 fn mutable_world_conflicts_with_optional_query() {
3291 #[derive(Component)]
3292 struct A;
3293 fn system(_: &mut World, _: Option<Query<&mut A>>) {}
3294 assert_is_system(system);
3295 }
3296
3297 #[test]
3298 #[should_panic(expected = "error[B0002]")]
3299 fn mutable_world_conflicts_with_query() {
3300 #[derive(Component)]
3301 struct A;
3302 fn system(_: &mut World, _: Query<&mut A>) {}
3303 assert_is_system(system);
3304 }
3305
3306 #[test]
3307 #[should_panic(expected = "error[B0002]")]
3308 fn mutable_world_conflicts_with_empty_query() {
3309 fn system(_: &mut World, _: Query<()>) {}
3310 assert_is_system(system);
3311 }
3312
3313 #[test]
3314 fn metadata_readers_work() {
3315 fn system1(
3316 _: &World,
3317 _: &Entities,
3318 _: &Archetypes,
3319 _: &Components,
3320 _: &EntityAllocator,
3321 _: &Bundles,
3322 _: Commands,
3323 ) {
3324 }
3325 assert_is_system(system1);
3326
3327 fn system2(
3328 _: DeferredWorld,
3329 _: &Entities,
3330 _: &Archetypes,
3331 _: &Components,
3332 _: &EntityAllocator,
3333 _: &Bundles,
3334 _: Commands,
3335 ) {
3336 }
3337 assert_is_system(system2);
3338 }
3339
3340 #[test]
3341 fn query_and_query_state_works() {
3342 #[derive(Component)]
3343 struct A;
3344 #[derive(Component)]
3345 struct B;
3346
3347 fn system1(_: &mut QueryState<&mut A>, _: Query<&mut B>) {}
3348 assert_is_system(system1);
3349
3350 fn system2(_: &mut QueryState<&mut A>, _: Query<&mut A>) {}
3351 assert_is_system(system2);
3352 }
3353
3354 #[test]
3355 fn exclusive_systems_are_non_send() {
3356 fn test_system(_: &mut World) {}
3357
3358 let mut world = World::new();
3359 let mut system = IntoSystem::into_system(test_system);
3360 system.initialize(&mut world);
3361
3362 assert!(!system.is_send());
3363 }
3364}