pub use crate::change_detection::{NonSend, NonSendMut, Res, ResMut};
use crate::{
archetype::Archetypes,
bundle::Bundles,
change_detection::{ComponentTicksMut, ComponentTicksRef, Tick},
component::{ComponentId, Components},
entity::{Entities, EntityAllocator},
query::{
Access, FilteredAccess, FilteredAccessSet, QueryData, QueryFilter, QuerySingleError,
QueryState, ReadOnlyQueryData,
},
resource::Resource,
storage::ResourceData,
system::{Query, Single, SystemMeta},
world::{
unsafe_world_cell::UnsafeWorldCell, DeferredWorld, FilteredResources, FilteredResourcesMut,
FromWorld, World,
},
};
use alloc::{borrow::Cow, boxed::Box, vec::Vec};
pub use bevy_ecs_macros::SystemParam;
use bevy_platform::cell::SyncCell;
use bevy_ptr::UnsafeCellDeref;
use bevy_utils::prelude::DebugName;
use core::{
any::Any,
fmt::{Debug, Display},
marker::PhantomData,
ops::{Deref, DerefMut},
};
use thiserror::Error;
use super::Populated;
use variadics_please::{all_tuples, all_tuples_enumerated};
pub unsafe trait SystemParam: Sized {
type State: Send + Sync + 'static;
type Item<'world, 'state>: SystemParam<State = Self::State>;
fn init_state(world: &mut World) -> Self::State;
fn init_access(
state: &Self::State,
system_meta: &mut SystemMeta,
component_access_set: &mut FilteredAccessSet,
world: &mut World,
);
#[inline]
#[expect(
unused_variables,
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."
)]
fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) {}
#[inline]
#[expect(
unused_variables,
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."
)]
fn queue(state: &mut Self::State, system_meta: &SystemMeta, world: DeferredWorld) {}
#[expect(
unused_variables,
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."
)]
unsafe fn validate_param(
state: &mut Self::State,
system_meta: &SystemMeta,
world: UnsafeWorldCell,
) -> Result<(), SystemParamValidationError> {
Ok(())
}
unsafe fn get_param<'world, 'state>(
state: &'state mut Self::State,
system_meta: &SystemMeta,
world: UnsafeWorldCell<'world>,
change_tick: Tick,
) -> Self::Item<'world, 'state>;
}
pub unsafe trait ReadOnlySystemParam: SystemParam {}
pub type SystemParamItem<'w, 's, P> = <P as SystemParam>::Item<'w, 's>;
unsafe impl<'w, 's, D: ReadOnlyQueryData + 'static, F: QueryFilter + 'static> ReadOnlySystemParam
for Query<'w, 's, D, F>
{
}
unsafe impl<D: QueryData + 'static, F: QueryFilter + 'static> SystemParam for Query<'_, '_, D, F> {
type State = QueryState<D, F>;
type Item<'w, 's> = Query<'w, 's, D, F>;
fn init_state(world: &mut World) -> Self::State {
QueryState::new(world)
}
fn init_access(
state: &Self::State,
system_meta: &mut SystemMeta,
component_access_set: &mut FilteredAccessSet,
world: &mut World,
) {
assert_component_access_compatibility(
&system_meta.name,
DebugName::type_name::<D>(),
DebugName::type_name::<F>(),
component_access_set,
&state.component_access,
world,
);
component_access_set.add(state.component_access.clone());
}
#[inline]
unsafe fn get_param<'w, 's>(
state: &'s mut Self::State,
system_meta: &SystemMeta,
world: UnsafeWorldCell<'w>,
change_tick: Tick,
) -> Self::Item<'w, 's> {
unsafe { state.query_unchecked_with_ticks(world, system_meta.last_run, change_tick) }
}
}
fn assert_component_access_compatibility(
system_name: &DebugName,
query_type: DebugName,
filter_type: DebugName,
system_access: &FilteredAccessSet,
current: &FilteredAccess,
world: &World,
) {
let conflicts = system_access.get_conflicts_single(current);
if conflicts.is_empty() {
return;
}
let mut accesses = conflicts.format_conflict_list(world);
if !accesses.is_empty() {
accesses.push(' ');
}
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());
}
unsafe impl<'a, 'b, D: QueryData + 'static, F: QueryFilter + 'static> SystemParam
for Single<'a, 'b, D, F>
{
type State = QueryState<D, F>;
type Item<'w, 's> = Single<'w, 's, D, F>;
fn init_state(world: &mut World) -> Self::State {
Query::init_state(world)
}
fn init_access(
state: &Self::State,
system_meta: &mut SystemMeta,
component_access_set: &mut FilteredAccessSet,
world: &mut World,
) {
Query::init_access(state, system_meta, component_access_set, world);
}
#[inline]
unsafe fn get_param<'w, 's>(
state: &'s mut Self::State,
system_meta: &SystemMeta,
world: UnsafeWorldCell<'w>,
change_tick: Tick,
) -> Self::Item<'w, 's> {
let query =
unsafe { state.query_unchecked_with_ticks(world, system_meta.last_run, change_tick) };
let single = query
.single_inner()
.expect("The query was expected to contain exactly one matching entity.");
Single {
item: single,
_filter: PhantomData,
}
}
#[inline]
unsafe fn validate_param(
state: &mut Self::State,
system_meta: &SystemMeta,
world: UnsafeWorldCell,
) -> Result<(), SystemParamValidationError> {
let query = unsafe {
state.query_unchecked_with_ticks(world, system_meta.last_run, world.change_tick())
};
match query.single_inner() {
Ok(_) => Ok(()),
Err(QuerySingleError::NoEntities(_)) => Err(
SystemParamValidationError::skipped::<Self>("No matching entities"),
),
Err(QuerySingleError::MultipleEntities(_)) => Err(
SystemParamValidationError::skipped::<Self>("Multiple matching entities"),
),
}
}
}
unsafe impl<'a, 'b, D: ReadOnlyQueryData + 'static, F: QueryFilter + 'static> ReadOnlySystemParam
for Single<'a, 'b, D, F>
{
}
unsafe impl<D: QueryData + 'static, F: QueryFilter + 'static> SystemParam
for Populated<'_, '_, D, F>
{
type State = QueryState<D, F>;
type Item<'w, 's> = Populated<'w, 's, D, F>;
fn init_state(world: &mut World) -> Self::State {
Query::init_state(world)
}
fn init_access(
state: &Self::State,
system_meta: &mut SystemMeta,
component_access_set: &mut FilteredAccessSet,
world: &mut World,
) {
Query::init_access(state, system_meta, component_access_set, world);
}
#[inline]
unsafe fn get_param<'w, 's>(
state: &'s mut Self::State,
system_meta: &SystemMeta,
world: UnsafeWorldCell<'w>,
change_tick: Tick,
) -> Self::Item<'w, 's> {
let query = unsafe { Query::get_param(state, system_meta, world, change_tick) };
Populated(query)
}
#[inline]
unsafe fn validate_param(
state: &mut Self::State,
system_meta: &SystemMeta,
world: UnsafeWorldCell,
) -> Result<(), SystemParamValidationError> {
let query = unsafe {
state.query_unchecked_with_ticks(world, system_meta.last_run, world.change_tick())
};
if query.is_empty() {
Err(SystemParamValidationError::skipped::<Self>(
"No matching entities",
))
} else {
Ok(())
}
}
}
unsafe impl<'w, 's, D: ReadOnlyQueryData + 'static, F: QueryFilter + 'static> ReadOnlySystemParam
for Populated<'w, 's, D, F>
{
}
pub struct ParamSet<'w, 's, T: SystemParam> {
param_states: &'s mut T::State,
world: UnsafeWorldCell<'w>,
system_meta: SystemMeta,
change_tick: Tick,
}
macro_rules! impl_param_set {
($(($index: tt, $param: ident, $fn_name: ident)),*) => {
unsafe impl<'w, 's, $($param,)*> ReadOnlySystemParam for ParamSet<'w, 's, ($($param,)*)>
where $($param: ReadOnlySystemParam,)*
{ }
unsafe impl<'_w, '_s, $($param: SystemParam,)*> SystemParam for ParamSet<'_w, '_s, ($($param,)*)>
{
type State = ($($param::State,)*);
type Item<'w, 's> = ParamSet<'w, 's, ($($param,)*)>;
#[expect(
clippy::allow_attributes,
reason = "This is inside a macro meant for tuples; as such, `non_snake_case` won't always lint."
)]
#[allow(
non_snake_case,
reason = "Certain variable names are provided by the caller, not by us."
)]
fn init_state(world: &mut World) -> Self::State {
($($param::init_state(world),)*)
}
#[expect(
clippy::allow_attributes,
reason = "This is inside a macro meant for tuples; as such, `non_snake_case` won't always lint."
)]
#[allow(
non_snake_case,
reason = "Certain variable names are provided by the caller, not by us."
)]
fn init_access(state: &Self::State, system_meta: &mut SystemMeta, component_access_set: &mut FilteredAccessSet, world: &mut World) {
let ($($param,)*) = state;
$(
let component_access_set_clone = &mut component_access_set.clone();
$param::init_access($param, system_meta, component_access_set_clone, world);
)*
$(
let mut access_set = FilteredAccessSet::new();
$param::init_access($param, system_meta, &mut access_set, world);
component_access_set.extend(access_set);
)*
}
fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) {
<($($param,)*) as SystemParam>::apply(state, system_meta, world);
}
fn queue(state: &mut Self::State, system_meta: &SystemMeta, mut world: DeferredWorld) {
<($($param,)*) as SystemParam>::queue(state, system_meta, world.reborrow());
}
#[inline]
unsafe fn validate_param<'w, 's>(
state: &'s mut Self::State,
system_meta: &SystemMeta,
world: UnsafeWorldCell<'w>,
) -> Result<(), SystemParamValidationError> {
unsafe {
<($($param,)*) as SystemParam>::validate_param(state, system_meta, world)
}
}
#[inline]
unsafe fn get_param<'w, 's>(
state: &'s mut Self::State,
system_meta: &SystemMeta,
world: UnsafeWorldCell<'w>,
change_tick: Tick,
) -> Self::Item<'w, 's> {
ParamSet {
param_states: state,
system_meta: system_meta.clone(),
world,
change_tick,
}
}
}
impl<'w, 's, $($param: SystemParam,)*> ParamSet<'w, 's, ($($param,)*)>
{
$(
#[doc = stringify!($index)]
pub fn $fn_name<'a>(&'a mut self) -> SystemParamItem<'a, 'a, $param> {
unsafe {
$param::get_param(&mut self.param_states.$index, &self.system_meta, self.world, self.change_tick)
}
}
)*
}
}
}
all_tuples_enumerated!(impl_param_set, 1, 8, P, p);
unsafe impl<'a, T: Resource> ReadOnlySystemParam for Res<'a, T> {}
unsafe impl<'a, T: Resource> SystemParam for Res<'a, T> {
type State = ComponentId;
type Item<'w, 's> = Res<'w, T>;
fn init_state(world: &mut World) -> Self::State {
world.components_registrator().register_resource::<T>()
}
fn init_access(
&component_id: &Self::State,
system_meta: &mut SystemMeta,
component_access_set: &mut FilteredAccessSet,
_world: &mut World,
) {
let combined_access = component_access_set.combined_access();
assert!(
!combined_access.has_resource_write(component_id),
"error[B0002]: Res<{}> in system {} conflicts with a previous ResMut<{0}> access. Consider removing the duplicate access. See: https://bevy.org/learn/errors/b0002",
DebugName::type_name::<T>(),
system_meta.name,
);
component_access_set.add_unfiltered_resource_read(component_id);
}
#[inline]
unsafe fn validate_param(
&mut component_id: &mut Self::State,
_system_meta: &SystemMeta,
world: UnsafeWorldCell,
) -> Result<(), SystemParamValidationError> {
if unsafe { world.storages() }
.resources
.get(component_id)
.is_some_and(ResourceData::is_present)
{
Ok(())
} else {
Err(SystemParamValidationError::invalid::<Self>(
"Resource does not exist",
))
}
}
#[inline]
unsafe fn get_param<'w, 's>(
&mut component_id: &'s mut Self::State,
system_meta: &SystemMeta,
world: UnsafeWorldCell<'w>,
change_tick: Tick,
) -> Self::Item<'w, 's> {
let (ptr, ticks) = world
.get_resource_with_ticks(component_id)
.unwrap_or_else(|| {
panic!(
"Resource requested by {} does not exist: {}",
system_meta.name,
DebugName::type_name::<T>()
);
});
Res {
value: ptr.deref(),
ticks: ComponentTicksRef {
added: ticks.added.deref(),
changed: ticks.changed.deref(),
changed_by: ticks.changed_by.map(|changed_by| changed_by.deref()),
last_run: system_meta.last_run,
this_run: change_tick,
},
}
}
}
unsafe impl<'a, T: Resource> SystemParam for ResMut<'a, T> {
type State = ComponentId;
type Item<'w, 's> = ResMut<'w, T>;
fn init_state(world: &mut World) -> Self::State {
world.components_registrator().register_resource::<T>()
}
fn init_access(
&component_id: &Self::State,
system_meta: &mut SystemMeta,
component_access_set: &mut FilteredAccessSet,
_world: &mut World,
) {
let combined_access = component_access_set.combined_access();
if combined_access.has_resource_write(component_id) {
panic!(
"error[B0002]: ResMut<{}> in system {} conflicts with a previous ResMut<{0}> access. Consider removing the duplicate access. See: https://bevy.org/learn/errors/b0002",
DebugName::type_name::<T>(), system_meta.name);
} else if combined_access.has_resource_read(component_id) {
panic!(
"error[B0002]: ResMut<{}> in system {} conflicts with a previous Res<{0}> access. Consider removing the duplicate access. See: https://bevy.org/learn/errors/b0002",
DebugName::type_name::<T>(), system_meta.name);
}
component_access_set.add_unfiltered_resource_write(component_id);
}
#[inline]
unsafe fn validate_param(
&mut component_id: &mut Self::State,
_system_meta: &SystemMeta,
world: UnsafeWorldCell,
) -> Result<(), SystemParamValidationError> {
if unsafe { world.storages() }
.resources
.get(component_id)
.is_some_and(ResourceData::is_present)
{
Ok(())
} else {
Err(SystemParamValidationError::invalid::<Self>(
"Resource does not exist",
))
}
}
#[inline]
unsafe fn get_param<'w, 's>(
&mut component_id: &'s mut Self::State,
system_meta: &SystemMeta,
world: UnsafeWorldCell<'w>,
change_tick: Tick,
) -> Self::Item<'w, 's> {
let value = world
.get_resource_mut_by_id(component_id)
.unwrap_or_else(|| {
panic!(
"Resource requested by {} does not exist: {}",
system_meta.name,
DebugName::type_name::<T>()
);
});
ResMut {
value: value.value.deref_mut::<T>(),
ticks: ComponentTicksMut {
added: value.ticks.added,
changed: value.ticks.changed,
changed_by: value.ticks.changed_by,
last_run: system_meta.last_run,
this_run: change_tick,
},
}
}
}
unsafe impl<'w> ReadOnlySystemParam for &'w World {}
unsafe impl SystemParam for &'_ World {
type State = ();
type Item<'w, 's> = &'w World;
fn init_state(_world: &mut World) -> Self::State {}
fn init_access(
_state: &Self::State,
_system_meta: &mut SystemMeta,
component_access_set: &mut FilteredAccessSet,
_world: &mut World,
) {
let mut filtered_access = FilteredAccess::default();
filtered_access.read_all();
if !component_access_set
.get_conflicts_single(&filtered_access)
.is_empty()
{
panic!("&World conflicts with a previous mutable system parameter. Allowing this would break Rust's mutability rules");
}
component_access_set.add(filtered_access);
}
#[inline]
unsafe fn get_param<'w, 's>(
_state: &'s mut Self::State,
_system_meta: &SystemMeta,
world: UnsafeWorldCell<'w>,
_change_tick: Tick,
) -> Self::Item<'w, 's> {
unsafe { world.world() }
}
}
unsafe impl<'w> SystemParam for DeferredWorld<'w> {
type State = ();
type Item<'world, 'state> = DeferredWorld<'world>;
fn init_state(_world: &mut World) -> Self::State {}
fn init_access(
_state: &Self::State,
system_meta: &mut SystemMeta,
component_access_set: &mut FilteredAccessSet,
_world: &mut World,
) {
assert!(
!component_access_set.combined_access().has_any_read(),
"DeferredWorld in system {} conflicts with a previous access.",
system_meta.name,
);
component_access_set.write_all();
}
unsafe fn get_param<'world, 'state>(
_state: &'state mut Self::State,
_system_meta: &SystemMeta,
world: UnsafeWorldCell<'world>,
_change_tick: Tick,
) -> Self::Item<'world, 'state> {
unsafe { world.into_deferred() }
}
}
#[derive(Debug)]
pub struct Local<'s, T: FromWorld + Send + 'static>(pub(crate) &'s mut T);
unsafe impl<'s, T: FromWorld + Send + 'static> ReadOnlySystemParam for Local<'s, T> {}
impl<'s, T: FromWorld + Send + 'static> Deref for Local<'s, T> {
type Target = T;
#[inline]
fn deref(&self) -> &Self::Target {
self.0
}
}
impl<'s, T: FromWorld + Send + 'static> DerefMut for Local<'s, T> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
self.0
}
}
impl<'s, 'a, T: FromWorld + Send + 'static> IntoIterator for &'a Local<'s, T>
where
&'a T: IntoIterator,
{
type Item = <&'a T as IntoIterator>::Item;
type IntoIter = <&'a T as IntoIterator>::IntoIter;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl<'s, 'a, T: FromWorld + Send + 'static> IntoIterator for &'a mut Local<'s, T>
where
&'a mut T: IntoIterator,
{
type Item = <&'a mut T as IntoIterator>::Item;
type IntoIter = <&'a mut T as IntoIterator>::IntoIter;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
unsafe impl<'a, T: FromWorld + Send + 'static> SystemParam for Local<'a, T> {
type State = SyncCell<T>;
type Item<'w, 's> = Local<'s, T>;
fn init_state(world: &mut World) -> Self::State {
SyncCell::new(T::from_world(world))
}
fn init_access(
_state: &Self::State,
_system_meta: &mut SystemMeta,
_component_access_set: &mut FilteredAccessSet,
_world: &mut World,
) {
}
#[inline]
unsafe fn get_param<'w, 's>(
state: &'s mut Self::State,
_system_meta: &SystemMeta,
_world: UnsafeWorldCell<'w>,
_change_tick: Tick,
) -> Self::Item<'w, 's> {
Local(state.get())
}
}
pub trait SystemBuffer: FromWorld + Send + 'static {
fn apply(&mut self, system_meta: &SystemMeta, world: &mut World);
fn queue(&mut self, _system_meta: &SystemMeta, _world: DeferredWorld) {}
}
pub struct Deferred<'a, T: SystemBuffer>(pub(crate) &'a mut T);
impl<'a, T: SystemBuffer> Deref for Deferred<'a, T> {
type Target = T;
#[inline]
fn deref(&self) -> &Self::Target {
self.0
}
}
impl<'a, T: SystemBuffer> DerefMut for Deferred<'a, T> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
self.0
}
}
impl<T: SystemBuffer> Deferred<'_, T> {
pub fn reborrow(&mut self) -> Deferred<'_, T> {
Deferred(self.0)
}
}
unsafe impl<T: SystemBuffer> ReadOnlySystemParam for Deferred<'_, T> {}
unsafe impl<T: SystemBuffer> SystemParam for Deferred<'_, T> {
type State = SyncCell<T>;
type Item<'w, 's> = Deferred<'s, T>;
#[track_caller]
fn init_state(world: &mut World) -> Self::State {
SyncCell::new(T::from_world(world))
}
fn init_access(
_state: &Self::State,
system_meta: &mut SystemMeta,
_component_access_set: &mut FilteredAccessSet,
_world: &mut World,
) {
system_meta.set_has_deferred();
}
fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) {
state.get().apply(system_meta, world);
}
fn queue(state: &mut Self::State, system_meta: &SystemMeta, world: DeferredWorld) {
state.get().queue(system_meta, world);
}
#[inline]
unsafe fn get_param<'w, 's>(
state: &'s mut Self::State,
_system_meta: &SystemMeta,
_world: UnsafeWorldCell<'w>,
_change_tick: Tick,
) -> Self::Item<'w, 's> {
Deferred(state.get())
}
}
pub struct ExclusiveMarker(PhantomData<()>);
unsafe impl SystemParam for ExclusiveMarker {
type State = ();
type Item<'w, 's> = Self;
#[inline]
fn init_state(_world: &mut World) -> Self::State {}
fn init_access(
_state: &Self::State,
system_meta: &mut SystemMeta,
_component_access_set: &mut FilteredAccessSet,
_world: &mut World,
) {
system_meta.set_exclusive();
}
#[inline]
unsafe fn get_param<'world, 'state>(
_state: &'state mut Self::State,
_system_meta: &SystemMeta,
_world: UnsafeWorldCell<'world>,
_change_tick: Tick,
) -> Self::Item<'world, 'state> {
Self(PhantomData)
}
}
unsafe impl ReadOnlySystemParam for ExclusiveMarker {}
pub struct NonSendMarker(PhantomData<*mut ()>);
unsafe impl SystemParam for NonSendMarker {
type State = ();
type Item<'w, 's> = Self;
#[inline]
fn init_state(_world: &mut World) -> Self::State {}
fn init_access(
_state: &Self::State,
system_meta: &mut SystemMeta,
_component_access_set: &mut FilteredAccessSet,
_world: &mut World,
) {
system_meta.set_non_send();
}
#[inline]
unsafe fn get_param<'world, 'state>(
_state: &'state mut Self::State,
_system_meta: &SystemMeta,
_world: UnsafeWorldCell<'world>,
_change_tick: Tick,
) -> Self::Item<'world, 'state> {
Self(PhantomData)
}
}
unsafe impl ReadOnlySystemParam for NonSendMarker {}
unsafe impl<'w, T> ReadOnlySystemParam for NonSend<'w, T> {}
unsafe impl<'a, T: 'static> SystemParam for NonSend<'a, T> {
type State = ComponentId;
type Item<'w, 's> = NonSend<'w, T>;
fn init_state(world: &mut World) -> Self::State {
world.components_registrator().register_non_send::<T>()
}
fn init_access(
&component_id: &Self::State,
system_meta: &mut SystemMeta,
component_access_set: &mut FilteredAccessSet,
_world: &mut World,
) {
system_meta.set_non_send();
let combined_access = component_access_set.combined_access();
assert!(
!combined_access.has_resource_write(component_id),
"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",
DebugName::type_name::<T>(),
system_meta.name,
);
component_access_set.add_unfiltered_resource_read(component_id);
}
#[inline]
unsafe fn validate_param(
&mut component_id: &mut Self::State,
_system_meta: &SystemMeta,
world: UnsafeWorldCell,
) -> Result<(), SystemParamValidationError> {
if unsafe { world.storages() }
.non_send_resources
.get(component_id)
.is_some_and(ResourceData::is_present)
{
Ok(())
} else {
Err(SystemParamValidationError::invalid::<Self>(
"Non-send resource does not exist",
))
}
}
#[inline]
unsafe fn get_param<'w, 's>(
&mut component_id: &'s mut Self::State,
system_meta: &SystemMeta,
world: UnsafeWorldCell<'w>,
change_tick: Tick,
) -> Self::Item<'w, 's> {
let (ptr, ticks) = world
.get_non_send_with_ticks(component_id)
.unwrap_or_else(|| {
panic!(
"Non-send resource requested by {} does not exist: {}",
system_meta.name,
DebugName::type_name::<T>()
);
});
NonSend {
value: ptr.deref(),
ticks: ComponentTicksRef::from_tick_cells(ticks, system_meta.last_run, change_tick),
}
}
}
unsafe impl<'a, T: 'static> SystemParam for NonSendMut<'a, T> {
type State = ComponentId;
type Item<'w, 's> = NonSendMut<'w, T>;
fn init_state(world: &mut World) -> Self::State {
world.components_registrator().register_non_send::<T>()
}
fn init_access(
&component_id: &Self::State,
system_meta: &mut SystemMeta,
component_access_set: &mut FilteredAccessSet,
_world: &mut World,
) {
system_meta.set_non_send();
let combined_access = component_access_set.combined_access();
if combined_access.has_resource_write(component_id) {
panic!(
"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",
DebugName::type_name::<T>(), system_meta.name);
} else if combined_access.has_resource_read(component_id) {
panic!(
"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",
DebugName::type_name::<T>(), system_meta.name);
}
component_access_set.add_unfiltered_resource_write(component_id);
}
#[inline]
unsafe fn validate_param(
&mut component_id: &mut Self::State,
_system_meta: &SystemMeta,
world: UnsafeWorldCell,
) -> Result<(), SystemParamValidationError> {
if unsafe { world.storages() }
.non_send_resources
.get(component_id)
.is_some_and(ResourceData::is_present)
{
Ok(())
} else {
Err(SystemParamValidationError::invalid::<Self>(
"Non-send resource does not exist",
))
}
}
#[inline]
unsafe fn get_param<'w, 's>(
&mut component_id: &'s mut Self::State,
system_meta: &SystemMeta,
world: UnsafeWorldCell<'w>,
change_tick: Tick,
) -> Self::Item<'w, 's> {
let (ptr, ticks) = world
.get_non_send_with_ticks(component_id)
.unwrap_or_else(|| {
panic!(
"Non-send resource requested by {} does not exist: {}",
system_meta.name,
DebugName::type_name::<T>()
);
});
NonSendMut {
value: ptr.assert_unique().deref_mut(),
ticks: ComponentTicksMut::from_tick_cells(ticks, system_meta.last_run, change_tick),
}
}
}
unsafe impl<'a> ReadOnlySystemParam for &'a Archetypes {}
unsafe impl<'a> SystemParam for &'a Archetypes {
type State = ();
type Item<'w, 's> = &'w Archetypes;
fn init_state(_world: &mut World) -> Self::State {}
fn init_access(
_state: &Self::State,
_system_meta: &mut SystemMeta,
_component_access_set: &mut FilteredAccessSet,
_world: &mut World,
) {
}
#[inline]
unsafe fn get_param<'w, 's>(
_state: &'s mut Self::State,
_system_meta: &SystemMeta,
world: UnsafeWorldCell<'w>,
_change_tick: Tick,
) -> Self::Item<'w, 's> {
world.archetypes()
}
}
unsafe impl<'a> ReadOnlySystemParam for &'a Components {}
unsafe impl<'a> SystemParam for &'a Components {
type State = ();
type Item<'w, 's> = &'w Components;
fn init_state(_world: &mut World) -> Self::State {}
fn init_access(
_state: &Self::State,
_system_meta: &mut SystemMeta,
_component_access_set: &mut FilteredAccessSet,
_world: &mut World,
) {
}
#[inline]
unsafe fn get_param<'w, 's>(
_state: &'s mut Self::State,
_system_meta: &SystemMeta,
world: UnsafeWorldCell<'w>,
_change_tick: Tick,
) -> Self::Item<'w, 's> {
world.components()
}
}
unsafe impl<'a> ReadOnlySystemParam for &'a Entities {}
unsafe impl<'a> SystemParam for &'a Entities {
type State = ();
type Item<'w, 's> = &'w Entities;
fn init_state(_world: &mut World) -> Self::State {}
fn init_access(
_state: &Self::State,
_system_meta: &mut SystemMeta,
_component_access_set: &mut FilteredAccessSet,
_world: &mut World,
) {
}
#[inline]
unsafe fn get_param<'w, 's>(
_state: &'s mut Self::State,
_system_meta: &SystemMeta,
world: UnsafeWorldCell<'w>,
_change_tick: Tick,
) -> Self::Item<'w, 's> {
world.entities()
}
}
unsafe impl<'a> ReadOnlySystemParam for &'a EntityAllocator {}
unsafe impl<'a> SystemParam for &'a EntityAllocator {
type State = ();
type Item<'w, 's> = &'w EntityAllocator;
fn init_state(_world: &mut World) -> Self::State {}
fn init_access(
_state: &Self::State,
_system_meta: &mut SystemMeta,
_component_access_set: &mut FilteredAccessSet,
_world: &mut World,
) {
}
#[inline]
unsafe fn get_param<'w, 's>(
_state: &'s mut Self::State,
_system_meta: &SystemMeta,
world: UnsafeWorldCell<'w>,
_change_tick: Tick,
) -> Self::Item<'w, 's> {
world.entities_allocator()
}
}
unsafe impl<'a> ReadOnlySystemParam for &'a Bundles {}
unsafe impl<'a> SystemParam for &'a Bundles {
type State = ();
type Item<'w, 's> = &'w Bundles;
fn init_state(_world: &mut World) -> Self::State {}
fn init_access(
_state: &Self::State,
_system_meta: &mut SystemMeta,
_component_access_set: &mut FilteredAccessSet,
_world: &mut World,
) {
}
#[inline]
unsafe fn get_param<'w, 's>(
_state: &'s mut Self::State,
_system_meta: &SystemMeta,
world: UnsafeWorldCell<'w>,
_change_tick: Tick,
) -> Self::Item<'w, 's> {
world.bundles()
}
}
#[derive(Debug, Clone, Copy)]
pub struct SystemChangeTick {
last_run: Tick,
this_run: Tick,
}
impl SystemChangeTick {
#[inline]
pub fn this_run(&self) -> Tick {
self.this_run
}
#[inline]
pub fn last_run(&self) -> Tick {
self.last_run
}
}
unsafe impl ReadOnlySystemParam for SystemChangeTick {}
unsafe impl SystemParam for SystemChangeTick {
type State = ();
type Item<'w, 's> = SystemChangeTick;
fn init_state(_world: &mut World) -> Self::State {}
fn init_access(
_state: &Self::State,
_system_meta: &mut SystemMeta,
_component_access_set: &mut FilteredAccessSet,
_world: &mut World,
) {
}
#[inline]
unsafe fn get_param<'w, 's>(
_state: &'s mut Self::State,
system_meta: &SystemMeta,
_world: UnsafeWorldCell<'w>,
change_tick: Tick,
) -> Self::Item<'w, 's> {
SystemChangeTick {
last_run: system_meta.last_run,
this_run: change_tick,
}
}
}
unsafe impl<T: SystemParam> SystemParam for Option<T> {
type State = T::State;
type Item<'world, 'state> = Option<T::Item<'world, 'state>>;
fn init_state(world: &mut World) -> Self::State {
T::init_state(world)
}
fn init_access(
state: &Self::State,
system_meta: &mut SystemMeta,
component_access_set: &mut FilteredAccessSet,
world: &mut World,
) {
T::init_access(state, system_meta, component_access_set, world);
}
#[inline]
unsafe fn get_param<'world, 'state>(
state: &'state mut Self::State,
system_meta: &SystemMeta,
world: UnsafeWorldCell<'world>,
change_tick: Tick,
) -> Self::Item<'world, 'state> {
unsafe {
T::validate_param(state, system_meta, world)
.ok()
.map(|()| T::get_param(state, system_meta, world, change_tick))
}
}
fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) {
T::apply(state, system_meta, world);
}
fn queue(state: &mut Self::State, system_meta: &SystemMeta, world: DeferredWorld) {
T::queue(state, system_meta, world);
}
}
unsafe impl<T: ReadOnlySystemParam> ReadOnlySystemParam for Option<T> {}
unsafe impl<T: SystemParam> SystemParam for Result<T, SystemParamValidationError> {
type State = T::State;
type Item<'world, 'state> = Result<T::Item<'world, 'state>, SystemParamValidationError>;
fn init_state(world: &mut World) -> Self::State {
T::init_state(world)
}
fn init_access(
state: &Self::State,
system_meta: &mut SystemMeta,
component_access_set: &mut FilteredAccessSet,
world: &mut World,
) {
T::init_access(state, system_meta, component_access_set, world);
}
#[inline]
unsafe fn get_param<'world, 'state>(
state: &'state mut Self::State,
system_meta: &SystemMeta,
world: UnsafeWorldCell<'world>,
change_tick: Tick,
) -> Self::Item<'world, 'state> {
unsafe {
T::validate_param(state, system_meta, world)
.map(|()| T::get_param(state, system_meta, world, change_tick))
}
}
fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) {
T::apply(state, system_meta, world);
}
fn queue(state: &mut Self::State, system_meta: &SystemMeta, world: DeferredWorld) {
T::queue(state, system_meta, world);
}
}
unsafe impl<T: ReadOnlySystemParam> ReadOnlySystemParam for Result<T, SystemParamValidationError> {}
#[derive(Debug)]
pub struct If<T>(pub T);
impl<T> If<T> {
pub fn into_inner(self) -> T {
self.0
}
}
impl<T> Deref for If<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T> DerefMut for If<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
unsafe impl<T: SystemParam> SystemParam for If<T> {
type State = T::State;
type Item<'world, 'state> = If<T::Item<'world, 'state>>;
fn init_state(world: &mut World) -> Self::State {
T::init_state(world)
}
fn init_access(
state: &Self::State,
system_meta: &mut SystemMeta,
component_access_set: &mut FilteredAccessSet,
world: &mut World,
) {
T::init_access(state, system_meta, component_access_set, world);
}
#[inline]
unsafe fn validate_param(
state: &mut Self::State,
system_meta: &SystemMeta,
world: UnsafeWorldCell,
) -> Result<(), SystemParamValidationError> {
unsafe { T::validate_param(state, system_meta, world) }.map_err(|mut e| {
e.skipped = true;
e
})
}
#[inline]
unsafe fn get_param<'world, 'state>(
state: &'state mut Self::State,
system_meta: &SystemMeta,
world: UnsafeWorldCell<'world>,
change_tick: Tick,
) -> Self::Item<'world, 'state> {
If(unsafe { T::get_param(state, system_meta, world, change_tick) })
}
fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) {
T::apply(state, system_meta, world);
}
fn queue(state: &mut Self::State, system_meta: &SystemMeta, world: DeferredWorld) {
T::queue(state, system_meta, world);
}
}
unsafe impl<T: ReadOnlySystemParam> ReadOnlySystemParam for If<T> {}
unsafe impl<T: SystemParam> SystemParam for Vec<T> {
type State = Vec<T::State>;
type Item<'world, 'state> = Vec<T::Item<'world, 'state>>;
fn init_state(_world: &mut World) -> Self::State {
Vec::new()
}
fn init_access(
state: &Self::State,
system_meta: &mut SystemMeta,
component_access_set: &mut FilteredAccessSet,
world: &mut World,
) {
for state in state {
T::init_access(state, system_meta, component_access_set, world);
}
}
#[inline]
unsafe fn validate_param(
state: &mut Self::State,
system_meta: &SystemMeta,
world: UnsafeWorldCell,
) -> Result<(), SystemParamValidationError> {
for state in state {
unsafe { T::validate_param(state, system_meta, world)? };
}
Ok(())
}
#[inline]
unsafe fn get_param<'world, 'state>(
state: &'state mut Self::State,
system_meta: &SystemMeta,
world: UnsafeWorldCell<'world>,
change_tick: Tick,
) -> Self::Item<'world, 'state> {
state
.iter_mut()
.map(|state| unsafe { T::get_param(state, system_meta, world, change_tick) })
.collect()
}
fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) {
for state in state {
T::apply(state, system_meta, world);
}
}
fn queue(state: &mut Self::State, system_meta: &SystemMeta, mut world: DeferredWorld) {
for state in state {
T::queue(state, system_meta, world.reborrow());
}
}
}
unsafe impl<T: SystemParam> SystemParam for ParamSet<'_, '_, Vec<T>> {
type State = Vec<T::State>;
type Item<'world, 'state> = ParamSet<'world, 'state, Vec<T>>;
fn init_state(_world: &mut World) -> Self::State {
Vec::new()
}
fn init_access(
state: &Self::State,
system_meta: &mut SystemMeta,
component_access_set: &mut FilteredAccessSet,
world: &mut World,
) {
for state in state {
let component_access_set_clone = &mut component_access_set.clone();
T::init_access(state, system_meta, component_access_set_clone, world);
}
for state in state {
let mut access_set = FilteredAccessSet::new();
T::init_access(state, system_meta, &mut access_set, world);
component_access_set.extend(access_set);
}
}
#[inline]
unsafe fn get_param<'world, 'state>(
state: &'state mut Self::State,
system_meta: &SystemMeta,
world: UnsafeWorldCell<'world>,
change_tick: Tick,
) -> Self::Item<'world, 'state> {
ParamSet {
param_states: state,
system_meta: system_meta.clone(),
world,
change_tick,
}
}
fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) {
for state in state {
T::apply(state, system_meta, world);
}
}
fn queue(state: &mut Self::State, system_meta: &SystemMeta, mut world: DeferredWorld) {
for state in state {
T::queue(state, system_meta, world.reborrow());
}
}
}
impl<T: SystemParam> ParamSet<'_, '_, Vec<T>> {
pub fn get_mut(&mut self, index: usize) -> T::Item<'_, '_> {
unsafe {
T::get_param(
&mut self.param_states[index],
&self.system_meta,
self.world,
self.change_tick,
)
}
}
pub fn for_each(&mut self, mut f: impl FnMut(T::Item<'_, '_>)) {
self.param_states.iter_mut().for_each(|state| {
f(
unsafe { T::get_param(state, &self.system_meta, self.world, self.change_tick) },
);
});
}
}
macro_rules! impl_system_param_tuple {
($(#[$meta:meta])* $($param: ident),*) => {
$(#[$meta])*
unsafe impl<$($param: ReadOnlySystemParam),*> ReadOnlySystemParam for ($($param,)*) {}
#[expect(
clippy::allow_attributes,
reason = "This is in a macro, and as such, the below lints may not always apply."
)]
#[allow(
non_snake_case,
reason = "Certain variable names are provided by the caller, not by us."
)]
#[allow(
unused_variables,
reason = "Zero-length tuples won't use some of the parameters."
)]
#[allow(clippy::unused_unit, reason = "Zero length tuple is unit.")]
$(#[$meta])*
unsafe impl<$($param: SystemParam),*> SystemParam for ($($param,)*) {
type State = ($($param::State,)*);
type Item<'w, 's> = ($($param::Item::<'w, 's>,)*);
#[inline]
#[track_caller]
fn init_state(world: &mut World) -> Self::State {
($($param::init_state(world),)*)
}
fn init_access(state: &Self::State, _system_meta: &mut SystemMeta, _component_access_set: &mut FilteredAccessSet, _world: &mut World) {
let ($($param,)*) = state;
$($param::init_access($param, _system_meta, _component_access_set, _world);)*
}
#[inline]
fn apply(($($param,)*): &mut Self::State, system_meta: &SystemMeta, world: &mut World) {
$($param::apply($param, system_meta, world);)*
}
#[inline]
#[allow(
unused_mut,
reason = "The `world` parameter is unused for zero-length tuples; however, it must be mutable for other lengths of tuples."
)]
fn queue(($($param,)*): &mut Self::State, system_meta: &SystemMeta, mut world: DeferredWorld) {
$($param::queue($param, system_meta, world.reborrow());)*
}
#[inline]
unsafe fn validate_param(
state: &mut Self::State,
system_meta: &SystemMeta,
world: UnsafeWorldCell,
) -> Result<(), SystemParamValidationError> {
let ($($param,)*) = state;
#[allow(
unused_unsafe,
reason = "Zero-length tuples won't have any params to validate."
)]
unsafe {
$(
$param::validate_param($param, system_meta, world)?;
)*
}
Ok(())
}
#[inline]
#[track_caller]
unsafe fn get_param<'w, 's>(
state: &'s mut Self::State,
system_meta: &SystemMeta,
world: UnsafeWorldCell<'w>,
change_tick: Tick,
) -> Self::Item<'w, 's> {
let ($($param,)*) = state;
#[allow(
unused_unsafe,
reason = "Zero-length tuples won't have any params to validate."
)]
unsafe {
#[allow(
clippy::unused_unit,
reason = "Zero-length tuples won't have any params to get."
)]
($($param::get_param($param, system_meta, world, change_tick),)*)
}
}
}
};
}
all_tuples!(
#[doc(fake_variadic)]
impl_system_param_tuple,
0,
16,
P
);
pub mod lifetimeless {
pub type SQuery<D, F = ()> = super::Query<'static, 'static, D, F>;
pub type Read<T> = &'static T;
pub type Write<T> = &'static mut T;
pub type SRes<T> = super::Res<'static, T>;
pub type SResMut<T> = super::ResMut<'static, T>;
pub type SCommands = crate::system::Commands<'static, 'static>;
}
pub struct StaticSystemParam<'w, 's, P: SystemParam>(SystemParamItem<'w, 's, P>);
impl<'w, 's, P: SystemParam> Deref for StaticSystemParam<'w, 's, P> {
type Target = SystemParamItem<'w, 's, P>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<'w, 's, P: SystemParam> DerefMut for StaticSystemParam<'w, 's, P> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<'w, 's, P: SystemParam> StaticSystemParam<'w, 's, P> {
pub fn into_inner(self) -> SystemParamItem<'w, 's, P> {
self.0
}
}
unsafe impl<'w, 's, P: ReadOnlySystemParam + 'static> ReadOnlySystemParam
for StaticSystemParam<'w, 's, P>
{
}
unsafe impl<P: SystemParam + 'static> SystemParam for StaticSystemParam<'_, '_, P> {
type State = P::State;
type Item<'world, 'state> = StaticSystemParam<'world, 'state, P>;
fn init_state(world: &mut World) -> Self::State {
P::init_state(world)
}
fn init_access(
state: &Self::State,
system_meta: &mut SystemMeta,
component_access_set: &mut FilteredAccessSet,
world: &mut World,
) {
P::init_access(state, system_meta, component_access_set, world);
}
fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) {
P::apply(state, system_meta, world);
}
fn queue(state: &mut Self::State, system_meta: &SystemMeta, world: DeferredWorld) {
P::queue(state, system_meta, world);
}
#[inline]
unsafe fn validate_param(
state: &mut Self::State,
system_meta: &SystemMeta,
world: UnsafeWorldCell,
) -> Result<(), SystemParamValidationError> {
unsafe { P::validate_param(state, system_meta, world) }
}
#[inline]
unsafe fn get_param<'world, 'state>(
state: &'state mut Self::State,
system_meta: &SystemMeta,
world: UnsafeWorldCell<'world>,
change_tick: Tick,
) -> Self::Item<'world, 'state> {
StaticSystemParam(unsafe { P::get_param(state, system_meta, world, change_tick) })
}
}
unsafe impl<T: ?Sized> SystemParam for PhantomData<T> {
type State = ();
type Item<'world, 'state> = Self;
fn init_state(_world: &mut World) -> Self::State {}
fn init_access(
_state: &Self::State,
_system_meta: &mut SystemMeta,
_component_access_set: &mut FilteredAccessSet,
_world: &mut World,
) {
}
#[inline]
unsafe fn get_param<'world, 'state>(
_state: &'state mut Self::State,
_system_meta: &SystemMeta,
_world: UnsafeWorldCell<'world>,
_change_tick: Tick,
) -> Self::Item<'world, 'state> {
PhantomData
}
}
unsafe impl<T: ?Sized> ReadOnlySystemParam for PhantomData<T> {}
pub struct DynSystemParam<'w, 's> {
state: &'s mut dyn Any,
world: UnsafeWorldCell<'w>,
system_meta: SystemMeta,
change_tick: Tick,
}
impl<'w, 's> DynSystemParam<'w, 's> {
unsafe fn new(
state: &'s mut dyn Any,
world: UnsafeWorldCell<'w>,
system_meta: SystemMeta,
change_tick: Tick,
) -> Self {
Self {
state,
world,
system_meta,
change_tick,
}
}
pub fn is<T: SystemParam>(&self) -> bool
where
T::Item<'static, 'static>: SystemParam<Item<'w, 's> = T> + 'static,
{
self.state.is::<ParamState<T::Item<'static, 'static>>>()
}
pub fn downcast<T: SystemParam>(self) -> Option<T>
where
T::Item<'static, 'static>: SystemParam<Item<'w, 's> = T> + 'static,
{
unsafe { downcast::<T>(self.state, &self.system_meta, self.world, self.change_tick) }
}
pub fn downcast_mut<'a, T: SystemParam>(&'a mut self) -> Option<T>
where
T::Item<'static, 'static>: SystemParam<Item<'a, 'a> = T> + 'static,
{
unsafe { downcast::<T>(self.state, &self.system_meta, self.world, self.change_tick) }
}
pub fn downcast_mut_inner<'a, T: ReadOnlySystemParam>(&'a mut self) -> Option<T>
where
T::Item<'static, 'static>: SystemParam<Item<'w, 'a> = T> + 'static,
{
unsafe { downcast::<T>(self.state, &self.system_meta, self.world, self.change_tick) }
}
}
unsafe fn downcast<'w, 's, T: SystemParam>(
state: &'s mut dyn Any,
system_meta: &SystemMeta,
world: UnsafeWorldCell<'w>,
change_tick: Tick,
) -> Option<T>
where
T::Item<'static, 'static>: SystemParam<Item<'w, 's> = T> + 'static,
{
state
.downcast_mut::<ParamState<T::Item<'static, 'static>>>()
.map(|state| {
unsafe { T::Item::get_param(&mut state.0, system_meta, world, change_tick) }
})
}
pub struct DynSystemParamState(Box<dyn DynParamState>);
impl DynSystemParamState {
pub(crate) fn new<T: SystemParam + 'static>(state: T::State) -> Self {
Self(Box::new(ParamState::<T>(state)))
}
}
trait DynParamState: Sync + Send + Any {
fn apply(&mut self, system_meta: &SystemMeta, world: &mut World);
fn queue(&mut self, system_meta: &SystemMeta, world: DeferredWorld);
fn init_access(
&self,
system_meta: &mut SystemMeta,
component_access_set: &mut FilteredAccessSet,
world: &mut World,
);
unsafe fn validate_param(
&mut self,
system_meta: &SystemMeta,
world: UnsafeWorldCell,
) -> Result<(), SystemParamValidationError>;
}
struct ParamState<T: SystemParam>(T::State);
impl<T: SystemParam + 'static> DynParamState for ParamState<T> {
fn apply(&mut self, system_meta: &SystemMeta, world: &mut World) {
T::apply(&mut self.0, system_meta, world);
}
fn queue(&mut self, system_meta: &SystemMeta, world: DeferredWorld) {
T::queue(&mut self.0, system_meta, world);
}
fn init_access(
&self,
system_meta: &mut SystemMeta,
component_access_set: &mut FilteredAccessSet,
world: &mut World,
) {
T::init_access(&self.0, system_meta, component_access_set, world);
}
unsafe fn validate_param(
&mut self,
system_meta: &SystemMeta,
world: UnsafeWorldCell,
) -> Result<(), SystemParamValidationError> {
unsafe { T::validate_param(&mut self.0, system_meta, world) }
}
}
unsafe impl SystemParam for DynSystemParam<'_, '_> {
type State = DynSystemParamState;
type Item<'world, 'state> = DynSystemParam<'world, 'state>;
fn init_state(_world: &mut World) -> Self::State {
DynSystemParamState::new::<()>(())
}
fn init_access(
state: &Self::State,
system_meta: &mut SystemMeta,
component_access_set: &mut FilteredAccessSet,
world: &mut World,
) {
state
.0
.init_access(system_meta, component_access_set, world);
}
#[inline]
unsafe fn validate_param(
state: &mut Self::State,
system_meta: &SystemMeta,
world: UnsafeWorldCell,
) -> Result<(), SystemParamValidationError> {
unsafe { state.0.validate_param(system_meta, world) }
}
#[inline]
unsafe fn get_param<'world, 'state>(
state: &'state mut Self::State,
system_meta: &SystemMeta,
world: UnsafeWorldCell<'world>,
change_tick: Tick,
) -> Self::Item<'world, 'state> {
unsafe { DynSystemParam::new(state.0.as_mut(), world, system_meta.clone(), change_tick) }
}
fn apply(state: &mut Self::State, system_meta: &SystemMeta, world: &mut World) {
state.0.apply(system_meta, world);
}
fn queue(state: &mut Self::State, system_meta: &SystemMeta, world: DeferredWorld) {
state.0.queue(system_meta, world);
}
}
unsafe impl SystemParam for FilteredResources<'_, '_> {
type State = Access;
type Item<'world, 'state> = FilteredResources<'world, 'state>;
fn init_state(_world: &mut World) -> Self::State {
Access::new()
}
fn init_access(
access: &Self::State,
system_meta: &mut SystemMeta,
component_access_set: &mut FilteredAccessSet,
world: &mut World,
) {
let combined_access = component_access_set.combined_access();
let conflicts = combined_access.get_conflicts(access);
if !conflicts.is_empty() {
let accesses = conflicts.format_conflict_list(world);
let system_name = &system_meta.name;
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");
}
if access.has_read_all_resources() {
component_access_set.add_unfiltered_read_all_resources();
} else {
for component_id in access.resource_reads_and_writes() {
component_access_set.add_unfiltered_resource_read(component_id);
}
}
}
unsafe fn get_param<'world, 'state>(
state: &'state mut Self::State,
system_meta: &SystemMeta,
world: UnsafeWorldCell<'world>,
change_tick: Tick,
) -> Self::Item<'world, 'state> {
unsafe { FilteredResources::new(world, state, system_meta.last_run, change_tick) }
}
}
unsafe impl ReadOnlySystemParam for FilteredResources<'_, '_> {}
unsafe impl SystemParam for FilteredResourcesMut<'_, '_> {
type State = Access;
type Item<'world, 'state> = FilteredResourcesMut<'world, 'state>;
fn init_state(_world: &mut World) -> Self::State {
Access::new()
}
fn init_access(
access: &Self::State,
system_meta: &mut SystemMeta,
component_access_set: &mut FilteredAccessSet,
world: &mut World,
) {
let combined_access = component_access_set.combined_access();
let conflicts = combined_access.get_conflicts(access);
if !conflicts.is_empty() {
let accesses = conflicts.format_conflict_list(world);
let system_name = &system_meta.name;
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");
}
if access.has_read_all_resources() {
component_access_set.add_unfiltered_read_all_resources();
} else {
for component_id in access.resource_reads() {
component_access_set.add_unfiltered_resource_read(component_id);
}
}
if access.has_write_all_resources() {
component_access_set.add_unfiltered_write_all_resources();
} else {
for component_id in access.resource_writes() {
component_access_set.add_unfiltered_resource_write(component_id);
}
}
}
unsafe fn get_param<'world, 'state>(
state: &'state mut Self::State,
system_meta: &SystemMeta,
world: UnsafeWorldCell<'world>,
change_tick: Tick,
) -> Self::Item<'world, 'state> {
unsafe { FilteredResourcesMut::new(world, state, system_meta.last_run, change_tick) }
}
}
#[derive(Debug, PartialEq, Eq, Clone, Error)]
pub struct SystemParamValidationError {
pub skipped: bool,
pub message: Cow<'static, str>,
pub param: DebugName,
pub field: Cow<'static, str>,
}
impl SystemParamValidationError {
pub fn skipped<T>(message: impl Into<Cow<'static, str>>) -> Self {
Self::new::<T>(true, message, Cow::Borrowed(""))
}
pub fn invalid<T>(message: impl Into<Cow<'static, str>>) -> Self {
Self::new::<T>(false, message, Cow::Borrowed(""))
}
pub fn new<T>(
skipped: bool,
message: impl Into<Cow<'static, str>>,
field: impl Into<Cow<'static, str>>,
) -> Self {
Self {
skipped,
message: message.into(),
param: DebugName::type_name::<T>(),
field: field.into(),
}
}
pub(crate) const EMPTY: Self = Self {
skipped: false,
message: Cow::Borrowed(""),
param: DebugName::borrowed(""),
field: Cow::Borrowed(""),
};
}
impl Display for SystemParamValidationError {
fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
write!(
fmt,
"Parameter `{}{}` failed validation: {}",
self.param.shortname(),
self.field,
self.message
)?;
if !self.skipped {
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.")?;
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::system::assert_is_system;
use core::cell::RefCell;
#[test]
#[should_panic]
fn non_send_alias() {
#[derive(Resource)]
struct A(usize);
fn my_system(mut res0: NonSendMut<A>, mut res1: NonSendMut<A>) {
res0.0 += 1;
res1.0 += 1;
}
let mut world = World::new();
world.insert_non_send_resource(A(42));
let mut schedule = crate::schedule::Schedule::default();
schedule.add_systems(my_system);
schedule.run(&mut world);
}
#[test]
fn system_param_generic_bounds() {
#[derive(SystemParam)]
pub struct SpecialQuery<
'w,
's,
D: QueryData + Send + Sync + 'static,
F: QueryFilter + Send + Sync + 'static = (),
> {
_query: Query<'w, 's, D, F>,
}
fn my_system(_: SpecialQuery<(), ()>) {}
assert_is_system(my_system);
}
#[test]
fn system_param_flexibility() {
#[derive(SystemParam)]
pub struct SpecialRes<'w, T: Resource> {
_res: Res<'w, T>,
}
#[derive(SystemParam)]
pub struct SpecialLocal<'s, T: FromWorld + Send + 'static> {
_local: Local<'s, T>,
}
#[derive(Resource)]
struct R;
fn my_system(_: SpecialRes<R>, _: SpecialLocal<u32>) {}
assert_is_system(my_system);
}
#[derive(Resource)]
pub struct R<const I: usize>;
#[test]
fn system_param_const_generics() {
#[expect(
dead_code,
reason = "This struct is used to ensure that const generics are supported as a SystemParam; thus, the inner value never needs to be read."
)]
#[derive(SystemParam)]
pub struct ConstGenericParam<'w, const I: usize>(Res<'w, R<I>>);
fn my_system(_: ConstGenericParam<0>, _: ConstGenericParam<1000>) {}
assert_is_system(my_system);
}
#[test]
fn system_param_field_limit() {
#[derive(SystemParam)]
pub struct LongParam<'w> {
_r0: Res<'w, R<0>>,
_r1: Res<'w, R<1>>,
_r2: Res<'w, R<2>>,
_r3: Res<'w, R<3>>,
_r4: Res<'w, R<4>>,
_r5: Res<'w, R<5>>,
_r6: Res<'w, R<6>>,
_r7: Res<'w, R<7>>,
_r8: Res<'w, R<8>>,
_r9: Res<'w, R<9>>,
_r10: Res<'w, R<10>>,
_r11: Res<'w, R<11>>,
_r12: Res<'w, R<12>>,
_r13: Res<'w, R<13>>,
_r14: Res<'w, R<14>>,
_r15: Res<'w, R<15>>,
_r16: Res<'w, R<16>>,
}
fn long_system(_: LongParam) {}
assert_is_system(long_system);
}
#[test]
fn system_param_phantom_data() {
#[derive(SystemParam)]
struct PhantomParam<'w, T: Resource, Marker: 'static> {
_foo: Res<'w, T>,
marker: PhantomData<&'w Marker>,
}
fn my_system(_: PhantomParam<R<0>, ()>) {}
assert_is_system(my_system);
}
#[test]
fn system_param_struct_variants() {
#[derive(SystemParam)]
pub struct UnitParam;
#[expect(
dead_code,
reason = "This struct is used to ensure that tuple structs are supported as a SystemParam; thus, the inner values never need to be read."
)]
#[derive(SystemParam)]
pub struct TupleParam<'w, 's, R: Resource, L: FromWorld + Send + 'static>(
Res<'w, R>,
Local<'s, L>,
);
fn my_system(_: UnitParam, _: TupleParam<R<0>, u32>) {}
assert_is_system(my_system);
}
#[test]
fn system_param_private_fields() {
#[derive(Resource)]
struct PrivateResource;
#[expect(
dead_code,
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."
)]
#[derive(SystemParam)]
pub struct EncapsulatedParam<'w>(Res<'w, PrivateResource>);
fn my_system(_: EncapsulatedParam) {}
assert_is_system(my_system);
}
#[test]
fn system_param_where_clause() {
#[derive(SystemParam)]
pub struct WhereParam<'w, 's, D>
where
D: 'static + QueryData,
{
_q: Query<'w, 's, D, ()>,
}
fn my_system(_: WhereParam<()>) {}
assert_is_system(my_system);
}
#[test]
fn system_param_name_collision() {
#[derive(Resource)]
pub struct FetchState;
#[derive(SystemParam)]
pub struct Collide<'w> {
_x: Res<'w, FetchState>,
}
fn my_system(_: Collide) {}
assert_is_system(my_system);
}
#[test]
fn system_param_invariant_lifetime() {
#[derive(SystemParam)]
pub struct InvariantParam<'w, 's> {
_set: ParamSet<'w, 's, (Query<'w, 's, ()>,)>,
}
fn my_system(_: InvariantParam) {}
assert_is_system(my_system);
}
#[test]
fn non_sync_local() {
fn non_sync_system(cell: Local<RefCell<u8>>) {
assert_eq!(*cell.borrow(), 0);
}
let mut world = World::new();
let mut schedule = crate::schedule::Schedule::default();
schedule.add_systems(non_sync_system);
schedule.run(&mut world);
}
#[test]
fn param_set_non_send_first() {
fn non_send_param_set(mut p: ParamSet<(NonSend<*mut u8>, ())>) {
let _ = p.p0();
p.p1();
}
let mut world = World::new();
world.insert_non_send_resource(core::ptr::null_mut::<u8>());
let mut schedule = crate::schedule::Schedule::default();
schedule.add_systems((non_send_param_set, non_send_param_set, non_send_param_set));
schedule.run(&mut world);
}
#[test]
fn param_set_non_send_second() {
fn non_send_param_set(mut p: ParamSet<((), NonSendMut<*mut u8>)>) {
p.p0();
let _ = p.p1();
}
let mut world = World::new();
world.insert_non_send_resource(core::ptr::null_mut::<u8>());
let mut schedule = crate::schedule::Schedule::default();
schedule.add_systems((non_send_param_set, non_send_param_set, non_send_param_set));
schedule.run(&mut world);
}
fn _dyn_system_param_type_inference(mut p: DynSystemParam) {
let _query: Query<()> = p.downcast_mut().unwrap();
let _query: Query<()> = p.downcast_mut_inner().unwrap();
let _query: Query<()> = p.downcast().unwrap();
}
#[test]
#[should_panic]
fn missing_resource_error() {
#[derive(Resource)]
pub struct MissingResource;
let mut schedule = crate::schedule::Schedule::default();
schedule.add_systems(res_system);
let mut world = World::new();
schedule.run(&mut world);
fn res_system(_: Res<MissingResource>) {}
}
#[test]
#[should_panic]
fn missing_message_error() {
use crate::prelude::{Message, MessageReader};
#[derive(Message)]
pub struct MissingEvent;
let mut schedule = crate::schedule::Schedule::default();
schedule.add_systems(message_system);
let mut world = World::new();
schedule.run(&mut world);
fn message_system(_: MessageReader<MissingEvent>) {}
}
}