-
-
Notifications
You must be signed in to change notification settings - Fork 3.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Merged by Bors] - Obviate the need for RunSystem
, and remove it
#3817
Changes from all commits
7d02561
e8b7faa
898da83
054ce4a
8a300c4
59067f9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1254,6 +1254,131 @@ pub mod lifetimeless { | |
pub type SCommands = crate::system::Commands<'static, 'static>; | ||
} | ||
|
||
/// 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), | ||
/// no matter the argument [`SystemParam`] (`P`) (other than | ||
/// that `P` must be `'static`) | ||
/// | ||
/// This makes it useful for having arbitrary [`SystemParam`] type arguments | ||
/// to function systems, or for generic types using the [`derive@SystemParam`] | ||
/// derive: | ||
/// | ||
/// ``` | ||
/// # use bevy_ecs::prelude::*; | ||
/// use bevy_ecs::system::{SystemParam, StaticSystemParam}; | ||
/// #[derive(SystemParam)] | ||
/// struct GenericParam<'w,'s, T: SystemParam + 'static> { | ||
/// field: StaticSystemParam<'w, 's, T>, | ||
/// } | ||
/// fn do_thing_generically<T: SystemParam + 'static>(t: StaticSystemParam<T>) {} | ||
/// | ||
/// fn check_always_is_system<T: SystemParam + 'static>(){ | ||
/// bevy_ecs::system::assert_is_system(do_thing_generically::<T>); | ||
/// } | ||
/// ``` | ||
/// Note that in a real case you'd generally want | ||
/// additional bounds on `P`, for your use of the parameter | ||
/// to have a reason to be generic. | ||
/// | ||
/// For example, using this would allow a type to be generic over | ||
/// whether a resource is accessed mutably or not, with | ||
/// impls being bounded on [`P: Deref<Target=MyType>`](Deref), and | ||
/// [`P: DerefMut<Target=MyType>`](DerefMut) depending on whether the | ||
/// method requires mutable access or not. | ||
Comment on lines
+1285
to
+1289
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I plan on trying to use this trick for That will be a seperate PR. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've done some more thinking about this, and I realise that none of the reading only |
||
/// | ||
/// The method which doesn't use this type will not compile: | ||
/// ```compile_fail | ||
/// # use bevy_ecs::prelude::*; | ||
/// # use bevy_ecs::system::{SystemParam, StaticSystemParam}; | ||
/// | ||
/// fn do_thing_generically<T: SystemParam + 'static>(t: T) {} | ||
/// | ||
/// #[derive(SystemParam)] | ||
/// struct GenericParam<'w,'s, T: SystemParam> { | ||
/// field: T, | ||
/// #[system_param(ignore)] | ||
/// // Use the lifetimes, as the `SystemParam` derive requires them | ||
/// phantom: core::marker::PhantomData<&'w &'s ()> | ||
/// } | ||
/// # fn check_always_is_system<T: SystemParam + 'static>(){ | ||
/// # bevy_ecs::system::assert_is_system(do_thing_generically::<T>); | ||
/// # } | ||
/// ``` | ||
/// | ||
pub struct StaticSystemParam<'w, 's, P: SystemParam>(SystemParamItem<'w, 's, P>); | ||
|
||
impl<'w, 's, P: SystemParam> Deref for StaticSystemParam<'w, 's, P> { | ||
type Target = SystemParamItem<'w, 's, P>; | ||
|
||
fn deref(&self) -> &Self::Target { | ||
&self.0 | ||
} | ||
} | ||
|
||
impl<'w, 's, P: SystemParam> DerefMut for StaticSystemParam<'w, 's, P> { | ||
fn deref_mut(&mut self) -> &mut Self::Target { | ||
&mut self.0 | ||
} | ||
} | ||
|
||
impl<'w, 's, P: SystemParam> StaticSystemParam<'w, 's, P> { | ||
/// Get the value of the parameter | ||
pub fn into_inner(self) -> SystemParamItem<'w, 's, P> { | ||
self.0 | ||
} | ||
} | ||
|
||
/// The [`SystemParamState`] of [`SystemChangeTick`]. | ||
pub struct StaticSystemParamState<S, P>(S, PhantomData<fn() -> P>); | ||
DJMcNab marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
// Safe: This doesn't add any more reads, and the delegated fetch confirms it | ||
unsafe impl<'w, 's, S: ReadOnlySystemParamFetch, P> ReadOnlySystemParamFetch | ||
for StaticSystemParamState<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 { | ||
// Safe: We properly delegate SystemParamState | ||
StaticSystemParam(S::get_param(&mut state.0, system_meta, world, change_tick)) | ||
} | ||
} | ||
|
||
unsafe impl<'w, 's, S: SystemParamState, P: SystemParam + 'static> SystemParamState | ||
for StaticSystemParamState<S, P> | ||
{ | ||
fn init(world: &mut World, system_meta: &mut SystemMeta) -> Self { | ||
Self(S::init(world, system_meta), PhantomData) | ||
} | ||
|
||
fn new_archetype(&mut self, archetype: &Archetype, system_meta: &mut SystemMeta) { | ||
self.0.new_archetype(archetype, system_meta) | ||
} | ||
|
||
fn apply(&mut self, world: &mut World) { | ||
self.0.apply(world) | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::SystemParam; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This restriction is unfortunate, but pretty fundamental as far as I can tell.
This is because we need be able to refer to
P
inSystemParamState
, which reasonably needs to be'static