diff --git a/crates/bevy_ecs/macros/src/lib.rs b/crates/bevy_ecs/macros/src/lib.rs index b8674daf0095f..4166e00de037c 100644 --- a/crates/bevy_ecs/macros/src/lib.rs +++ b/crates/bevy_ecs/macros/src/lib.rs @@ -228,7 +228,7 @@ pub fn impl_param_set(_input: TokenStream) -> TokenStream { // Conflicting params in ParamSet are not accessible at the same time // ParamSets are guaranteed to not conflict with other SystemParams unsafe { - <#param::State as SystemParamState>::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) } } }); @@ -240,7 +240,7 @@ pub fn impl_param_set(_input: TokenStream) -> TokenStream { let meta = &metas[0..param_count]; let param_fn_mut = ¶m_fn_muts[0..param_count]; tokens.extend(TokenStream::from(quote! { - impl<'w, 's, #(#param: SystemParam,)*> SystemParam for ParamSet<'w, 's, (#(#param,)*)> + impl<'w, 's, #(#param: SystemParam,)*> SystemParam for ParamSet<'w, 's, (#(#param,)*)> { type State = ParamSetState<(#(#param::State,)*)>; } @@ -254,9 +254,9 @@ pub fn impl_param_set(_input: TokenStream) -> TokenStream { // 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_state: SystemParamState,)*> SystemParamState for ParamSetState<(#(#param_state,)*)> + unsafe impl<#(#param_state: SystemParamState,)*> SystemParamState for ParamSetState<(#(#param_state,)*)> { - type Item<'w, 's> = ParamSet<'w, 's, (#(<#param_state as SystemParamState>::Item::<'w, 's>,)*)>; + type Item<'w, 's> = ParamSet<'w, 's, (#(<#param_state as SystemParamState>::Item::<'w, 's>,)*)>; fn init(world: &mut World, system_meta: &mut SystemMeta) -> Self { #( @@ -305,7 +305,7 @@ pub fn impl_param_set(_input: TokenStream) -> TokenStream { } } - impl<'w, 's, #(#param: SystemParam,)*> ParamSet<'w, 's, (#(#param,)*)> + impl<'w, 's, #(#param: SystemParam,)*> ParamSet<'w, 's, (#(#param,)*)> { #(#param_fn_mut)* @@ -322,9 +322,17 @@ struct SystemParamFieldAttributes { } static SYSTEM_PARAM_ATTRIBUTE_NAME: &str = "system_param"; +static FALLIBILITY_ATTRIBUTE_NAME: &str = "fallibility"; + +#[derive(PartialEq)] +enum Fallibility { + Infallible, + Optional, + Resultful, +} /// Implement `SystemParam` to use a struct as a parameter in a system -#[proc_macro_derive(SystemParam, attributes(system_param))] +#[proc_macro_derive(SystemParam, attributes(fallibility, system_param))] pub fn derive_system_param(input: TokenStream) -> TokenStream { let ast = parse_macro_input!(input as DeriveInput); let fields = match get_named_struct_fields(&ast.data) { @@ -333,6 +341,66 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream { }; let path = bevy_ecs_path(); + let mut fallibility = None; + + // Read struct-level attributes + for attr in &ast.attrs { + let Some(attr_ident) = attr.path.get_ident() else { continue }; + if attr_ident == FALLIBILITY_ATTRIBUTE_NAME { + if fallibility.is_none() { + if let Ok(fallible_ident) = + attr.parse_args_with(|input: ParseStream| input.parse::()) + { + match fallible_ident.to_string().as_str() { + "Infallible" => { + fallibility = Some(Fallibility::Infallible); + } + "Optional" => { + fallibility = Some(Fallibility::Optional); + } + "Resultful" => { + fallibility = Some(Fallibility::Resultful); + }, + _ => return syn::Error::new_spanned( + attr, + "The content of `fallibility` should be either `Infallible`, `Optional`, or `Resultful`." + ) + .into_compile_error() + .into() + } + } else { + return syn::Error::new_spanned( + attr, + "The content of `fallibility` should be a single identifier.", + ) + .into_compile_error() + .into(); + } + } else { + return syn::Error::new_spanned( + attr, + "There should only be one `fallibility` attribute.", + ) + .into_compile_error() + .into(); + } + } + } + + let fallibility = fallibility.unwrap_or(Fallibility::Infallible); + + let fallible = { + let mut f = path.clone(); + f.segments.push(format_ident!("system").into()); + match fallibility { + Fallibility::Infallible => f.segments.push(format_ident!("Infallible").into()), + Fallibility::Optional => f.segments.push(format_ident!("Optional").into()), + Fallibility::Resultful => f.segments.push(format_ident!("Resultful").into()), + } + f + }; + + // Read field-level attributes let field_attributes = fields .iter() .map(|field| { @@ -429,18 +497,54 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream { let struct_name = &ast.ident; let state_struct_visibility = &ast.vis; + let returned_struct = quote! { + #struct_name { + #(#fields,)* + #(#ignored_fields: <#ignored_field_types>::default(),)* + } + }; + + let (get_param_body, get_param_return) = match fallibility { + Fallibility::Infallible => ( + quote! { + #(let #fields = <<#field_types as #path::system::SystemParam<#fallible>>::State as #path::system::SystemParamState<#fallible>>::get_param(&mut state.state.#field_indices, system_meta, world, change_tick);)* + + #returned_struct + }, + quote! { Self::Item<'w, 's> }, + ), + Fallibility::Optional => ( + quote! { + #(let Some(#fields) = <<#field_types as #path::system::SystemParam<#fallible>>::State as #path::system::SystemParamState<#fallible>>::get_param(&mut state.state.#field_indices, system_meta, world, change_tick) else { + return None; + };)* + + Some(#returned_struct) + }, + quote! { Option> }, + ), + Fallibility::Resultful => ( + quote! { + #(let #fields = <<#field_types as #path::system::SystemParam<#fallible>>::State as #path::system::SystemParamState<#fallible>>::get_param(&mut state.state.#field_indices, system_meta, world, change_tick)?;)* + + Ok(#returned_struct) + }, + quote! { Result, &'s dyn std::error::Error> }, + ), + }; + 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::State, e.g. EventReaderState can be accessed via // as SystemParam>::State const _: () = { - impl<'w, 's, #punctuated_generics> #path::system::SystemParam for #struct_name #ty_generics #where_clause { + impl<'w, 's, #punctuated_generics> #path::system::SystemParam<#fallible> for #struct_name #ty_generics #where_clause { type State = State<'w, 's, #punctuated_generic_idents>; } #[doc(hidden)] type State<'w, 's, #punctuated_generic_idents> = FetchState< - (#(<#field_types as #path::system::SystemParam>::State,)*), + (#(<#field_types as #path::system::SystemParam<#fallible>>::State,)*), #punctuated_generic_idents >; @@ -450,7 +554,7 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream { marker: std::marker::PhantomData(#punctuated_generic_idents)> } - unsafe impl<'__w, '__s, #punctuated_generics> #path::system::SystemParamState for + unsafe impl<'__w, '__s, #punctuated_generics> #path::system::SystemParamState<#fallible> for State<'__w, '__s, #punctuated_generic_idents> #where_clause { type Item<'w, 's> = #struct_name #ty_generics; @@ -467,7 +571,7 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream { } fn apply(&mut self, system_meta: &#path::system::SystemMeta, world: &mut #path::world::World) { - self.state.apply(system_meta, world) + #path::system::SystemParamState::apply(&mut self.state, system_meta, world) } unsafe fn get_param<'w, 's>( @@ -475,11 +579,8 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream { system_meta: &#path::system::SystemMeta, world: &'w #path::world::World, change_tick: u32, - ) -> Self::Item<'w, 's> { - #struct_name { - #(#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(),)* - } + ) -> #get_param_return { + #get_param_body } } diff --git a/crates/bevy_ecs/src/system/commands/parallel_scope.rs b/crates/bevy_ecs/src/system/commands/parallel_scope.rs index 72c8118aa5152..2f0d71efc9cf1 100644 --- a/crates/bevy_ecs/src/system/commands/parallel_scope.rs +++ b/crates/bevy_ecs/src/system/commands/parallel_scope.rs @@ -5,7 +5,7 @@ use thread_local::ThreadLocal; use crate::{ entity::Entities, prelude::World, - system::{SystemMeta, SystemParam, SystemParamState}, + system::{Infallible, SystemMeta, SystemParam, SystemParamState}, }; use super::{CommandQueue, Commands}; @@ -48,12 +48,12 @@ pub struct ParallelCommands<'w, 's> { entities: &'w Entities, } -impl SystemParam for ParallelCommands<'_, '_> { +impl SystemParam for ParallelCommands<'_, '_> { type State = ParallelCommandsState; } // SAFETY: no component or resource access to report -unsafe impl SystemParamState for ParallelCommandsState { +unsafe impl SystemParamState for ParallelCommandsState { type Item<'w, 's> = ParallelCommands<'w, 's>; fn init(_: &mut World, _: &mut crate::system::SystemMeta) -> Self { diff --git a/crates/bevy_ecs/src/system/exclusive_system_param.rs b/crates/bevy_ecs/src/system/exclusive_system_param.rs index 6c52738901254..f7babfa7b9185 100644 --- a/crates/bevy_ecs/src/system/exclusive_system_param.rs +++ b/crates/bevy_ecs/src/system/exclusive_system_param.rs @@ -1,7 +1,7 @@ use crate::{ prelude::{FromWorld, QueryState}, query::{ReadOnlyWorldQuery, WorldQuery}, - system::{Local, LocalState, SystemMeta, SystemParam, SystemState}, + system::{Infallible, Local, LocalState, SystemMeta, SystemParam, SystemState}, world::World, }; use bevy_ecs_macros::all_tuples; @@ -45,11 +45,11 @@ impl ExclusiveSystemPa } } -impl<'a, P: SystemParam + 'static> ExclusiveSystemParam for &'a mut SystemState

{ +impl<'a, P: SystemParam + 'static> ExclusiveSystemParam for &'a mut SystemState

{ type State = SystemState

; } -impl ExclusiveSystemParamState for SystemState

{ +impl> ExclusiveSystemParamState for SystemState

{ type Item<'s> = &'s mut SystemState

; fn init(world: &mut World, _system_meta: &mut SystemMeta) -> Self { diff --git a/crates/bevy_ecs/src/system/function_system.rs b/crates/bevy_ecs/src/system/function_system.rs index 2cc88f9e30b77..2c8602c31ba4a 100644 --- a/crates/bevy_ecs/src/system/function_system.rs +++ b/crates/bevy_ecs/src/system/function_system.rs @@ -6,8 +6,8 @@ use crate::{ query::{Access, FilteredAccessSet}, schedule::{SystemLabel, SystemLabelId}, system::{ - check_system_change_tick, ReadOnlySystemParam, System, SystemParam, SystemParamItem, - SystemParamState, + check_system_change_tick, Infallible, ReadOnlySystemParam, System, SystemParam, + SystemParamItem, SystemParamState, }, world::{World, WorldId}, }; @@ -139,18 +139,18 @@ impl SystemMeta { /// }; /// }); /// ``` -pub struct SystemState { +pub struct SystemState + 'static> { meta: SystemMeta, - param_state: ::State, + param_state: >::State, world_id: WorldId, archetype_generation: ArchetypeGeneration, } -impl SystemState { +impl> SystemState { pub fn new(world: &mut World) -> Self { let mut meta = SystemMeta::new::(); meta.last_change_tick = world.change_tick().wrapping_sub(MAX_CHANGE_AGE); - let param_state = ::init(world, &mut meta); + let param_state = >::init(world, &mut meta); Self { meta, param_state, @@ -223,7 +223,7 @@ impl SystemState { world: &'w World, ) -> SystemParamItem<'w, 's, Param> { let change_tick = world.increment_change_tick(); - let param = ::get_param( + let param = >::get_param( &mut self.param_state, &self.meta, world, @@ -234,7 +234,7 @@ impl SystemState { } } -impl FromWorld for SystemState { +impl> FromWorld for SystemState { fn from_world(world: &mut World) -> Self { Self::new(world) } @@ -312,7 +312,7 @@ pub struct InputMarker; /// [`FunctionSystem`] must be `.initialized` before they can be run. pub struct FunctionSystem where - Param: SystemParam, + Param: SystemParam, { func: F, param_state: Option, @@ -329,7 +329,7 @@ impl IntoSystem + 'static, Marker: 'static, F: SystemParamFunction + Send + Sync + 'static, { @@ -348,7 +348,7 @@ where impl FunctionSystem where - Param: SystemParam, + Param: SystemParam, { /// Message shown when a system isn't initialised // When lines get too long, rustfmt can sometimes refuse to format them. @@ -360,7 +360,7 @@ impl System for FunctionSystem + 'static, Marker: 'static, F: SystemParamFunction + Send + Sync + 'static, { @@ -400,7 +400,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 = ::State::get_param( + let params = >::State::get_param( self.param_state.as_mut().expect(Self::PARAM_MESSAGE), &self.system_meta, world, @@ -429,7 +429,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(::init( + self.param_state = Some(>::init( world, &mut self.system_meta, )); @@ -505,7 +505,7 @@ impl Copy for SystemTypeIdLabel {} /// use std::num::ParseIntError; /// /// use bevy_ecs::prelude::*; -/// use bevy_ecs::system::{SystemParam, SystemParamItem}; +/// use bevy_ecs::system::{Infallible, SystemParam, SystemParamItem}; /// /// // Unfortunately, we need all of these generics. `A` is the first system, with its /// // parameters and marker type required for coherence. `B` is the second system, and @@ -519,8 +519,8 @@ impl Copy for SystemTypeIdLabel {} /// // We need A and B to be systems, add those bounds /// A: SystemParamFunction, /// B: SystemParamFunction, -/// AParam: SystemParam, -/// BParam: SystemParam, +/// AParam: SystemParam, +/// BParam: SystemParam, /// { /// // The type of `params` is inferred based on the return of this function above /// move |In(a_in), mut params| { @@ -553,14 +553,16 @@ impl Copy for SystemTypeIdLabel {} /// ``` /// [`PipeSystem`]: crate::system::PipeSystem /// [`ParamSet`]: crate::system::ParamSet -pub trait SystemParamFunction: Send + Sync + 'static { +pub trait SystemParamFunction, Marker>: + Send + Sync + 'static +{ fn run(&mut self, input: In, param_value: SystemParamItem) -> Out; } macro_rules! impl_system_function { ($($param: ident),*) => { #[allow(non_snake_case)] - impl SystemParamFunction<(), Out, ($($param,)*), ()> for Func + impl),*> SystemParamFunction<(), Out, ($($param,)*), ()> for Func where for <'a> &'a mut Func: FnMut($($param),*) -> Out + @@ -584,7 +586,7 @@ macro_rules! impl_system_function { } #[allow(non_snake_case)] - impl SystemParamFunction for Func + impl),*> SystemParamFunction for Func where for <'a> &'a mut Func: FnMut(In, $($param),*) -> Out + @@ -617,8 +619,13 @@ pub trait AsSystemLabel { fn as_system_label(&self) -> SystemLabelId; } -impl> - AsSystemLabel<(In, Out, Param, Marker)> for T +impl< + In, + Out, + Param: SystemParam, + Marker, + T: SystemParamFunction, + > AsSystemLabel<(In, Out, Param, Marker)> for T { #[inline] fn as_system_label(&self) -> SystemLabelId { diff --git a/crates/bevy_ecs/src/system/system_param.rs b/crates/bevy_ecs/src/system/system_param.rs index 63f356c4b592c..42c60017cedca 100644 --- a/crates/bevy_ecs/src/system/system_param.rs +++ b/crates/bevy_ecs/src/system/system_param.rs @@ -18,13 +18,249 @@ use bevy_ptr::UnsafeCellDeref; use bevy_utils::synccell::SyncCell; use std::{ borrow::Cow, + error::Error, fmt::Debug, marker::PhantomData, ops::{Deref, DerefMut}, }; +/// A [`SystemParam`] that can be used as `T`. +/// +/// `SystemParam` is best implemented for parameters that can't fail. +/// +/// # Example +/// +/// ``` +/// # use bevy_ecs::prelude::*; +/// use bevy_ecs::system::{ +/// Infallible, ResState, SystemMeta, +/// SystemParam, SystemParamState, +/// }; +/// # #[derive(Resource)] +/// # struct SomeResource { +/// # value: u32, +/// # } +/// +/// #[derive(Debug)] +/// struct MyParam<'w> { +/// value: &'w u32, +/// } +/// +/// impl<'w> SystemParam for MyParam<'w> { +/// type State = MyParamState; +/// } +/// +/// struct MyParamState { +/// res_state: ResState, +/// } +/// +/// unsafe impl SystemParamState for MyParamState { +/// fn init(world: &mut World, system_meta: &mut SystemMeta) -> Self { +/// Self { +/// res_state: as SystemParamState>::init(world, system_meta), +/// } +/// } +/// +/// type Item<'w, 's> = MyParam<'w>; +/// +/// #[inline] +/// unsafe fn get_param<'w, 's>( +/// state: &'s mut Self, +/// system_meta: &SystemMeta, +/// world: &'w World, +/// change_tick: u32, +/// ) -> Self::Item<'w, 's> { +/// let some_res = < as SystemParam>::State as SystemParamState>::get_param( +/// &mut state.res_state, +/// system_meta, +/// world, +/// change_tick, +/// ); +/// let r = some_res.into_inner(); +/// MyParam { +/// value: &r.value, +/// } +/// } +/// } +/// ``` +pub struct Infallible; + +/// A [`SystemParam`] that can be used as `Option` and `T`. +/// +/// `SystemParam` is best implemented for parameters that have a single point of failure. +/// +/// By implementing `SystemParam`, `SystemParam` is implemented for `Option` and `T`. +/// +/// # Example +/// +/// ``` +/// # use bevy_ecs::prelude::*; +/// use bevy_ecs::system::{ +/// Infallible, Optional, OptionState, ResState, SystemMeta, +/// SystemParam, SystemParamState, +/// }; +/// # #[derive(Resource)] +/// # struct SomeResource { +/// # value: u32, +/// # } +/// +/// #[derive(Debug)] +/// struct MyParam<'w> { +/// value: &'w u32, +/// } +/// +/// impl<'w> SystemParam for MyParam<'w> { +/// type State = MyParamState; +/// } +/// +/// struct MyParamState { +/// res_state: OptionState>, +/// } +/// +/// unsafe impl SystemParamState for MyParamState { +/// fn init(world: &mut World, system_meta: &mut SystemMeta) -> Self { +/// Self { +/// res_state: OptionState::init(world, system_meta), +/// } +/// } +/// +/// type Item<'w, 's> = MyParam<'w>; +/// +/// #[inline] +/// unsafe fn get_param<'w, 's>( +/// state: &'s mut Self, +/// system_meta: &SystemMeta, +/// world: &'w World, +/// change_tick: u32, +/// ) -> Option> { +/// let some_res = <> as SystemParam>::State as SystemParamState>::get_param( +/// &mut state.res_state, +/// system_meta, +/// world, +/// change_tick, +/// ); +/// some_res.map(|r| { +/// let r = r.into_inner(); +/// MyParam { +/// value: &r.value, +/// } +/// }) +/// } +/// } +/// ``` +pub struct Optional; + +/// A [`SystemParam`] that can be used as `Result`, `Option`, and `T`. +/// +/// `SystemParam` is best implemented for parameters that have multiple points of failure. +/// +/// By implementing `SystemParam`, `SystemParam` is implemented for `T` and `SystemParam` is implemented for `Result`. +/// +/// # Example +/// +/// ``` +/// # use bevy_ecs::prelude::*; +/// use bevy_ecs::system::{ +/// Infallible, Resultful, OptionState, ResState, SystemMeta, +/// SystemParam, SystemParamState, +/// }; +/// use std::error::Error; +/// # #[derive(Resource)] +/// # struct SomeResource { +/// # value: u32, +/// # } +/// +/// #[derive(Debug)] +/// struct MyParam<'w> { +/// value: &'w u32, +/// } +/// +/// impl<'w> SystemParam for MyParam<'w> { +/// type State = MyParamState; +/// } +/// +/// struct MyParamState { +/// res_state: OptionState>, +/// } +/// +/// unsafe impl SystemParamState for MyParamState { +/// fn init(world: &mut World, system_meta: &mut SystemMeta) -> Self { +/// Self { +/// res_state: OptionState::init(world, system_meta), +/// } +/// } +/// +/// type Item<'w, 's> = MyParam<'w>; +/// +/// #[inline] +/// unsafe fn get_param<'w, 's>( +/// state: &'s mut Self, +/// system_meta: &SystemMeta, +/// world: &'w World, +/// change_tick: u32, +/// ) -> Result, &'s dyn Error> { +/// // Since `Res` doesn't implement `SystemParam`, we have to use `Option>` and map it to a result. +/// let some_res = <> as SystemParam>::State as SystemParamState>::get_param( +/// &mut state.res_state, +/// system_meta, +/// world, +/// change_tick, +/// ); +/// +/// match some_res { +/// Some(r) => { +/// let r = r.into_inner(); +/// Ok(MyParam { +/// value: &r.value, +/// }) +/// } +/// None => { +/// Err(&MyError(45)) +/// } +/// } +/// } +/// } +/// +/// #[derive(Debug)] +/// struct MyError(u32); +/// +/// impl std::fmt::Display for MyError { +/// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +/// write!(f, "MyError has {}!", self.0) +/// } +/// } +/// +/// impl Error for MyError {} +/// ``` +pub struct Resultful; + +mod sealed { + use std::error::Error; + + /// Describes a [`SystemParam`](super::SystemParam)'s level of fallibility. + pub trait Fallibility { + /// Maps `T` to some form of error-handling. + type Fallible<'s, T>; + } + impl Fallibility for super::Infallible { + type Fallible<'s, T> = T; + } + impl Fallibility for super::Optional { + type Fallible<'s, T> = Option; + } + impl Fallibility for super::Resultful { + type Fallible<'s, T> = Result; + } +} + /// A parameter that can be used in a [`System`](super::System). /// +/// This trait comes in three variants, where [`Infallible`] is the base variant: +/// +/// - [`Infallible`]: Which can be used as `T`. +/// - [`Optional`]: Which can be used as `Option` or `T`. +/// - [`Resultful`]: Which can be used as `Result`, `Option`, or `T`. +/// /// # Derive /// /// This trait can be derived with the [`derive@super::SystemParam`] macro. @@ -38,6 +274,11 @@ use std::{ /// /// ## Attributes /// +/// `#[fallibility(T)]`: +/// Can be added to the struct. `T` can be one of [`Infallible`], [`Optional`], or [`Resultful`]. +/// This requires the fields to have the same fallibility. +/// If the attribute is not specified, the fallibility defaults to [`Infallible`]. +/// /// `#[system_param(ignore)]`: /// Can be added to any field in the struct. Fields decorated with this attribute /// will be created with the default value upon realisation. @@ -53,6 +294,7 @@ use std::{ /// use bevy_ecs::system::SystemParam; /// /// #[derive(SystemParam)] +/// #[fallibility(Optional)] /// struct MyParam<'w, Marker: 'static> { /// foo: Res<'w, SomeResource>, /// #[system_param(ignore)] @@ -121,11 +363,143 @@ use std::{ /// /// [`SyncCell`]: bevy_utils::synccell::SyncCell /// [`Exclusive`]: https://doc.rust-lang.org/nightly/std/sync/struct.Exclusive.html -pub trait SystemParam: Sized { - type State: SystemParamState; +pub trait SystemParam: Sized { + type State: SystemParamState; +} + +impl> SystemParam for T { + type State = T::State; +} + +// SAFETY: `SystemParamState` must be safely implemented. +unsafe impl> SystemParamState for T { + fn init(world: &mut World, system_meta: &mut SystemMeta) -> Self { + T::init(world, system_meta) + } + #[inline] + fn new_archetype(&mut self, archetype: &Archetype, system_meta: &mut SystemMeta) { + self.new_archetype(archetype, system_meta); + } + #[inline] + fn apply(&mut self, system_meta: &SystemMeta, world: &mut World) { + self.apply(system_meta, world); + } + + type Item<'world, 'state> = T::Item<'world, 'state>; + + unsafe fn get_param<'world, 'state>( + state: &'state mut Self, + system_meta: &SystemMeta, + world: &'world World, + change_tick: u32, + ) -> Self::Item<'world, 'state> { + T::get_param(state, system_meta, world, change_tick).unwrap_or_else(|| { + panic!( + "Failed to get system param `{}`", + std::any::type_name::>() + ) + }) + } +} + +impl> SystemParam for Option { + type State = OptionState; +} + +#[doc(hidden)] +pub struct OptionState>(T); + +// SAFETY: `SystemParamState` must be safely implemented. +unsafe impl> SystemParamState for OptionState { + fn init(world: &mut World, system_meta: &mut SystemMeta) -> Self { + Self(T::init(world, system_meta)) + } + #[inline] + fn new_archetype(&mut self, archetype: &Archetype, system_meta: &mut SystemMeta) { + self.0.new_archetype(archetype, system_meta); + } + #[inline] + fn apply(&mut self, system_meta: &SystemMeta, world: &mut World) { + self.0.apply(system_meta, world); + } + + type Item<'world, 'state> = Option>; + + unsafe fn get_param<'world, 'state>( + state: &'state mut Self, + system_meta: &SystemMeta, + world: &'world World, + change_tick: u32, + ) -> Self::Item<'world, 'state> { + T::get_param(&mut state.0, system_meta, world, change_tick) + } } -pub type SystemParamItem<'w, 's, P> = <

::State as SystemParamState>::Item<'w, 's>; +impl> SystemParam for T { + type State = T::State; +} + +// SAFETY: `SystemParamState` must be safely implemented. +unsafe impl> SystemParamState for T { + fn init(world: &mut World, system_meta: &mut SystemMeta) -> Self { + T::init(world, system_meta) + } + #[inline] + fn new_archetype(&mut self, archetype: &Archetype, system_meta: &mut SystemMeta) { + self.new_archetype(archetype, system_meta); + } + #[inline] + fn apply(&mut self, system_meta: &SystemMeta, world: &mut World) { + self.apply(system_meta, world); + } + + type Item<'world, 'state> = T::Item<'world, 'state>; + + unsafe fn get_param<'world, 'state>( + state: &'state mut Self, + system_meta: &SystemMeta, + world: &'world World, + change_tick: u32, + ) -> Option> { + T::get_param(state, system_meta, world, change_tick).ok() + } +} + +impl<'s, T: SystemParam> SystemParam for Result { + type State = ResultState; +} + +#[doc(hidden)] +pub struct ResultState>(T); + +// SAFETY: `SystemParamState` must be safely implemented. +unsafe impl> SystemParamState for ResultState { + fn init(world: &mut World, system_meta: &mut SystemMeta) -> Self { + Self(T::init(world, system_meta)) + } + #[inline] + fn new_archetype(&mut self, archetype: &Archetype, system_meta: &mut SystemMeta) { + self.0.new_archetype(archetype, system_meta); + } + #[inline] + fn apply(&mut self, system_meta: &SystemMeta, world: &mut World) { + self.0.apply(system_meta, world); + } + + type Item<'world, 'state> = Result, &'state dyn Error>; + + unsafe fn get_param<'world, 'state>( + state: &'state mut Self, + system_meta: &SystemMeta, + world: &'world World, + change_tick: u32, + ) -> Self::Item<'world, 'state> { + T::get_param(&mut state.0, system_meta, world, change_tick) + } +} + +pub type SystemParamItem<'w, 's, P> = + <

>::State as SystemParamState>::Item<'w, 's>; /// The state of a [`SystemParam`]. /// @@ -135,7 +509,7 @@ pub type SystemParamItem<'w, 's, P> = <

::State as SystemParamS /// [`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 { +pub unsafe trait SystemParamState: Send + Sync + 'static { fn init(world: &mut World, system_meta: &mut SystemMeta) -> Self; #[inline] fn new_archetype(&mut self, _archetype: &Archetype, _system_meta: &mut SystemMeta) {} @@ -143,7 +517,7 @@ pub unsafe trait SystemParamState: Send + Sync + 'static { #[allow(unused_variables)] fn apply(&mut self, system_meta: &SystemMeta, _world: &mut World) {} - type Item<'world, 'state>: SystemParam; + type Item<'world, 'state>: SystemParam; /// # Safety /// /// This call might access any of the input parameters in an unsafe way. Make sure the data @@ -153,16 +527,16 @@ pub unsafe trait SystemParamState: Send + Sync + 'static { system_meta: &SystemMeta, world: &'world World, change_tick: u32, - ) -> Self::Item<'world, 'state>; + ) -> T::Fallible<'state, 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 {} +pub unsafe trait ReadOnlySystemParam: SystemParam {} -impl<'w, 's, Q: WorldQuery + 'static, F: ReadOnlyWorldQuery + 'static> SystemParam +impl<'w, 's, Q: WorldQuery + 'static, F: ReadOnlyWorldQuery + 'static> SystemParam for Query<'w, 's, Q, F> { type State = QueryState; @@ -176,7 +550,7 @@ unsafe impl<'w, 's, Q: ReadOnlyWorldQuery + 'static, F: ReadOnlyWorldQuery + 'st // SAFETY: Relevant query ComponentId and ArchetypeComponentId access is applied to SystemMeta. If // this QueryState conflicts with any prior access, a panic will occur. -unsafe impl SystemParamState +unsafe impl SystemParamState for QueryState { type Item<'w, 's> = Query<'w, 's, Q, F>; @@ -239,14 +613,14 @@ fn assert_component_access_compatibility( query_type, filter_type, system_name, accesses); } -pub struct ParamSet<'w, 's, T: SystemParam> { +pub struct ParamSet<'w, 's, T: SystemParam> { param_states: &'s mut T::State, world: &'w World, system_meta: SystemMeta, change_tick: u32, } /// The [`SystemParamState`] of [`ParamSet`]. -pub struct ParamSetState(T); +pub struct ParamSetState>(T); impl_param_set!(); @@ -390,13 +764,13 @@ pub struct ResState { marker: PhantomData, } -impl<'a, T: Resource> SystemParam for Res<'a, T> { +impl<'a, T: Resource> SystemParam for Res<'a, T> { type State = ResState; } // SAFETY: Res ComponentId and ArchetypeComponentId access is applied to SystemMeta. If this Res // conflicts with any prior access, a panic will occur. -unsafe impl SystemParamState for ResState { +unsafe impl SystemParamState for ResState { type Item<'w, 's> = Res<'w, T>; fn init(world: &mut World, system_meta: &mut SystemMeta) -> Self { @@ -430,56 +804,9 @@ unsafe impl SystemParamState for ResState { system_meta: &SystemMeta, world: &'w World, change_tick: u32, - ) -> Self::Item<'w, 's> { - let (ptr, ticks) = world - .get_resource_with_ticks(state.component_id) - .unwrap_or_else(|| { - panic!( - "Resource requested by {} does not exist: {}", - system_meta.name, - std::any::type_name::() - ) - }); - Res { - value: ptr.deref(), - added: ticks.added.deref(), - changed: ticks.changed.deref(), - last_change_tick: system_meta.last_change_tick, - change_tick, - } - } -} - -/// The [`SystemParamState`] of [`Option>`]. -/// See: [`Res`] -#[doc(hidden)] -pub struct OptionResState(ResState); - -impl<'a, T: Resource> SystemParam for Option> { - type State = OptionResState; -} - -// SAFETY: Only reads a single World resource -unsafe impl<'a, T: Resource> ReadOnlySystemParam for Option> {} - -// SAFETY: this impl defers to `ResState`, which initializes -// and validates the correct world access -unsafe impl SystemParamState for OptionResState { - type Item<'w, 's> = Option>; - - fn init(world: &mut World, system_meta: &mut SystemMeta) -> Self { - Self(ResState::init(world, system_meta)) - } - - #[inline] - unsafe fn get_param<'w, 's>( - state: &'s mut Self, - system_meta: &SystemMeta, - world: &'w World, - change_tick: u32, - ) -> Self::Item<'w, 's> { + ) -> Option> { world - .get_resource_with_ticks(state.0.component_id) + .get_resource_with_ticks(state.component_id) .map(|(ptr, ticks)| Res { value: ptr.deref(), added: ticks.added.deref(), @@ -497,13 +824,13 @@ pub struct ResMutState { marker: PhantomData, } -impl<'a, T: Resource> SystemParam for ResMut<'a, T> { +impl<'a, T: Resource> SystemParam for ResMut<'a, T> { type State = ResMutState; } // SAFETY: Res ComponentId and ArchetypeComponentId access is applied to SystemMeta. If this Res // conflicts with any prior access, a panic will occur. -unsafe impl SystemParamState for ResMutState { +unsafe impl SystemParamState for ResMutState { type Item<'w, 's> = ResMut<'w, T>; fn init(world: &mut World, system_meta: &mut SystemMeta) -> Self { @@ -540,55 +867,9 @@ unsafe impl SystemParamState for ResMutState { system_meta: &SystemMeta, world: &'w World, change_tick: u32, - ) -> Self::Item<'w, 's> { - let value = world - .get_resource_unchecked_mut_with_id(state.component_id) - .unwrap_or_else(|| { - panic!( - "Resource requested by {} does not exist: {}", - system_meta.name, - std::any::type_name::() - ) - }); - ResMut { - value: value.value, - ticks: Ticks { - added: value.ticks.added, - changed: value.ticks.changed, - last_change_tick: system_meta.last_change_tick, - change_tick, - }, - } - } -} - -/// The [`SystemParamState`] of [`Option>`]. -/// See: [`ResMut`] -#[doc(hidden)] -pub struct OptionResMutState(ResMutState); - -impl<'a, T: Resource> SystemParam for Option> { - type State = OptionResMutState; -} - -// SAFETY: this impl defers to `ResMutState`, which initializes -// and validates the correct world access -unsafe impl SystemParamState for OptionResMutState { - type Item<'w, 's> = Option>; - - fn init(world: &mut World, system_meta: &mut SystemMeta) -> Self { - Self(ResMutState::init(world, system_meta)) - } - - #[inline] - unsafe fn get_param<'w, 's>( - state: &'s mut Self, - system_meta: &SystemMeta, - world: &'w World, - change_tick: u32, - ) -> Self::Item<'w, 's> { + ) -> Option> { world - .get_resource_unchecked_mut_with_id(state.0.component_id) + .get_resource_unchecked_mut_with_id(state.component_id) .map(|value| ResMut { value: value.value, ticks: Ticks { @@ -601,7 +882,7 @@ unsafe impl SystemParamState for OptionResMutState { } } -impl<'w, 's> SystemParam for Commands<'w, 's> { +impl<'w, 's> SystemParam for Commands<'w, 's> { type State = CommandQueue; } @@ -609,7 +890,7 @@ impl<'w, 's> SystemParam for Commands<'w, 's> { unsafe impl<'w, 's> ReadOnlySystemParam for Commands<'w, 's> {} // SAFETY: only local state is accessed -unsafe impl SystemParamState for CommandQueue { +unsafe impl SystemParamState for CommandQueue { type Item<'w, 's> = Commands<'w, 's>; fn init(_world: &mut World, _system_meta: &mut SystemMeta) -> Self { @@ -642,12 +923,12 @@ unsafe impl<'w> ReadOnlySystemParam for &'w World {} #[doc(hidden)] pub struct WorldState; -impl<'w> SystemParam for &'w World { +impl<'w> SystemParam for &'w World { type State = WorldState; } // SAFETY: `read_all` access is set and conflicts result in a panic -unsafe impl SystemParamState for WorldState { +unsafe impl SystemParamState for WorldState { type Item<'w, 's> = &'w World; fn init(_world: &mut World, system_meta: &mut SystemMeta) -> Self { @@ -787,12 +1068,12 @@ where #[doc(hidden)] pub struct LocalState(pub(crate) SyncCell); -impl<'a, T: FromWorld + Send + 'static> SystemParam for Local<'a, T> { +impl<'a, T: FromWorld + Send + 'static> SystemParam for Local<'a, T> { type State = LocalState; } // SAFETY: only local state is accessed -unsafe impl SystemParamState for LocalState { +unsafe impl SystemParamState for LocalState { type Item<'w, 's> = Local<'s, T>; fn init(world: &mut World, _system_meta: &mut SystemMeta) -> Self { @@ -875,13 +1156,13 @@ pub struct RemovedComponentsState { marker: PhantomData, } -impl<'a, T: Component> SystemParam for RemovedComponents<'a, T> { +impl<'a, T: Component> SystemParam for RemovedComponents<'a, T> { type State = RemovedComponentsState; } // SAFETY: no component access. removed component entity collections can be read in parallel and are // never mutably borrowed during system execution -unsafe impl SystemParamState for RemovedComponentsState { +unsafe impl SystemParamState for RemovedComponentsState { type Item<'w, 's> = RemovedComponents<'w, T>; fn init(world: &mut World, _system_meta: &mut SystemMeta) -> Self { @@ -978,13 +1259,13 @@ pub struct NonSendState { marker: PhantomData T>, } -impl<'a, T: 'static> SystemParam for NonSend<'a, T> { +impl<'a, T: 'static> SystemParam for NonSend<'a, T> { type State = NonSendState; } // SAFETY: NonSendComponentId and ArchetypeComponentId access is applied to SystemMeta. If this // NonSend conflicts with any prior access, a panic will occur. -unsafe impl SystemParamState for NonSendState { +unsafe impl SystemParamState for NonSendState { type Item<'w, 's> = NonSend<'w, T>; fn init(world: &mut World, system_meta: &mut SystemMeta) -> Self { @@ -1020,58 +1301,10 @@ unsafe impl SystemParamState for NonSendState { system_meta: &SystemMeta, world: &'w World, change_tick: u32, - ) -> Self::Item<'w, 's> { - world.validate_non_send_access::(); - let (ptr, ticks) = world - .get_resource_with_ticks(state.component_id) - .unwrap_or_else(|| { - panic!( - "Non-send resource requested by {} does not exist: {}", - system_meta.name, - std::any::type_name::() - ) - }); - - NonSend { - value: ptr.deref(), - ticks: ticks.read(), - last_change_tick: system_meta.last_change_tick, - change_tick, - } - } -} - -/// The [`SystemParamState`] of [`Option>`]. -/// See: [`NonSend`] -#[doc(hidden)] -pub struct OptionNonSendState(NonSendState); - -impl<'w, T: 'static> SystemParam for Option> { - type State = OptionNonSendState; -} - -// SAFETY: Only reads a single non-send resource -unsafe impl<'w, T: 'static> ReadOnlySystemParam for Option> {} - -// SAFETY: this impl defers to `NonSendState`, which initializes -// and validates the correct world access -unsafe impl SystemParamState for OptionNonSendState { - type Item<'w, 's> = Option>; - - fn init(world: &mut World, system_meta: &mut SystemMeta) -> Self { - Self(NonSendState::init(world, system_meta)) - } - - #[inline] - unsafe fn get_param<'w, 's>( - state: &'s mut Self, - system_meta: &SystemMeta, - world: &'w World, - change_tick: u32, - ) -> Self::Item<'w, 's> { + ) -> Option> { world.validate_non_send_access::(); world - .get_resource_with_ticks(state.0.component_id) + .get_resource_with_ticks(state.component_id) .map(|(ptr, ticks)| NonSend { value: ptr.deref(), ticks: ticks.read(), @@ -1088,13 +1321,13 @@ pub struct NonSendMutState { marker: PhantomData T>, } -impl<'a, T: 'static> SystemParam for NonSendMut<'a, T> { +impl<'a, T: 'static> SystemParam for NonSendMut<'a, T> { type State = NonSendMutState; } // SAFETY: NonSendMut ComponentId and ArchetypeComponentId access is applied to SystemMeta. If this // NonSendMut conflicts with any prior access, a panic will occur. -unsafe impl SystemParamState for NonSendMutState { +unsafe impl SystemParamState for NonSendMutState { type Item<'w, 's> = NonSendMut<'w, T>; fn init(world: &mut World, system_meta: &mut SystemMeta) -> Self { @@ -1133,52 +1366,10 @@ unsafe impl SystemParamState for NonSendMutState { system_meta: &SystemMeta, world: &'w World, change_tick: u32, - ) -> Self::Item<'w, 's> { - world.validate_non_send_access::(); - let (ptr, ticks) = world - .get_resource_with_ticks(state.component_id) - .unwrap_or_else(|| { - panic!( - "Non-send resource requested by {} does not exist: {}", - system_meta.name, - std::any::type_name::() - ) - }); - NonSendMut { - value: ptr.assert_unique().deref_mut(), - ticks: Ticks::from_tick_cells(ticks, system_meta.last_change_tick, change_tick), - } - } -} - -/// The [`SystemParamState`] of [`Option>`]. -/// See: [`NonSendMut`] -#[doc(hidden)] -pub struct OptionNonSendMutState(NonSendMutState); - -impl<'a, T: 'static> SystemParam for Option> { - type State = OptionNonSendMutState; -} - -// SAFETY: this impl defers to `NonSendMutState`, which initializes -// and validates the correct world access -unsafe impl SystemParamState for OptionNonSendMutState { - type Item<'w, 's> = Option>; - - fn init(world: &mut World, system_meta: &mut SystemMeta) -> Self { - Self(NonSendMutState::init(world, system_meta)) - } - - #[inline] - unsafe fn get_param<'w, 's>( - state: &'s mut Self, - system_meta: &SystemMeta, - world: &'w World, - change_tick: u32, - ) -> Self::Item<'w, 's> { + ) -> Option> { world.validate_non_send_access::(); world - .get_resource_with_ticks(state.0.component_id) + .get_resource_with_ticks(state.component_id) .map(|(ptr, ticks)| NonSendMut { value: ptr.assert_unique().deref_mut(), ticks: Ticks::from_tick_cells(ticks, system_meta.last_change_tick, change_tick), @@ -1186,7 +1377,7 @@ unsafe impl SystemParamState for OptionNonSendMutState { } } -impl<'a> SystemParam for &'a Archetypes { +impl<'a> SystemParam for &'a Archetypes { type State = ArchetypesState; } @@ -1198,7 +1389,7 @@ unsafe impl<'a> ReadOnlySystemParam for &'a Archetypes {} pub struct ArchetypesState; // SAFETY: no component value access -unsafe impl SystemParamState for ArchetypesState { +unsafe impl SystemParamState for ArchetypesState { type Item<'w, 's> = &'w Archetypes; fn init(_world: &mut World, _system_meta: &mut SystemMeta) -> Self { @@ -1216,7 +1407,7 @@ unsafe impl SystemParamState for ArchetypesState { } } -impl<'a> SystemParam for &'a Components { +impl<'a> SystemParam for &'a Components { type State = ComponentsState; } @@ -1228,7 +1419,7 @@ unsafe impl<'a> ReadOnlySystemParam for &'a Components {} pub struct ComponentsState; // SAFETY: no component value access -unsafe impl SystemParamState for ComponentsState { +unsafe impl SystemParamState for ComponentsState { type Item<'w, 's> = &'w Components; fn init(_world: &mut World, _system_meta: &mut SystemMeta) -> Self { @@ -1246,7 +1437,7 @@ unsafe impl SystemParamState for ComponentsState { } } -impl<'a> SystemParam for &'a Entities { +impl<'a> SystemParam for &'a Entities { type State = EntitiesState; } @@ -1258,7 +1449,7 @@ unsafe impl<'a> ReadOnlySystemParam for &'a Entities {} pub struct EntitiesState; // SAFETY: no component value access -unsafe impl SystemParamState for EntitiesState { +unsafe impl SystemParamState for EntitiesState { type Item<'w, 's> = &'w Entities; fn init(_world: &mut World, _system_meta: &mut SystemMeta) -> Self { @@ -1276,7 +1467,7 @@ unsafe impl SystemParamState for EntitiesState { } } -impl<'a> SystemParam for &'a Bundles { +impl<'a> SystemParam for &'a Bundles { type State = BundlesState; } @@ -1288,7 +1479,7 @@ unsafe impl<'a> ReadOnlySystemParam for &'a Bundles {} pub struct BundlesState; // SAFETY: no component value access -unsafe impl SystemParamState for BundlesState { +unsafe impl SystemParamState for BundlesState { type Item<'w, 's> = &'w Bundles; fn init(_world: &mut World, _system_meta: &mut SystemMeta) -> Self { @@ -1338,7 +1529,7 @@ impl SystemChangeTick { // SAFETY: Only reads internal system state unsafe impl ReadOnlySystemParam for SystemChangeTick {} -impl SystemParam for SystemChangeTick { +impl SystemParam for SystemChangeTick { type State = SystemChangeTickState; } @@ -1347,7 +1538,7 @@ impl SystemParam for SystemChangeTick { pub struct SystemChangeTickState {} // SAFETY: `SystemParamTickState` doesn't require any world access -unsafe impl SystemParamState for SystemChangeTickState { +unsafe impl SystemParamState for SystemChangeTickState { type Item<'w, 's> = SystemChangeTick; fn init(_world: &mut World, _system_meta: &mut SystemMeta) -> Self { @@ -1414,7 +1605,7 @@ impl<'s> std::fmt::Display for SystemName<'s> { } } -impl<'s> SystemParam for SystemName<'s> { +impl<'s> SystemParam for SystemName<'s> { type State = SystemNameState; } @@ -1428,7 +1619,7 @@ pub struct SystemNameState { } // SAFETY: no component value access -unsafe impl SystemParamState for SystemNameState { +unsafe impl SystemParamState for SystemNameState { type Item<'w, 's> = SystemName<'s>; fn init(_world: &mut World, system_meta: &mut SystemMeta) -> Self { @@ -1452,7 +1643,7 @@ unsafe impl SystemParamState for SystemNameState { macro_rules! impl_system_param_tuple { ($($param: ident),*) => { - impl<$($param: SystemParam),*> SystemParam for ($($param,)*) { + impl<$($param: SystemParam),*> SystemParam for ($($param,)*) { type State = ($($param::State,)*); } @@ -1463,7 +1654,7 @@ macro_rules! impl_system_param_tuple { // 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,)*) { + unsafe impl<$($param: SystemParamState),*> SystemParamState for ($($param,)*) { type Item<'w, 's> = ($($param::Item::<'w, 's>,)*); #[inline] @@ -1523,14 +1714,14 @@ pub mod lifetimeless { /// /// ``` /// # use bevy_ecs::prelude::*; -/// use bevy_ecs::system::{SystemParam, StaticSystemParam}; +/// use bevy_ecs::system::{Infallible, SystemParam, StaticSystemParam}; /// #[derive(SystemParam)] -/// struct GenericParam<'w,'s, T: SystemParam + 'static> { +/// struct GenericParam<'w,'s, T: SystemParam + 'static> { /// field: StaticSystemParam<'w, 's, T>, /// } -/// fn do_thing_generically(t: StaticSystemParam) {} +/// fn do_thing_generically + 'static>(t: StaticSystemParam) {} /// -/// fn check_always_is_system(){ +/// fn check_always_is_system + 'static>(){ /// bevy_ecs::system::assert_is_system(do_thing_generically::); /// } /// ``` @@ -1563,9 +1754,9 @@ pub mod lifetimeless { /// # } /// ``` /// -pub struct StaticSystemParam<'w, 's, P: SystemParam>(SystemParamItem<'w, 's, P>); +pub struct StaticSystemParam<'w, 's, P: SystemParam>(SystemParamItem<'w, 's, P>); -impl<'w, 's, P: SystemParam> Deref for StaticSystemParam<'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 { @@ -1573,13 +1764,13 @@ impl<'w, 's, P: SystemParam> Deref for StaticSystemParam<'w, 's, P> { } } -impl<'w, 's, P: SystemParam> DerefMut for StaticSystemParam<'w, 's, P> { +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> { +impl<'w, 's, P: SystemParam> StaticSystemParam<'w, 's, P> { /// Get the value of the parameter pub fn into_inner(self) -> SystemParamItem<'w, 's, P> { self.0 @@ -1596,15 +1787,15 @@ unsafe impl<'w, 's, P: ReadOnlySystemParam + 'static> ReadOnlySystemParam { } -impl<'world, 'state, P: SystemParam + 'static> SystemParam +impl<'world, 'state, P: SystemParam + 'static> SystemParam for StaticSystemParam<'world, 'state, P> { type State = StaticSystemParamState; } // SAFETY: all methods are just delegated to `S`'s `SystemParamState` implementation -unsafe impl + 'static> SystemParamState - for StaticSystemParamState +unsafe impl, P: SystemParam + 'static> + SystemParamState for StaticSystemParamState { type Item<'world, 'state> = StaticSystemParam<'world, 'state, P>; @@ -1663,4 +1854,10 @@ mod tests { #[derive(SystemParam)] pub struct UnitParam {} + + #[derive(SystemParam)] + #[fallibility(Optional)] + pub struct OptionalParam<'w, T: Resource> { + _res: Res<'w, T>, + } } diff --git a/crates/bevy_render/src/extract_param.rs b/crates/bevy_render/src/extract_param.rs index b3d4ba665a55a..a0b9cb1292d32 100644 --- a/crates/bevy_render/src/extract_param.rs +++ b/crates/bevy_render/src/extract_param.rs @@ -2,8 +2,8 @@ use crate::MainWorld; use bevy_ecs::{ prelude::*, system::{ - ReadOnlySystemParam, ResState, SystemMeta, SystemParam, SystemParamItem, SystemParamState, - SystemState, + Infallible, ReadOnlySystemParam, ResState, SystemMeta, SystemParam, SystemParamItem, + SystemParamState, SystemState, }, }; use std::ops::{Deref, DerefMut}; @@ -49,7 +49,7 @@ where item: SystemParamItem<'w, 's, P>, } -impl<'w, 's, P> SystemParam for Extract<'w, 's, P> +impl<'w, 's, P> SystemParam for Extract<'w, 's, P> where P: ReadOnlySystemParam, { @@ -57,14 +57,14 @@ where } #[doc(hidden)] -pub struct ExtractState { +pub struct ExtractState + 'static> { state: SystemState

, main_world_state: ResState, } // SAFETY: only accesses MainWorld resource with read only system params using ResState, // which is initialized in init() -unsafe impl SystemParamState for ExtractState

+unsafe impl + 'static> SystemParamState for ExtractState

where P: ReadOnlySystemParam + 'static, { @@ -74,7 +74,10 @@ where let mut main_world = world.resource_mut::(); Self { state: SystemState::new(&mut main_world), - main_world_state: ResState::init(world, system_meta), + main_world_state: as SystemParamState>::init( + world, + system_meta, + ), } } @@ -84,7 +87,7 @@ where world: &'w World, change_tick: u32, ) -> Self::Item<'w, 's> { - let main_world = ResState::::get_param( + let main_world = as SystemParamState>::get_param( &mut state.main_world_state, system_meta, world, @@ -95,7 +98,7 @@ where } } -impl<'w, 's, P: SystemParam> Deref for Extract<'w, 's, P> +impl<'w, 's, P: SystemParam> Deref for Extract<'w, 's, P> where P: ReadOnlySystemParam, { @@ -107,7 +110,7 @@ where } } -impl<'w, 's, P: SystemParam> DerefMut for Extract<'w, 's, P> +impl<'w, 's, P: SystemParam> DerefMut for Extract<'w, 's, P> where P: ReadOnlySystemParam, { @@ -117,7 +120,7 @@ where } } -impl<'a, 'w, 's, P: SystemParam> IntoIterator for &'a Extract<'w, 's, P> +impl<'a, 'w, 's, P: SystemParam> IntoIterator for &'a Extract<'w, 's, P> where P: ReadOnlySystemParam, &'a SystemParamItem<'w, 's, P>: IntoIterator, diff --git a/crates/bevy_render/src/render_asset.rs b/crates/bevy_render/src/render_asset.rs index 9bdee8a4cd893..eab9d6648d1fb 100644 --- a/crates/bevy_render/src/render_asset.rs +++ b/crates/bevy_render/src/render_asset.rs @@ -4,7 +4,7 @@ use bevy_asset::{Asset, AssetEvent, Assets, Handle}; use bevy_derive::{Deref, DerefMut}; use bevy_ecs::{ prelude::*, - system::{StaticSystemParam, SystemParam, SystemParamItem}, + system::{Infallible, StaticSystemParam, SystemParam, SystemParamItem}, }; use bevy_utils::{HashMap, HashSet}; use std::marker::PhantomData; @@ -29,7 +29,7 @@ pub trait RenderAsset: Asset { type PreparedAsset: Send + Sync + 'static; /// Specifies all ECS data required by [`RenderAsset::prepare_asset`]. /// For convenience use the [`lifetimeless`](bevy_ecs::system::lifetimeless) [`SystemParam`]. - type Param: SystemParam; + type Param: SystemParam; /// Converts the asset into a [`RenderAsset::ExtractedAsset`]. fn extract_asset(&self) -> Self::ExtractedAsset; /// Prepares the `extracted asset` for the GPU by transforming it into diff --git a/crates/bevy_render/src/render_phase/draw.rs b/crates/bevy_render/src/render_phase/draw.rs index 67ff987b7972d..3a7f73e10ca07 100644 --- a/crates/bevy_render/src/render_phase/draw.rs +++ b/crates/bevy_render/src/render_phase/draw.rs @@ -7,8 +7,8 @@ use bevy_ecs::{ all_tuples, entity::Entity, system::{ - lifetimeless::SRes, ReadOnlySystemParam, Resource, SystemParam, SystemParamItem, - SystemState, + lifetimeless::SRes, Infallible, ReadOnlySystemParam, Resource, SystemParam, + SystemParamItem, SystemState, }, world::World, }; @@ -167,7 +167,7 @@ impl DrawFunctions

{ pub trait RenderCommand { /// Specifies all ECS data required by [`RenderCommand::render`]. /// All parameters have to be read only. - type Param: SystemParam + 'static; + type Param: SystemParam + 'static; /// Renders the [`PhaseItem`] by issuing draw calls via the [`TrackedRenderPass`]. fn render<'w>( @@ -184,7 +184,7 @@ pub enum RenderCommandResult { } pub trait EntityRenderCommand { - type Param: SystemParam + 'static; + type Param: SystemParam + 'static; fn render<'w>( view: Entity, item: Entity,