Simplify trait hierarchy for SystemParam (#6865)

# Objective

* Implementing a custom `SystemParam` by hand requires implementing three traits -- four if it is read-only.
* The trait `SystemParamFetch<'w, 's>` is a workaround from before we had generic associated types, and is no longer necessary.

## Solution

* Combine the trait `SystemParamFetch` with `SystemParamState`.
    * I decided to remove the `Fetch` name and keep the `State` name, since the former was consistently conflated with the latter.
* Replace the trait `ReadOnlySystemParamFetch` with `ReadOnlySystemParam`, which simplifies trait bounds in generic code.

---

## Changelog

- Removed the trait `SystemParamFetch`, moving its functionality to `SystemParamState`.
- Replaced the trait `ReadOnlySystemParamFetch` with `ReadOnlySystemParam`.

## Migration Guide

The trait `SystemParamFetch` has been removed, and its functionality has been transferred to `SystemParamState`.

```rust
// Before
impl SystemParamState for MyParamState {
    fn init(world: &mut World, system_meta: &mut SystemMeta) -> Self { ... }
}
impl<'w, 's> SystemParamFetch<'w, 's> for MyParamState {
    type Item = MyParam<'w, 's>;
    fn get_param(...) -> Self::Item;
}

// After
impl SystemParamState for MyParamState {
    type Item<'w, 's> = MyParam<'w, 's>; // Generic associated types!
    fn init(world: &mut World, system_meta: &mut SystemMeta) -> Self { ... }
    fn get_param<'w, 's>(...) -> Self::Item<'w, 's>;
}
```

The trait `ReadOnlySystemParamFetch` has been replaced with `ReadOnlySystemParam`.

```rust
// Before
unsafe impl ReadOnlySystemParamFetch for MyParamState {}

// After
unsafe impl<'w, 's> ReadOnlySystemParam for MyParam<'w, 's> {}
```
This commit is contained in:
JoJoJet 2022-12-11 18:34:14 +00:00
parent c16791ce67
commit 1af73624fa
10 changed files with 318 additions and 386 deletions

View file

@ -209,19 +209,19 @@ pub fn impl_param_set(_input: TokenStream) -> TokenStream {
let mut tokens = TokenStream::new();
let max_params = 8;
let params = get_idents(|i| format!("P{i}"), max_params);
let params_fetch = get_idents(|i| format!("PF{i}"), max_params);
let params_state = get_idents(|i| format!("PF{i}"), max_params);
let metas = get_idents(|i| format!("m{i}"), max_params);
let mut param_fn_muts = Vec::new();
for (i, param) in params.iter().enumerate() {
let fn_name = Ident::new(&format!("p{i}"), Span::call_site());
let index = Index::from(i);
param_fn_muts.push(quote! {
pub fn #fn_name<'a>(&'a mut self) -> <#param::Fetch as SystemParamFetch<'a, 'a>>::Item {
pub fn #fn_name<'a>(&'a mut self) -> SystemParamItem<'a, 'a, #param> {
// SAFETY: systems run without conflicts with other systems.
// Conflicting params in ParamSet are not accessible at the same time
// ParamSets are guaranteed to not conflict with other SystemParams
unsafe {
<#param::Fetch as SystemParamFetch<'a, 'a>>::get_param(&mut self.param_states.#index, &self.system_meta, self.world, self.change_tick)
<#param::State as SystemParamState>::get_param(&mut self.param_states.#index, &self.system_meta, self.world, self.change_tick)
}
}
});
@ -229,34 +229,36 @@ pub fn impl_param_set(_input: TokenStream) -> TokenStream {
for param_count in 1..=max_params {
let param = &params[0..param_count];
let param_fetch = &params_fetch[0..param_count];
let param_state = &params_state[0..param_count];
let meta = &metas[0..param_count];
let param_fn_mut = &param_fn_muts[0..param_count];
tokens.extend(TokenStream::from(quote! {
impl<'w, 's, #(#param: SystemParam,)*> SystemParam for ParamSet<'w, 's, (#(#param,)*)>
{
type Fetch = ParamSetState<(#(#param::Fetch,)*)>;
type State = ParamSetState<(#(#param::State,)*)>;
}
// SAFETY: All parameters are constrained to ReadOnlyFetch, so World is only read
// SAFETY: All parameters are constrained to ReadOnlyState, so World is only read
unsafe impl<#(#param_fetch: for<'w1, 's1> SystemParamFetch<'w1, 's1>,)*> ReadOnlySystemParamFetch for ParamSetState<(#(#param_fetch,)*)>
where #(#param_fetch: ReadOnlySystemParamFetch,)*
unsafe impl<'w, 's, #(#param,)*> ReadOnlySystemParam for ParamSet<'w, 's, (#(#param,)*)>
where #(#param: ReadOnlySystemParam,)*
{ }
// SAFETY: Relevant parameter ComponentId and ArchetypeComponentId access is applied to SystemMeta. If any ParamState conflicts
// with any prior access, a panic will occur.
unsafe impl<#(#param_fetch: for<'w1, 's1> SystemParamFetch<'w1, 's1>,)*> SystemParamState for ParamSetState<(#(#param_fetch,)*)>
unsafe impl<#(#param_state: SystemParamState,)*> SystemParamState for ParamSetState<(#(#param_state,)*)>
{
type Item<'w, 's> = ParamSet<'w, 's, (#(<#param_state as SystemParamState>::Item::<'w, 's>,)*)>;
fn init(world: &mut World, system_meta: &mut SystemMeta) -> Self {
#(
// Pretend to add each param to the system alone, see if it conflicts
let mut #meta = system_meta.clone();
#meta.component_access_set.clear();
#meta.archetype_component_access.clear();
#param_fetch::init(world, &mut #meta);
let #param = #param_fetch::init(world, &mut system_meta.clone());
#param_state::init(world, &mut #meta);
let #param = #param_state::init(world, &mut system_meta.clone());
)*
#(
system_meta
@ -279,21 +281,14 @@ pub fn impl_param_set(_input: TokenStream) -> TokenStream {
fn apply(&mut self, world: &mut World) {
self.0.apply(world)
}
}
impl<'w, 's, #(#param_fetch: for<'w1, 's1> SystemParamFetch<'w1, 's1>,)*> SystemParamFetch<'w, 's> for ParamSetState<(#(#param_fetch,)*)>
{
type Item = ParamSet<'w, 's, (#(<#param_fetch as SystemParamFetch<'w, 's>>::Item,)*)>;
#[inline]
unsafe fn get_param(
unsafe fn get_param<'w, 's>(
state: &'s mut Self,
system_meta: &SystemMeta,
world: &'w World,
change_tick: u32,
) -> Self::Item {
) -> Self::Item<'w, 's> {
ParamSet {
param_states: &mut state.0,
system_meta: system_meta.clone(),
@ -414,34 +409,48 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream {
_ => unreachable!(),
}));
// Create a where clause for the `ReadOnlySystemParam` impl.
// Ensure that each field implements `ReadOnlySystemParam`.
let mut read_only_generics = generics.clone();
let read_only_where_clause = read_only_generics.make_where_clause();
for field_type in &field_types {
read_only_where_clause
.predicates
.push(syn::parse_quote!(#field_type: #path::system::ReadOnlySystemParam));
}
let struct_name = &ast.ident;
let fetch_struct_visibility = &ast.vis;
let state_struct_visibility = &ast.vis;
TokenStream::from(quote! {
// We define the FetchState struct in an anonymous scope to avoid polluting the user namespace.
// The struct can still be accessed via SystemParam::Fetch, e.g. EventReaderState can be accessed via
// <EventReader<'static, 'static, T> as SystemParam>::Fetch
// The struct can still be accessed via SystemParam::State, e.g. EventReaderState can be accessed via
// <EventReader<'static, 'static, T> as SystemParam>::State
const _: () = {
impl<'w, 's, #punctuated_generics> #path::system::SystemParam for #struct_name #ty_generics #where_clause {
type Fetch = State<'w, 's, #punctuated_generic_idents>;
type State = State<'w, 's, #punctuated_generic_idents>;
}
#[doc(hidden)]
type State<'w, 's, #punctuated_generic_idents> = FetchState<
(#(<#field_types as #path::system::SystemParam>::Fetch,)*),
(#(<#field_types as #path::system::SystemParam>::State,)*),
#punctuated_generic_idents
>;
#[doc(hidden)]
#fetch_struct_visibility struct FetchState <TSystemParamState, #punctuated_generic_idents> {
#state_struct_visibility struct FetchState <TSystemParamState, #punctuated_generic_idents> {
state: TSystemParamState,
marker: std::marker::PhantomData<fn()->(#punctuated_generic_idents)>
}
unsafe impl<TSystemParamState: #path::system::SystemParamState, #punctuated_generics> #path::system::SystemParamState for FetchState <TSystemParamState, #punctuated_generic_idents> #where_clause {
unsafe impl<'__w, '__s, #punctuated_generics> #path::system::SystemParamState for
State<'__w, '__s, #punctuated_generic_idents>
#where_clause {
type Item<'w, 's> = #struct_name #ty_generics;
fn init(world: &mut #path::world::World, system_meta: &mut #path::system::SystemMeta) -> Self {
Self {
state: TSystemParamState::init(world, system_meta),
state: #path::system::SystemParamState::init(world, system_meta),
marker: std::marker::PhantomData,
}
}
@ -453,25 +462,22 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream {
fn apply(&mut self, world: &mut #path::world::World) {
self.state.apply(world)
}
}
impl<'w, 's, #punctuated_generics> #path::system::SystemParamFetch<'w, 's> for State<'w, 's, #punctuated_generic_idents> #where_clause {
type Item = #struct_name #ty_generics;
unsafe fn get_param(
unsafe fn get_param<'w, 's>(
state: &'s mut Self,
system_meta: &#path::system::SystemMeta,
world: &'w #path::world::World,
change_tick: u32,
) -> Self::Item {
) -> Self::Item<'w, 's> {
#struct_name {
#(#fields: <<#field_types as #path::system::SystemParam>::Fetch as #path::system::SystemParamFetch>::get_param(&mut state.state.#field_indices, system_meta, world, change_tick),)*
#(#fields: <<#field_types as #path::system::SystemParam>::State as #path::system::SystemParamState>::get_param(&mut state.state.#field_indices, system_meta, world, change_tick),)*
#(#ignored_fields: <#ignored_field_types>::default(),)*
}
}
}
// Safety: The `ParamState` is `ReadOnlySystemParamFetch`, so this can only read from the `World`
unsafe impl<TSystemParamState: #path::system::SystemParamState + #path::system::ReadOnlySystemParamFetch, #punctuated_generics> #path::system::ReadOnlySystemParamFetch for FetchState <TSystemParamState, #punctuated_generic_idents> #where_clause {}
// Safety: Each field is `ReadOnlySystemParam`, so this can only read from the `World`
unsafe impl<'w, 's, #punctuated_generics> #path::system::ReadOnlySystemParam for #struct_name #ty_generics #read_only_where_clause {}
};
})
}

View file

@ -5,7 +5,7 @@ use thread_local::ThreadLocal;
use crate::{
entity::Entities,
prelude::World,
system::{SystemParam, SystemParamFetch, SystemParamState},
system::{SystemParam, SystemParamState},
};
use super::{CommandQueue, Commands};
@ -49,27 +49,13 @@ pub struct ParallelCommands<'w, 's> {
}
impl SystemParam for ParallelCommands<'_, '_> {
type Fetch = ParallelCommandsState;
}
impl<'w, 's> SystemParamFetch<'w, 's> for ParallelCommandsState {
type Item = ParallelCommands<'w, 's>;
unsafe fn get_param(
state: &'s mut Self,
_: &crate::system::SystemMeta,
world: &'w World,
_: u32,
) -> Self::Item {
ParallelCommands {
state,
entities: world.entities(),
}
}
type State = ParallelCommandsState;
}
// SAFETY: no component or resource access to report
unsafe impl SystemParamState for ParallelCommandsState {
type Item<'w, 's> = ParallelCommands<'w, 's>;
fn init(_: &mut World, _: &mut crate::system::SystemMeta) -> Self {
Self::default()
}
@ -79,6 +65,18 @@ unsafe impl SystemParamState for ParallelCommandsState {
cq.get_mut().apply(world);
}
}
unsafe fn get_param<'w, 's>(
state: &'s mut Self,
_: &crate::system::SystemMeta,
world: &'w World,
_: u32,
) -> Self::Item<'w, 's> {
ParallelCommands {
state,
entities: world.entities(),
}
}
}
impl<'w, 's> ParallelCommands<'w, 's> {

View file

@ -5,9 +5,8 @@ use crate::{
query::Access,
schedule::{SystemLabel, SystemLabelId},
system::{
check_system_change_tick, AsSystemLabel, ExclusiveSystemParam, ExclusiveSystemParamFetch,
ExclusiveSystemParamItem, ExclusiveSystemParamState, IntoSystem, System, SystemMeta,
SystemTypeIdLabel,
check_system_change_tick, AsSystemLabel, ExclusiveSystemParam, ExclusiveSystemParamItem,
ExclusiveSystemParamState, IntoSystem, System, SystemMeta, SystemTypeIdLabel,
},
world::{World, WorldId},
};
@ -25,7 +24,7 @@ where
Param: ExclusiveSystemParam,
{
func: F,
param_state: Option<Param::Fetch>,
param_state: Option<Param::State>,
system_meta: SystemMeta,
world_id: Option<WorldId>,
// NOTE: PhantomData<fn()-> T> gives this safe Send/Sync impls
@ -95,7 +94,7 @@ where
let saved_last_tick = world.last_change_tick;
world.last_change_tick = self.system_meta.last_change_tick;
let params = <Param as ExclusiveSystemParam>::Fetch::get_param(
let params = <Param as ExclusiveSystemParam>::State::get_param(
self.param_state.as_mut().expect(PARAM_MESSAGE),
&self.system_meta,
);
@ -130,7 +129,7 @@ where
fn initialize(&mut self, world: &mut World) {
self.world_id = Some(world.id());
self.system_meta.last_change_tick = world.change_tick().wrapping_sub(MAX_CHANGE_AGE);
self.param_state = Some(<Param::Fetch as ExclusiveSystemParamState>::init(
self.param_state = Some(<Param::State as ExclusiveSystemParamState>::init(
world,
&mut self.system_meta,
));

View file

@ -8,111 +8,86 @@ use bevy_ecs_macros::all_tuples;
use bevy_utils::synccell::SyncCell;
pub trait ExclusiveSystemParam: Sized {
type Fetch: for<'s> ExclusiveSystemParamFetch<'s>;
type State: ExclusiveSystemParamState;
}
pub type ExclusiveSystemParamItem<'s, P> =
<<P as ExclusiveSystemParam>::Fetch as ExclusiveSystemParamFetch<'s>>::Item;
<<P as ExclusiveSystemParam>::State as ExclusiveSystemParamState>::Item<'s>;
/// The state of a [`SystemParam`].
pub trait ExclusiveSystemParamState: Send + Sync {
pub trait ExclusiveSystemParamState: Send + Sync + 'static {
type Item<'s>: ExclusiveSystemParam<State = Self>;
fn init(world: &mut World, system_meta: &mut SystemMeta) -> Self;
#[inline]
fn apply(&mut self, _world: &mut World) {}
}
pub trait ExclusiveSystemParamFetch<'state>: ExclusiveSystemParamState {
type Item: ExclusiveSystemParam<Fetch = Self>;
fn get_param(state: &'state mut Self, system_meta: &SystemMeta) -> Self::Item;
fn get_param<'s>(state: &'s mut Self, system_meta: &SystemMeta) -> Self::Item<'s>;
}
impl<'a, Q: WorldQuery + 'static, F: ReadOnlyWorldQuery + 'static> ExclusiveSystemParam
for &'a mut QueryState<Q, F>
{
type Fetch = QueryState<Q, F>;
}
impl<'s, Q: WorldQuery + 'static, F: ReadOnlyWorldQuery + 'static> ExclusiveSystemParamFetch<'s>
for QueryState<Q, F>
{
type Item = &'s mut QueryState<Q, F>;
fn get_param(state: &'s mut Self, _system_meta: &SystemMeta) -> Self::Item {
state
}
type State = QueryState<Q, F>;
}
impl<Q: WorldQuery + 'static, F: ReadOnlyWorldQuery + 'static> ExclusiveSystemParamState
for QueryState<Q, F>
{
type Item<'s> = &'s mut QueryState<Q, F>;
fn init(world: &mut World, _system_meta: &mut SystemMeta) -> Self {
QueryState::new(world)
}
}
impl<'a, P: SystemParam + 'static> ExclusiveSystemParam for &'a mut SystemState<P> {
type Fetch = SystemState<P>;
}
impl<'s, P: SystemParam + 'static> ExclusiveSystemParamFetch<'s> for SystemState<P> {
type Item = &'s mut SystemState<P>;
fn get_param(state: &'s mut Self, _system_meta: &SystemMeta) -> Self::Item {
fn get_param<'s>(state: &'s mut Self, _system_meta: &SystemMeta) -> Self::Item<'s> {
state
}
}
impl<'a, P: SystemParam + 'static> ExclusiveSystemParam for &'a mut SystemState<P> {
type State = SystemState<P>;
}
impl<P: SystemParam> ExclusiveSystemParamState for SystemState<P> {
type Item<'s> = &'s mut SystemState<P>;
fn init(world: &mut World, _system_meta: &mut SystemMeta) -> Self {
SystemState::new(world)
}
fn get_param<'s>(state: &'s mut Self, _system_meta: &SystemMeta) -> Self::Item<'s> {
state
}
}
impl<'s, T: FromWorld + Send + Sync + 'static> ExclusiveSystemParam for Local<'s, T> {
type Fetch = LocalState<T>;
}
impl<'s, T: FromWorld + Send + Sync + 'static> ExclusiveSystemParamFetch<'s> for LocalState<T> {
type Item = Local<'s, T>;
fn get_param(state: &'s mut Self, _system_meta: &SystemMeta) -> Self::Item {
Local(state.0.get())
}
type State = LocalState<T>;
}
impl<T: FromWorld + Send + Sync> ExclusiveSystemParamState for LocalState<T> {
type Item<'s> = Local<'s, T>;
fn init(world: &mut World, _system_meta: &mut SystemMeta) -> Self {
Self(SyncCell::new(T::from_world(world)))
}
fn get_param<'s>(state: &'s mut Self, _system_meta: &SystemMeta) -> Self::Item<'s> {
Local(state.0.get())
}
}
macro_rules! impl_exclusive_system_param_tuple {
($($param: ident),*) => {
impl<$($param: ExclusiveSystemParam),*> ExclusiveSystemParam for ($($param,)*) {
type Fetch = ($($param::Fetch,)*);
type State = ($($param::State,)*);
}
#[allow(unused_variables)]
#[allow(non_snake_case)]
impl<'s, $($param: ExclusiveSystemParamFetch<'s>),*> ExclusiveSystemParamFetch<'s> for ($($param,)*) {
type Item = ($($param::Item,)*);
#[inline]
#[allow(clippy::unused_unit)]
fn get_param(
state: &'s mut Self,
system_meta: &SystemMeta,
) -> Self::Item {
let ($($param,)*) = state;
($($param::get_param($param, system_meta),)*)
}
}
// SAFETY: implementors of each `ExclusiveSystemParamState` in the tuple have validated their impls
#[allow(clippy::undocumented_unsafe_blocks)] // false positive by clippy
#[allow(non_snake_case)]
impl<$($param: ExclusiveSystemParamState),*> ExclusiveSystemParamState for ($($param,)*) {
type Item<'s> = ($($param::Item<'s>,)*);
#[inline]
fn init(_world: &mut World, _system_meta: &mut SystemMeta) -> Self {
(($($param::init(_world, _system_meta),)*))
@ -123,7 +98,19 @@ macro_rules! impl_exclusive_system_param_tuple {
let ($($param,)*) = self;
$($param.apply(_world);)*
}
#[inline]
#[allow(clippy::unused_unit)]
fn get_param<'s>(
state: &'s mut Self,
system_meta: &SystemMeta,
) -> Self::Item<'s> {
let ($($param,)*) = state;
($($param::get_param($param, system_meta),)*)
}
}
};
}

View file

@ -6,8 +6,8 @@ use crate::{
query::{Access, FilteredAccessSet},
schedule::{SystemLabel, SystemLabelId},
system::{
check_system_change_tick, ReadOnlySystemParamFetch, System, SystemParam, SystemParamFetch,
SystemParamItem, SystemParamState,
check_system_change_tick, ReadOnlySystemParam, System, SystemParam, SystemParamItem,
SystemParamState,
},
world::{World, WorldId},
};
@ -135,7 +135,7 @@ impl SystemMeta {
/// ```
pub struct SystemState<Param: SystemParam + 'static> {
meta: SystemMeta,
param_state: <Param as SystemParam>::Fetch,
param_state: <Param as SystemParam>::State,
world_id: WorldId,
archetype_generation: ArchetypeGeneration,
}
@ -144,7 +144,7 @@ impl<Param: SystemParam> SystemState<Param> {
pub fn new(world: &mut World) -> Self {
let mut meta = SystemMeta::new::<Param>();
meta.last_change_tick = world.change_tick().wrapping_sub(MAX_CHANGE_AGE);
let param_state = <Param::Fetch as SystemParamState>::init(world, &mut meta);
let param_state = <Param::State as SystemParamState>::init(world, &mut meta);
Self {
meta,
param_state,
@ -160,12 +160,9 @@ impl<Param: SystemParam> SystemState<Param> {
/// Retrieve the [`SystemParam`] values. This can only be called when all parameters are read-only.
#[inline]
pub fn get<'w, 's>(
&'s mut self,
world: &'w World,
) -> <Param::Fetch as SystemParamFetch<'w, 's>>::Item
pub fn get<'w, 's>(&'s mut self, world: &'w World) -> SystemParamItem<'w, 's, Param>
where
Param::Fetch: ReadOnlySystemParamFetch,
Param: ReadOnlySystemParam,
{
self.validate_world_and_update_archetypes(world);
// SAFETY: Param is read-only and doesn't allow mutable access to World. It also matches the World this SystemState was created with.
@ -174,10 +171,7 @@ impl<Param: SystemParam> SystemState<Param> {
/// Retrieve the mutable [`SystemParam`] values.
#[inline]
pub fn get_mut<'w, 's>(
&'s mut self,
world: &'w mut World,
) -> <Param::Fetch as SystemParamFetch<'w, 's>>::Item {
pub fn get_mut<'w, 's>(&'s mut self, world: &'w mut World) -> SystemParamItem<'w, 's, Param> {
self.validate_world_and_update_archetypes(world);
// SAFETY: World is uniquely borrowed and matches the World this SystemState was created with.
unsafe { self.get_unchecked_manual(world) }
@ -221,9 +215,9 @@ impl<Param: SystemParam> SystemState<Param> {
pub unsafe fn get_unchecked_manual<'w, 's>(
&'s mut self,
world: &'w World,
) -> <Param::Fetch as SystemParamFetch<'w, 's>>::Item {
) -> SystemParamItem<'w, 's, Param> {
let change_tick = world.increment_change_tick();
let param = <Param::Fetch as SystemParamFetch>::get_param(
let param = <Param::State as SystemParamState>::get_param(
&mut self.param_state,
&self.meta,
world,
@ -315,7 +309,7 @@ where
Param: SystemParam,
{
func: F,
param_state: Option<Param::Fetch>,
param_state: Option<Param::State>,
system_meta: SystemMeta,
world_id: Option<WorldId>,
archetype_generation: ArchetypeGeneration,
@ -400,7 +394,7 @@ where
// We update the archetype component access correctly based on `Param`'s requirements
// in `update_archetype_component_access`.
// Our caller upholds the requirements.
let params = <Param as SystemParam>::Fetch::get_param(
let params = <Param as SystemParam>::State::get_param(
self.param_state.as_mut().expect(Self::PARAM_MESSAGE),
&self.system_meta,
world,
@ -429,7 +423,7 @@ where
fn initialize(&mut self, world: &mut World) {
self.world_id = Some(world.id());
self.system_meta.last_change_tick = world.change_tick().wrapping_sub(MAX_CHANGE_AGE);
self.param_state = Some(<Param::Fetch as SystemParamState>::init(
self.param_state = Some(<Param::State as SystemParamState>::init(
world,
&mut self.system_meta,
));
@ -588,7 +582,7 @@ macro_rules! impl_system_function {
where
for <'a> &'a mut Func:
FnMut(In<Input>, $($param),*) -> Out +
FnMut(In<Input>, $(<<$param as SystemParam>::Fetch as SystemParamFetch>::Item),*) -> Out, Out: 'static
FnMut(In<Input>, $(SystemParamItem<$param>),*) -> Out, Out: 'static
{
#[inline]
fn run(&mut self, input: Input, param_value: SystemParamItem< ($($param,)*)>) -> Out {

View file

@ -72,7 +72,7 @@ use std::{
///
/// ```text
/// expected ... [ParamType]
/// found associated type `<<[ParamType] as SystemParam>::Fetch as SystemParamFetch<'_, '_>>::Item`
/// found associated type `<<[ParamType] as SystemParam>::State as SystemParamState>::Item<'_, '_>`
/// ```
/// where `[ParamType]` is the type of one of your fields.
/// To solve this error, you can wrap the field of type `[ParamType]` with [`StaticSystemParam`]
@ -81,7 +81,7 @@ use std::{
/// ## Details
///
/// The derive macro requires that the [`SystemParam`] implementation of
/// each field `F`'s [`Fetch`](`SystemParam::Fetch`)'s [`Item`](`SystemParamFetch::Item`) is itself `F`
/// each field `F`'s [`State`](`SystemParam::State`)'s [`Item`](`SystemParamState::Item`) is itself `F`
/// (ignoring lifetimes for simplicity).
/// This assumption is due to type inference reasons, so that the derived [`SystemParam`] can be
/// used as an argument to a function system.
@ -122,17 +122,17 @@ use std::{
/// [`SyncCell`]: bevy_utils::synccell::SyncCell
/// [`Exclusive`]: https://doc.rust-lang.org/nightly/std/sync/struct.Exclusive.html
pub trait SystemParam: Sized {
type Fetch: for<'w, 's> SystemParamFetch<'w, 's>;
type State: SystemParamState;
}
pub type SystemParamItem<'w, 's, P> = <<P as SystemParam>::Fetch as SystemParamFetch<'w, 's>>::Item;
pub type SystemParamItem<'w, 's, P> = <<P as SystemParam>::State as SystemParamState>::Item<'w, 's>;
/// The state of a [`SystemParam`].
///
/// # Safety
///
/// It is the implementor's responsibility to ensure `system_meta` is populated with the _exact_
/// [`World`] access used by the [`SystemParamState`] (and associated [`SystemParamFetch`]).
/// [`World`] access used by the [`SystemParamState`].
/// Additionally, it is the implementor's responsibility to ensure there is no
/// conflicting access across all [`SystemParam`]'s.
pub unsafe trait SystemParamState: Send + Sync + 'static {
@ -141,37 +141,35 @@ pub unsafe trait SystemParamState: Send + Sync + 'static {
fn new_archetype(&mut self, _archetype: &Archetype, _system_meta: &mut SystemMeta) {}
#[inline]
fn apply(&mut self, _world: &mut World) {}
}
/// A [`SystemParamFetch`] that only reads a given [`World`].
///
/// # Safety
/// This must only be implemented for [`SystemParamFetch`] impls that exclusively read the World passed in to [`SystemParamFetch::get_param`]
pub unsafe trait ReadOnlySystemParamFetch {}
pub trait SystemParamFetch<'world, 'state>: SystemParamState {
type Item: SystemParam<Fetch = Self>;
type Item<'world, 'state>: SystemParam<State = Self>;
/// # Safety
///
/// This call might access any of the input parameters in an unsafe way. Make sure the data
/// access is safe in the context of the system scheduler.
unsafe fn get_param(
unsafe fn get_param<'world, 'state>(
state: &'state mut Self,
system_meta: &SystemMeta,
world: &'world World,
change_tick: u32,
) -> Self::Item;
) -> Self::Item<'world, 'state>;
}
/// A [`SystemParam`] that only reads a given [`World`].
///
/// # Safety
/// This must only be implemented for [`SystemParam`] impls that exclusively read the World passed in to [`SystemParamState::get_param`]
pub unsafe trait ReadOnlySystemParam: SystemParam {}
impl<'w, 's, Q: WorldQuery + 'static, F: ReadOnlyWorldQuery + 'static> SystemParam
for Query<'w, 's, Q, F>
{
type Fetch = QueryState<Q, F>;
type State = QueryState<Q, F>;
}
// SAFETY: QueryState is constrained to read-only fetches, so it only reads World.
unsafe impl<Q: ReadOnlyWorldQuery, F: ReadOnlyWorldQuery> ReadOnlySystemParamFetch
for QueryState<Q, F>
unsafe impl<'w, 's, Q: ReadOnlyWorldQuery + 'static, F: ReadOnlyWorldQuery + 'static>
ReadOnlySystemParam for Query<'w, 's, Q, F>
{
}
@ -180,6 +178,8 @@ unsafe impl<Q: ReadOnlyWorldQuery, F: ReadOnlyWorldQuery> ReadOnlySystemParamFet
unsafe impl<Q: WorldQuery + 'static, F: ReadOnlyWorldQuery + 'static> SystemParamState
for QueryState<Q, F>
{
type Item<'w, 's> = Query<'w, 's, Q, F>;
fn init(world: &mut World, system_meta: &mut SystemMeta) -> Self {
let state = QueryState::new(world);
assert_component_access_compatibility(
@ -205,20 +205,14 @@ unsafe impl<Q: WorldQuery + 'static, F: ReadOnlyWorldQuery + 'static> SystemPara
.archetype_component_access
.extend(&self.archetype_component_access);
}
}
impl<'w, 's, Q: WorldQuery + 'static, F: ReadOnlyWorldQuery + 'static> SystemParamFetch<'w, 's>
for QueryState<Q, F>
{
type Item = Query<'w, 's, Q, F>;
#[inline]
unsafe fn get_param(
unsafe fn get_param<'w, 's>(
state: &'s mut Self,
system_meta: &SystemMeta,
world: &'w World,
change_tick: u32,
) -> Self::Item {
) -> Self::Item<'w, 's> {
Query::new(world, state, system_meta.last_change_tick, change_tick)
}
}
@ -245,13 +239,13 @@ fn assert_component_access_compatibility(
}
pub struct ParamSet<'w, 's, T: SystemParam> {
param_states: &'s mut T::Fetch,
param_states: &'s mut T::State,
world: &'w World,
system_meta: SystemMeta,
change_tick: u32,
}
/// The [`SystemParamState`] of [`ParamSet<T::Item>`].
pub struct ParamSetState<T: for<'w, 's> SystemParamFetch<'w, 's>>(T);
pub struct ParamSetState<T: SystemParamState>(T);
impl_param_set!();
@ -308,7 +302,7 @@ pub struct Res<'w, T: Resource> {
}
// SAFETY: Res only reads a single World resource
unsafe impl<T: Resource> ReadOnlySystemParamFetch for ResState<T> {}
unsafe impl<'w, T: Resource> ReadOnlySystemParam for Res<'w, T> {}
impl<'w, T: Resource> Debug for Res<'w, T>
where
@ -396,12 +390,14 @@ pub struct ResState<T> {
}
impl<'a, T: Resource> SystemParam for Res<'a, T> {
type Fetch = ResState<T>;
type State = ResState<T>;
}
// SAFETY: Res ComponentId and ArchetypeComponentId access is applied to SystemMeta. If this Res
// conflicts with any prior access, a panic will occur.
unsafe impl<T: Resource> SystemParamState for ResState<T> {
type Item<'w, 's> = Res<'w, T>;
fn init(world: &mut World, system_meta: &mut SystemMeta) -> Self {
let component_id = world.initialize_resource::<T>();
let combined_access = system_meta.component_access_set.combined_access();
@ -426,18 +422,14 @@ unsafe impl<T: Resource> SystemParamState for ResState<T> {
marker: PhantomData,
}
}
}
impl<'w, 's, T: Resource> SystemParamFetch<'w, 's> for ResState<T> {
type Item = Res<'w, T>;
#[inline]
unsafe fn get_param(
unsafe fn get_param<'w, 's>(
state: &'s mut Self,
system_meta: &SystemMeta,
world: &'w World,
change_tick: u32,
) -> Self::Item {
) -> Self::Item<'w, 's> {
let (ptr, ticks) = world
.get_resource_with_ticks(state.component_id)
.unwrap_or_else(|| {
@ -463,30 +455,28 @@ impl<'w, 's, T: Resource> SystemParamFetch<'w, 's> for ResState<T> {
pub struct OptionResState<T>(ResState<T>);
impl<'a, T: Resource> SystemParam for Option<Res<'a, T>> {
type Fetch = OptionResState<T>;
type State = OptionResState<T>;
}
// SAFETY: Only reads a single World resource
unsafe impl<T: Resource> ReadOnlySystemParamFetch for OptionResState<T> {}
unsafe impl<'a, T: Resource> ReadOnlySystemParam for Option<Res<'a, T>> {}
// SAFETY: this impl defers to `ResState`, which initializes
// and validates the correct world access
unsafe impl<T: Resource> SystemParamState for OptionResState<T> {
type Item<'w, 's> = Option<Res<'w, T>>;
fn init(world: &mut World, system_meta: &mut SystemMeta) -> Self {
Self(ResState::init(world, system_meta))
}
}
impl<'w, 's, T: Resource> SystemParamFetch<'w, 's> for OptionResState<T> {
type Item = Option<Res<'w, T>>;
#[inline]
unsafe fn get_param(
unsafe fn get_param<'w, 's>(
state: &'s mut Self,
system_meta: &SystemMeta,
world: &'w World,
change_tick: u32,
) -> Self::Item {
) -> Self::Item<'w, 's> {
world
.get_resource_with_ticks(state.0.component_id)
.map(|(ptr, ticks)| Res {
@ -507,12 +497,14 @@ pub struct ResMutState<T> {
}
impl<'a, T: Resource> SystemParam for ResMut<'a, T> {
type Fetch = ResMutState<T>;
type State = ResMutState<T>;
}
// SAFETY: Res ComponentId and ArchetypeComponentId access is applied to SystemMeta. If this Res
// conflicts with any prior access, a panic will occur.
unsafe impl<T: Resource> SystemParamState for ResMutState<T> {
type Item<'w, 's> = ResMut<'w, T>;
fn init(world: &mut World, system_meta: &mut SystemMeta) -> Self {
let component_id = world.initialize_resource::<T>();
let combined_access = system_meta.component_access_set.combined_access();
@ -540,18 +532,14 @@ unsafe impl<T: Resource> SystemParamState for ResMutState<T> {
marker: PhantomData,
}
}
}
impl<'w, 's, T: Resource> SystemParamFetch<'w, 's> for ResMutState<T> {
type Item = ResMut<'w, T>;
#[inline]
unsafe fn get_param(
unsafe fn get_param<'w, 's>(
state: &'s mut Self,
system_meta: &SystemMeta,
world: &'w World,
change_tick: u32,
) -> Self::Item {
) -> Self::Item<'w, 's> {
let value = world
.get_resource_unchecked_mut_with_id(state.component_id)
.unwrap_or_else(|| {
@ -579,27 +567,25 @@ impl<'w, 's, T: Resource> SystemParamFetch<'w, 's> for ResMutState<T> {
pub struct OptionResMutState<T>(ResMutState<T>);
impl<'a, T: Resource> SystemParam for Option<ResMut<'a, T>> {
type Fetch = OptionResMutState<T>;
type State = OptionResMutState<T>;
}
// SAFETY: this impl defers to `ResMutState`, which initializes
// and validates the correct world access
unsafe impl<T: Resource> SystemParamState for OptionResMutState<T> {
type Item<'w, 's> = Option<ResMut<'w, T>>;
fn init(world: &mut World, system_meta: &mut SystemMeta) -> Self {
Self(ResMutState::init(world, system_meta))
}
}
impl<'w, 's, T: Resource> SystemParamFetch<'w, 's> for OptionResMutState<T> {
type Item = Option<ResMut<'w, T>>;
#[inline]
unsafe fn get_param(
unsafe fn get_param<'w, 's>(
state: &'s mut Self,
system_meta: &SystemMeta,
world: &'w World,
change_tick: u32,
) -> Self::Item {
) -> Self::Item<'w, 's> {
world
.get_resource_unchecked_mut_with_id(state.0.component_id)
.map(|value| ResMut {
@ -615,14 +601,16 @@ impl<'w, 's, T: Resource> SystemParamFetch<'w, 's> for OptionResMutState<T> {
}
impl<'w, 's> SystemParam for Commands<'w, 's> {
type Fetch = CommandQueue;
type State = CommandQueue;
}
// SAFETY: Commands only accesses internal state
unsafe impl ReadOnlySystemParamFetch for CommandQueue {}
unsafe impl<'w, 's> ReadOnlySystemParam for Commands<'w, 's> {}
// SAFETY: only local state is accessed
unsafe impl SystemParamState for CommandQueue {
type Item<'w, 's> = Commands<'w, 's>;
fn init(_world: &mut World, _system_meta: &mut SystemMeta) -> Self {
Default::default()
}
@ -630,35 +618,33 @@ unsafe impl SystemParamState for CommandQueue {
fn apply(&mut self, world: &mut World) {
self.apply(world);
}
}
impl<'w, 's> SystemParamFetch<'w, 's> for CommandQueue {
type Item = Commands<'w, 's>;
#[inline]
unsafe fn get_param(
unsafe fn get_param<'w, 's>(
state: &'s mut Self,
_system_meta: &SystemMeta,
world: &'w World,
_change_tick: u32,
) -> Self::Item {
) -> Self::Item<'w, 's> {
Commands::new(state, world)
}
}
/// SAFETY: only reads world
unsafe impl ReadOnlySystemParamFetch for WorldState {}
unsafe impl<'w> ReadOnlySystemParam for &'w World {}
/// The [`SystemParamState`] of [`&World`](crate::world::World).
#[doc(hidden)]
pub struct WorldState;
impl<'w> SystemParam for &'w World {
type Fetch = WorldState;
type State = WorldState;
}
// SAFETY: `read_all` access is set and conflicts result in a panic
unsafe impl SystemParamState for WorldState {
type Item<'w, 's> = &'w World;
fn init(_world: &mut World, system_meta: &mut SystemMeta) -> Self {
let mut access = Access::default();
access.read_all();
@ -684,16 +670,13 @@ unsafe impl SystemParamState for WorldState {
WorldState
}
}
impl<'w, 's> SystemParamFetch<'w, 's> for WorldState {
type Item = &'w World;
unsafe fn get_param(
unsafe fn get_param<'w, 's>(
_state: &'s mut Self,
_system_meta: &SystemMeta,
world: &'w World,
_change_tick: u32,
) -> Self::Item {
) -> Self::Item<'w, 's> {
world
}
}
@ -744,7 +727,7 @@ impl<'w, 's> SystemParamFetch<'w, 's> for WorldState {
pub struct Local<'a, T: FromWorld + Send + 'static>(pub(crate) &'a mut T);
// SAFETY: Local only accesses internal state
unsafe impl<T: Send + 'static> ReadOnlySystemParamFetch for LocalState<T> {}
unsafe impl<'a, T: FromWorld + Send + 'static> ReadOnlySystemParam for Local<'a, T> {}
impl<'a, T: FromWorld + Send + Sync + 'static> Debug for Local<'a, T>
where
@ -800,26 +783,24 @@ where
pub struct LocalState<T: Send + 'static>(pub(crate) SyncCell<T>);
impl<'a, T: FromWorld + Send + 'static> SystemParam for Local<'a, T> {
type Fetch = LocalState<T>;
type State = LocalState<T>;
}
// SAFETY: only local state is accessed
unsafe impl<T: FromWorld + Send + 'static> SystemParamState for LocalState<T> {
type Item<'w, 's> = Local<'s, T>;
fn init(world: &mut World, _system_meta: &mut SystemMeta) -> Self {
Self(SyncCell::new(T::from_world(world)))
}
}
impl<'w, 's, T: FromWorld + Send + 'static> SystemParamFetch<'w, 's> for LocalState<T> {
type Item = Local<'s, T>;
#[inline]
unsafe fn get_param(
unsafe fn get_param<'w, 's>(
state: &'s mut Self,
_system_meta: &SystemMeta,
_world: &'w World,
_change_tick: u32,
) -> Self::Item {
) -> Self::Item<'w, 's> {
Local(state.0.get())
}
}
@ -881,7 +862,7 @@ impl<'a, T: Component> IntoIterator for &'a RemovedComponents<'a, T> {
}
// SAFETY: Only reads World components
unsafe impl<T: Component> ReadOnlySystemParamFetch for RemovedComponentsState<T> {}
unsafe impl<'a, T: Component> ReadOnlySystemParam for RemovedComponents<'a, T> {}
/// The [`SystemParamState`] of [`RemovedComponents<T>`].
#[doc(hidden)]
@ -891,30 +872,28 @@ pub struct RemovedComponentsState<T> {
}
impl<'a, T: Component> SystemParam for RemovedComponents<'a, T> {
type Fetch = RemovedComponentsState<T>;
type State = RemovedComponentsState<T>;
}
// SAFETY: no component access. removed component entity collections can be read in parallel and are
// never mutably borrowed during system execution
unsafe impl<T: Component> SystemParamState for RemovedComponentsState<T> {
type Item<'w, 's> = RemovedComponents<'w, T>;
fn init(world: &mut World, _system_meta: &mut SystemMeta) -> Self {
Self {
component_id: world.init_component::<T>(),
marker: PhantomData,
}
}
}
impl<'w, 's, T: Component> SystemParamFetch<'w, 's> for RemovedComponentsState<T> {
type Item = RemovedComponents<'w, T>;
#[inline]
unsafe fn get_param(
unsafe fn get_param<'w, 's>(
state: &'s mut Self,
_system_meta: &SystemMeta,
world: &'w World,
_change_tick: u32,
) -> Self::Item {
) -> Self::Item<'w, 's> {
RemovedComponents {
world,
component_id: state.component_id,
@ -943,7 +922,7 @@ pub struct NonSend<'w, T: 'static> {
}
// SAFETY: Only reads a single World non-send resource
unsafe impl<T> ReadOnlySystemParamFetch for NonSendState<T> {}
unsafe impl<'w, T> ReadOnlySystemParam for NonSend<'w, T> {}
impl<'w, T> Debug for NonSend<'w, T>
where
@ -996,12 +975,14 @@ pub struct NonSendState<T> {
}
impl<'a, T: 'static> SystemParam for NonSend<'a, T> {
type Fetch = NonSendState<T>;
type State = NonSendState<T>;
}
// SAFETY: NonSendComponentId and ArchetypeComponentId access is applied to SystemMeta. If this
// NonSend conflicts with any prior access, a panic will occur.
unsafe impl<T: 'static> SystemParamState for NonSendState<T> {
type Item<'w, 's> = NonSend<'w, T>;
fn init(world: &mut World, system_meta: &mut SystemMeta) -> Self {
system_meta.set_non_send();
@ -1028,18 +1009,14 @@ unsafe impl<T: 'static> SystemParamState for NonSendState<T> {
marker: PhantomData,
}
}
}
impl<'w, 's, T: 'static> SystemParamFetch<'w, 's> for NonSendState<T> {
type Item = NonSend<'w, T>;
#[inline]
unsafe fn get_param(
unsafe fn get_param<'w, 's>(
state: &'s mut Self,
system_meta: &SystemMeta,
world: &'w World,
change_tick: u32,
) -> Self::Item {
) -> Self::Item<'w, 's> {
world.validate_non_send_access::<T>();
let (ptr, ticks) = world
.get_resource_with_ticks(state.component_id)
@ -1066,30 +1043,28 @@ impl<'w, 's, T: 'static> SystemParamFetch<'w, 's> for NonSendState<T> {
pub struct OptionNonSendState<T>(NonSendState<T>);
impl<'w, T: 'static> SystemParam for Option<NonSend<'w, T>> {
type Fetch = OptionNonSendState<T>;
type State = OptionNonSendState<T>;
}
// SAFETY: Only reads a single non-send resource
unsafe impl<T: 'static> ReadOnlySystemParamFetch for OptionNonSendState<T> {}
unsafe impl<'w, T: 'static> ReadOnlySystemParam for Option<NonSend<'w, T>> {}
// SAFETY: this impl defers to `NonSendState`, which initializes
// and validates the correct world access
unsafe impl<T: 'static> SystemParamState for OptionNonSendState<T> {
type Item<'w, 's> = Option<NonSend<'w, T>>;
fn init(world: &mut World, system_meta: &mut SystemMeta) -> Self {
Self(NonSendState::init(world, system_meta))
}
}
impl<'w, 's, T: 'static> SystemParamFetch<'w, 's> for OptionNonSendState<T> {
type Item = Option<NonSend<'w, T>>;
#[inline]
unsafe fn get_param(
unsafe fn get_param<'w, 's>(
state: &'s mut Self,
system_meta: &SystemMeta,
world: &'w World,
change_tick: u32,
) -> Self::Item {
) -> Self::Item<'w, 's> {
world.validate_non_send_access::<T>();
world
.get_resource_with_ticks(state.0.component_id)
@ -1110,12 +1085,14 @@ pub struct NonSendMutState<T> {
}
impl<'a, T: 'static> SystemParam for NonSendMut<'a, T> {
type Fetch = NonSendMutState<T>;
type State = NonSendMutState<T>;
}
// SAFETY: NonSendMut ComponentId and ArchetypeComponentId access is applied to SystemMeta. If this
// NonSendMut conflicts with any prior access, a panic will occur.
unsafe impl<T: 'static> SystemParamState for NonSendMutState<T> {
type Item<'w, 's> = NonSendMut<'w, T>;
fn init(world: &mut World, system_meta: &mut SystemMeta) -> Self {
system_meta.set_non_send();
@ -1145,18 +1122,14 @@ unsafe impl<T: 'static> SystemParamState for NonSendMutState<T> {
marker: PhantomData,
}
}
}
impl<'w, 's, T: 'static> SystemParamFetch<'w, 's> for NonSendMutState<T> {
type Item = NonSendMut<'w, T>;
#[inline]
unsafe fn get_param(
unsafe fn get_param<'w, 's>(
state: &'s mut Self,
system_meta: &SystemMeta,
world: &'w World,
change_tick: u32,
) -> Self::Item {
) -> Self::Item<'w, 's> {
world.validate_non_send_access::<T>();
let (ptr, ticks) = world
.get_resource_with_ticks(state.component_id)
@ -1180,27 +1153,25 @@ impl<'w, 's, T: 'static> SystemParamFetch<'w, 's> for NonSendMutState<T> {
pub struct OptionNonSendMutState<T>(NonSendMutState<T>);
impl<'a, T: 'static> SystemParam for Option<NonSendMut<'a, T>> {
type Fetch = OptionNonSendMutState<T>;
type State = OptionNonSendMutState<T>;
}
// SAFETY: this impl defers to `NonSendMutState`, which initializes
// and validates the correct world access
unsafe impl<T: 'static> SystemParamState for OptionNonSendMutState<T> {
type Item<'w, 's> = Option<NonSendMut<'w, T>>;
fn init(world: &mut World, system_meta: &mut SystemMeta) -> Self {
Self(NonSendMutState::init(world, system_meta))
}
}
impl<'w, 's, T: 'static> SystemParamFetch<'w, 's> for OptionNonSendMutState<T> {
type Item = Option<NonSendMut<'w, T>>;
#[inline]
unsafe fn get_param(
unsafe fn get_param<'w, 's>(
state: &'s mut Self,
system_meta: &SystemMeta,
world: &'w World,
change_tick: u32,
) -> Self::Item {
) -> Self::Item<'w, 's> {
world.validate_non_send_access::<T>();
world
.get_resource_with_ticks(state.0.component_id)
@ -1212,11 +1183,11 @@ impl<'w, 's, T: 'static> SystemParamFetch<'w, 's> for OptionNonSendMutState<T> {
}
impl<'a> SystemParam for &'a Archetypes {
type Fetch = ArchetypesState;
type State = ArchetypesState;
}
// SAFETY: Only reads World archetypes
unsafe impl ReadOnlySystemParamFetch for ArchetypesState {}
unsafe impl<'a> ReadOnlySystemParam for &'a Archetypes {}
/// The [`SystemParamState`] of [`Archetypes`].
#[doc(hidden)]
@ -1224,31 +1195,29 @@ pub struct ArchetypesState;
// SAFETY: no component value access
unsafe impl SystemParamState for ArchetypesState {
type Item<'w, 's> = &'w Archetypes;
fn init(_world: &mut World, _system_meta: &mut SystemMeta) -> Self {
Self
}
}
impl<'w, 's> SystemParamFetch<'w, 's> for ArchetypesState {
type Item = &'w Archetypes;
#[inline]
unsafe fn get_param(
unsafe fn get_param<'w, 's>(
_state: &'s mut Self,
_system_meta: &SystemMeta,
world: &'w World,
_change_tick: u32,
) -> Self::Item {
) -> Self::Item<'w, 's> {
world.archetypes()
}
}
impl<'a> SystemParam for &'a Components {
type Fetch = ComponentsState;
type State = ComponentsState;
}
// SAFETY: Only reads World components
unsafe impl ReadOnlySystemParamFetch for ComponentsState {}
unsafe impl<'a> ReadOnlySystemParam for &'a Components {}
/// The [`SystemParamState`] of [`Components`].
#[doc(hidden)]
@ -1256,31 +1225,29 @@ pub struct ComponentsState;
// SAFETY: no component value access
unsafe impl SystemParamState for ComponentsState {
type Item<'w, 's> = &'w Components;
fn init(_world: &mut World, _system_meta: &mut SystemMeta) -> Self {
Self
}
}
impl<'w, 's> SystemParamFetch<'w, 's> for ComponentsState {
type Item = &'w Components;
#[inline]
unsafe fn get_param(
unsafe fn get_param<'w, 's>(
_state: &'s mut Self,
_system_meta: &SystemMeta,
world: &'w World,
_change_tick: u32,
) -> Self::Item {
) -> Self::Item<'w, 's> {
world.components()
}
}
impl<'a> SystemParam for &'a Entities {
type Fetch = EntitiesState;
type State = EntitiesState;
}
// SAFETY: Only reads World entities
unsafe impl ReadOnlySystemParamFetch for EntitiesState {}
unsafe impl<'a> ReadOnlySystemParam for &'a Entities {}
/// The [`SystemParamState`] of [`Entities`].
#[doc(hidden)]
@ -1288,31 +1255,29 @@ pub struct EntitiesState;
// SAFETY: no component value access
unsafe impl SystemParamState for EntitiesState {
type Item<'w, 's> = &'w Entities;
fn init(_world: &mut World, _system_meta: &mut SystemMeta) -> Self {
Self
}
}
impl<'w, 's> SystemParamFetch<'w, 's> for EntitiesState {
type Item = &'w Entities;
#[inline]
unsafe fn get_param(
unsafe fn get_param<'w, 's>(
_state: &'s mut Self,
_system_meta: &SystemMeta,
world: &'w World,
_change_tick: u32,
) -> Self::Item {
) -> Self::Item<'w, 's> {
world.entities()
}
}
impl<'a> SystemParam for &'a Bundles {
type Fetch = BundlesState;
type State = BundlesState;
}
// SAFETY: Only reads World bundles
unsafe impl ReadOnlySystemParamFetch for BundlesState {}
unsafe impl<'a> ReadOnlySystemParam for &'a Bundles {}
/// The [`SystemParamState`] of [`Bundles`].
#[doc(hidden)]
@ -1320,21 +1285,19 @@ pub struct BundlesState;
// SAFETY: no component value access
unsafe impl SystemParamState for BundlesState {
type Item<'w, 's> = &'w Bundles;
fn init(_world: &mut World, _system_meta: &mut SystemMeta) -> Self {
Self
}
}
impl<'w, 's> SystemParamFetch<'w, 's> for BundlesState {
type Item = &'w Bundles;
#[inline]
unsafe fn get_param(
unsafe fn get_param<'w, 's>(
_state: &'s mut Self,
_system_meta: &SystemMeta,
world: &'w World,
_change_tick: u32,
) -> Self::Item {
) -> Self::Item<'w, 's> {
world.bundles()
}
}
@ -1369,10 +1332,10 @@ impl SystemChangeTick {
}
// SAFETY: Only reads internal system state
unsafe impl ReadOnlySystemParamFetch for SystemChangeTickState {}
unsafe impl ReadOnlySystemParam for SystemChangeTick {}
impl SystemParam for SystemChangeTick {
type Fetch = SystemChangeTickState;
type State = SystemChangeTickState;
}
/// The [`SystemParamState`] of [`SystemChangeTick`].
@ -1381,20 +1344,18 @@ pub struct SystemChangeTickState {}
// SAFETY: `SystemParamTickState` doesn't require any world access
unsafe impl SystemParamState for SystemChangeTickState {
type Item<'w, 's> = SystemChangeTick;
fn init(_world: &mut World, _system_meta: &mut SystemMeta) -> Self {
Self {}
}
}
impl<'w, 's> SystemParamFetch<'w, 's> for SystemChangeTickState {
type Item = SystemChangeTick;
unsafe fn get_param(
unsafe fn get_param<'w, 's>(
_state: &'s mut Self,
system_meta: &SystemMeta,
_world: &'w World,
change_tick: u32,
) -> Self::Item {
) -> Self::Item<'w, 's> {
SystemChangeTick {
last_change_tick: system_meta.last_change_tick,
change_tick,
@ -1450,11 +1411,11 @@ impl<'s> std::fmt::Display for SystemName<'s> {
}
impl<'s> SystemParam for SystemName<'s> {
type Fetch = SystemNameState;
type State = SystemNameState;
}
// SAFETY: Only reads internal system state
unsafe impl ReadOnlySystemParamFetch for SystemNameState {}
unsafe impl<'s> ReadOnlySystemParam for SystemName<'s> {}
/// The [`SystemParamState`] of [`SystemName`].
#[doc(hidden)]
@ -1464,23 +1425,21 @@ pub struct SystemNameState {
// SAFETY: no component value access
unsafe impl SystemParamState for SystemNameState {
type Item<'w, 's> = SystemName<'s>;
fn init(_world: &mut World, system_meta: &mut SystemMeta) -> Self {
Self {
name: system_meta.name.clone(),
}
}
}
impl<'w, 's> SystemParamFetch<'w, 's> for SystemNameState {
type Item = SystemName<'s>;
#[inline]
unsafe fn get_param(
unsafe fn get_param<'w, 's>(
state: &'s mut Self,
_system_meta: &SystemMeta,
_world: &'w World,
_change_tick: u32,
) -> Self::Item {
) -> Self::Item<'w, 's> {
SystemName {
name: state.name.as_ref(),
}
@ -1490,35 +1449,19 @@ impl<'w, 's> SystemParamFetch<'w, 's> for SystemNameState {
macro_rules! impl_system_param_tuple {
($($param: ident),*) => {
impl<$($param: SystemParam),*> SystemParam for ($($param,)*) {
type Fetch = ($($param::Fetch,)*);
type State = ($($param::State,)*);
}
// SAFETY: tuple consists only of ReadOnlySystemParamFetches
unsafe impl<$($param: ReadOnlySystemParamFetch),*> ReadOnlySystemParamFetch for ($($param,)*) {}
// SAFETY: tuple consists only of ReadOnlySystemParams
unsafe impl<$($param: ReadOnlySystemParam),*> ReadOnlySystemParam for ($($param,)*) {}
#[allow(unused_variables)]
#[allow(non_snake_case)]
impl<'w, 's, $($param: SystemParamFetch<'w, 's>),*> SystemParamFetch<'w, 's> for ($($param,)*) {
type Item = ($($param::Item,)*);
#[inline]
#[allow(clippy::unused_unit)]
unsafe fn get_param(
state: &'s mut Self,
system_meta: &SystemMeta,
world: &'w World,
change_tick: u32,
) -> Self::Item {
let ($($param,)*) = state;
($($param::get_param($param, system_meta, world, change_tick),)*)
}
}
// SAFETY: implementors of each `SystemParamState` in the tuple have validated their impls
#[allow(clippy::undocumented_unsafe_blocks)] // false positive by clippy
#[allow(non_snake_case)]
unsafe impl<$($param: SystemParamState),*> SystemParamState for ($($param,)*) {
type Item<'w, 's> = ($($param::Item::<'w, 's>,)*);
#[inline]
fn init(_world: &mut World, _system_meta: &mut SystemMeta) -> Self {
(($($param::init(_world, _system_meta),)*))
@ -1535,6 +1478,19 @@ macro_rules! impl_system_param_tuple {
let ($($param,)*) = self;
$($param.apply(_world);)*
}
#[inline]
#[allow(clippy::unused_unit)]
unsafe fn get_param<'w, 's>(
state: &'s mut Self,
_system_meta: &SystemMeta,
_world: &'w World,
_change_tick: u32,
) -> Self::Item<'w, 's> {
let ($($param,)*) = state;
($($param::get_param($param, _system_meta, _world, _change_tick),)*)
}
}
};
}
@ -1553,7 +1509,7 @@ pub mod lifetimeless {
/// A helper for using system parameters in generic contexts
///
/// This type is a [`SystemParam`] adapter which always has
/// `Self::Fetch::Item == Self` (ignoring lifetimes for brevity),
/// `Self::State::Item == Self` (ignoring lifetimes for brevity),
/// no matter the argument [`SystemParam`] (`P`) (other than
/// that `P` must be `'static`)
///
@ -1592,7 +1548,7 @@ pub mod lifetimeless {
/// fn do_thing_generically<T: SystemParam + 'static>(t: T) {}
///
/// #[derive(SystemParam)]
/// struct GenericParam<'w,'s, T: SystemParam> {
/// struct GenericParam<'w, 's, T: SystemParam> {
/// field: T,
/// #[system_param(ignore)]
/// // Use the lifetimes in this type, or they will be unbound.
@ -1631,39 +1587,23 @@ impl<'w, 's, P: SystemParam> StaticSystemParam<'w, 's, P> {
pub struct StaticSystemParamState<S, P>(S, PhantomData<fn() -> P>);
// SAFETY: This doesn't add any more reads, and the delegated fetch confirms it
unsafe impl<S: ReadOnlySystemParamFetch, P> ReadOnlySystemParamFetch
for StaticSystemParamState<S, P>
unsafe impl<'w, 's, P: ReadOnlySystemParam + 'static> ReadOnlySystemParam
for StaticSystemParam<'w, 's, P>
{
}
impl<'world, 'state, P: SystemParam + 'static> SystemParam
for StaticSystemParam<'world, 'state, P>
{
type Fetch = StaticSystemParamState<P::Fetch, P>;
}
impl<'world, 'state, S: SystemParamFetch<'world, 'state>, P: SystemParam + 'static>
SystemParamFetch<'world, 'state> for StaticSystemParamState<S, P>
where
P: SystemParam<Fetch = S>,
{
type Item = StaticSystemParam<'world, 'state, P>;
unsafe fn get_param(
state: &'state mut Self,
system_meta: &SystemMeta,
world: &'world World,
change_tick: u32,
) -> Self::Item {
// SAFETY: We properly delegate SystemParamState
StaticSystemParam(S::get_param(&mut state.0, system_meta, world, change_tick))
}
type State = StaticSystemParamState<P::State, P>;
}
// SAFETY: all methods are just delegated to `S`'s `SystemParamState` implementation
unsafe impl<S: SystemParamState, P: SystemParam + 'static> SystemParamState
unsafe impl<S: SystemParamState, P: SystemParam<State = S> + 'static> SystemParamState
for StaticSystemParamState<S, P>
{
type Item<'world, 'state> = StaticSystemParam<'world, 'state, P>;
fn init(world: &mut World, system_meta: &mut SystemMeta) -> Self {
Self(S::init(world, system_meta), PhantomData)
}
@ -1675,6 +1615,16 @@ unsafe impl<S: SystemParamState, P: SystemParam + 'static> SystemParamState
fn apply(&mut self, world: &mut World) {
self.0.apply(world);
}
unsafe fn get_param<'world, 'state>(
state: &'state mut Self,
system_meta: &SystemMeta,
world: &'world World,
change_tick: u32,
) -> Self::Item<'world, 'state> {
// SAFETY: We properly delegate SystemParamState
StaticSystemParam(S::get_param(&mut state.0, system_meta, world, change_tick))
}
}
#[cfg(test)]

View file

@ -1,5 +1,5 @@
use bevy_ecs::prelude::*;
use bevy_ecs::system::{ReadOnlySystemParamFetch, SystemParam, SystemState};
use bevy_ecs::system::{ReadOnlySystemParam, SystemParam, SystemState};
#[derive(Component)]
struct Foo;
@ -18,8 +18,8 @@ fn main() {
assert_readonly::<Mutable>();
}
fn assert_readonly<P: SystemParam>()
fn assert_readonly<P>()
where
<P as SystemParam>::Fetch: ReadOnlySystemParamFetch,
P: ReadOnlySystemParam,
{
}

View file

@ -1,8 +1,8 @@
warning: unused import: `SystemState`
--> tests/ui/system_param_derive_readonly.rs:2:63
--> tests/ui/system_param_derive_readonly.rs:2:58
|
2 | use bevy_ecs::system::{ReadOnlySystemParamFetch, SystemParam, SystemState};
| ^^^^^^^^^^^
2 | use bevy_ecs::system::{ReadOnlySystemParam, SystemParam, SystemState};
| ^^^^^^^^^^^
|
= note: `#[warn(unused_imports)]` on by default
@ -23,14 +23,14 @@ error[E0277]: the trait bound `&'static mut Foo: ReadOnlyWorldQuery` is not sati
(F0, F1, F2, F3, F4, F5, F6)
and $N others
= note: `ReadOnlyWorldQuery` is implemented for `&'static Foo`, but not for `&'static mut Foo`
= note: required for `QueryState<&'static mut Foo>` to implement `ReadOnlySystemParamFetch`
= note: 2 redundant requirements hidden
= note: required for `FetchState<(QueryState<&'static mut Foo>,)>` to implement `ReadOnlySystemParamFetch`
= note: required for `bevy_ecs::system::Query<'_, '_, &'static mut Foo>` to implement `ReadOnlySystemParam`
= note: 1 redundant requirement hidden
= note: required for `Mutable<'_, '_>` to implement `ReadOnlySystemParam`
note: required by a bound in `assert_readonly`
--> tests/ui/system_param_derive_readonly.rs:23:32
--> tests/ui/system_param_derive_readonly.rs:23:8
|
21 | fn assert_readonly<P: SystemParam>()
21 | fn assert_readonly<P>()
| --------------- required by a bound in this
22 | where
23 | <P as SystemParam>::Fetch: ReadOnlySystemParamFetch,
| ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_readonly`
23 | P: ReadOnlySystemParam,
| ^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_readonly`

View file

@ -2,8 +2,8 @@ use crate::MainWorld;
use bevy_ecs::{
prelude::*,
system::{
ReadOnlySystemParamFetch, ResState, SystemMeta, SystemParam, SystemParamFetch,
SystemParamItem, SystemParamState, SystemState,
ReadOnlySystemParam, ResState, SystemMeta, SystemParam, SystemParamItem, SystemParamState,
SystemState,
},
};
use std::ops::{Deref, DerefMut};
@ -42,18 +42,18 @@ use std::ops::{Deref, DerefMut};
///
/// [`RenderStage::Extract`]: crate::RenderStage::Extract
/// [Window]: bevy_window::Window
pub struct Extract<'w, 's, P: SystemParam + 'static>
pub struct Extract<'w, 's, P>
where
P::Fetch: ReadOnlySystemParamFetch,
P: ReadOnlySystemParam + 'static,
{
item: <P::Fetch as SystemParamFetch<'w, 's>>::Item,
item: SystemParamItem<'w, 's, P>,
}
impl<'w, 's, P: SystemParam> SystemParam for Extract<'w, 's, P>
impl<'w, 's, P> SystemParam for Extract<'w, 's, P>
where
P::Fetch: ReadOnlySystemParamFetch,
P: ReadOnlySystemParam,
{
type Fetch = ExtractState<P>;
type State = ExtractState<P>;
}
#[doc(hidden)]
@ -64,7 +64,12 @@ pub struct ExtractState<P: SystemParam + 'static> {
// SAFETY: only accesses MainWorld resource with read only system params using ResState,
// which is initialized in init()
unsafe impl<P: SystemParam + 'static> SystemParamState for ExtractState<P> {
unsafe impl<P: SystemParam + 'static> SystemParamState for ExtractState<P>
where
P: ReadOnlySystemParam + 'static,
{
type Item<'w, 's> = Extract<'w, 's, P>;
fn init(world: &mut World, system_meta: &mut SystemMeta) -> Self {
let mut main_world = world.resource_mut::<MainWorld>();
Self {
@ -72,20 +77,13 @@ unsafe impl<P: SystemParam + 'static> SystemParamState for ExtractState<P> {
main_world_state: ResState::init(world, system_meta),
}
}
}
impl<'w, 's, P: SystemParam + 'static> SystemParamFetch<'w, 's> for ExtractState<P>
where
P::Fetch: ReadOnlySystemParamFetch,
{
type Item = Extract<'w, 's, P>;
unsafe fn get_param(
unsafe fn get_param<'w, 's>(
state: &'s mut Self,
system_meta: &SystemMeta,
world: &'w World,
change_tick: u32,
) -> Self::Item {
) -> Self::Item<'w, 's> {
let main_world = ResState::<MainWorld>::get_param(
&mut state.main_world_state,
system_meta,
@ -99,9 +97,9 @@ where
impl<'w, 's, P: SystemParam> Deref for Extract<'w, 's, P>
where
P::Fetch: ReadOnlySystemParamFetch,
P: ReadOnlySystemParam,
{
type Target = <P::Fetch as SystemParamFetch<'w, 's>>::Item;
type Target = SystemParamItem<'w, 's, P>;
#[inline]
fn deref(&self) -> &Self::Target {
@ -111,7 +109,7 @@ where
impl<'w, 's, P: SystemParam> DerefMut for Extract<'w, 's, P>
where
P::Fetch: ReadOnlySystemParamFetch,
P: ReadOnlySystemParam,
{
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
@ -121,7 +119,7 @@ where
impl<'a, 'w, 's, P: SystemParam> IntoIterator for &'a Extract<'w, 's, P>
where
P::Fetch: ReadOnlySystemParamFetch,
P: ReadOnlySystemParam,
&'a SystemParamItem<'w, 's, P>: IntoIterator,
{
type Item = <&'a SystemParamItem<'w, 's, P> as IntoIterator>::Item;

View file

@ -7,7 +7,7 @@ use bevy_ecs::{
all_tuples,
entity::Entity,
system::{
lifetimeless::SRes, ReadOnlySystemParamFetch, Resource, SystemParam, SystemParamItem,
lifetimeless::SRes, ReadOnlySystemParam, Resource, SystemParam, SystemParamItem,
SystemState,
},
world::World,
@ -325,7 +325,7 @@ impl<P: PhaseItem, C: RenderCommand<P>> RenderCommandState<P, C> {
impl<P: PhaseItem, C: RenderCommand<P> + Send + Sync + 'static> Draw<P> for RenderCommandState<P, C>
where
<C::Param as SystemParam>::Fetch: ReadOnlySystemParamFetch,
C::Param: ReadOnlySystemParam,
{
/// Prepares the ECS parameters for the wrapped [`RenderCommand`] and then renders it.
fn draw<'w>(
@ -348,7 +348,7 @@ pub trait AddRenderCommand {
&mut self,
) -> &mut Self
where
<C::Param as SystemParam>::Fetch: ReadOnlySystemParamFetch;
C::Param: ReadOnlySystemParam;
}
impl AddRenderCommand for App {
@ -356,7 +356,7 @@ impl AddRenderCommand for App {
&mut self,
) -> &mut Self
where
<C::Param as SystemParam>::Fetch: ReadOnlySystemParamFetch,
C::Param: ReadOnlySystemParam,
{
let draw_function = RenderCommandState::<P, C>::new(&mut self.world);
let draw_functions = self