Skip to content

Commit

Permalink
Allow Option<NonSend<T>> and Option<NonSendMut<T>> as SystemParam (be…
Browse files Browse the repository at this point in the history
…vyengine#2345)

# Objective

Currently, you can add `Option<Res<T>` or `Option<ResMut<T>` as a SystemParam, if the Resource could potentially not exist, but this functionality doesn't exist for `NonSend` and `NonSendMut`

## Solution

Adds implementations to use `Option<NonSend<T>>` and Option<NonSendMut<T>> as SystemParams.
  • Loading branch information
MinerSebas authored and ostwilkens committed Jul 27, 2021
1 parent 3923c95 commit f8af599
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 0 deletions.
2 changes: 2 additions & 0 deletions crates/bevy_ecs/src/change_detection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,8 @@ impl_debug!(ResMut<'a, T>, Component);
/// # Panics
///
/// Panics when used as a `SystemParameter` if the resource does not exist.
///
/// Use `Option<NonSendMut<T>>` instead if the resource might not always exist.
pub struct NonSendMut<'a, T: 'static> {
pub(crate) value: &'a mut T,
pub(crate) ticks: Ticks<'a>,
Expand Down
85 changes: 85 additions & 0 deletions crates/bevy_ecs/src/system/system_param.rs
Original file line number Diff line number Diff line change
Expand Up @@ -683,6 +683,8 @@ impl<'a, T: Component> SystemParamFetch<'a> for RemovedComponentsState<T> {
/// # Panics
///
/// Panics when used as a `SystemParameter` if the resource does not exist.
///
/// Use `Option<NonSend<T>>` instead if the resource might not always exist.
pub struct NonSend<'w, T: 'static> {
pub(crate) value: &'w T,
ticks: ComponentTicks,
Expand Down Expand Up @@ -798,6 +800,48 @@ impl<'a, T: 'static> SystemParamFetch<'a> for NonSendState<T> {
}
}

/// The [`SystemParamState`] of `Option<NonSend<T>>`.
pub struct OptionNonSendState<T>(NonSendState<T>);

impl<'a, T: Component> SystemParam for Option<NonSend<'a, T>> {
type Fetch = OptionNonSendState<T>;
}

// SAFE: Only reads a single non-send resource
unsafe impl<T: 'static> ReadOnlySystemParamFetch for OptionNonSendState<T> {}

unsafe impl<T: 'static> SystemParamState for OptionNonSendState<T> {
type Config = ();

fn init(world: &mut World, system_meta: &mut SystemMeta, _config: Self::Config) -> Self {
Self(NonSendState::init(world, system_meta, ()))
}

fn default_config() {}
}

impl<'a, T: 'static> SystemParamFetch<'a> for OptionNonSendState<T> {
type Item = Option<NonSend<'a, T>>;

#[inline]
unsafe fn get_param(
state: &'a mut Self,
system_meta: &SystemMeta,
world: &'a World,
change_tick: u32,
) -> Self::Item {
world.validate_non_send_access::<T>();
world
.get_populated_resource_column(state.0.component_id)
.map(|column| NonSend {
value: &*column.get_data_ptr().cast::<T>().as_ptr(),
ticks: column.get_ticks_unchecked(0).clone(),
last_change_tick: system_meta.last_change_tick,
change_tick,
})
}
}

/// The [`SystemParamState`] of [`NonSendMut`].
pub struct NonSendMutState<T> {
component_id: ComponentId,
Expand Down Expand Up @@ -876,6 +920,47 @@ impl<'a, T: 'static> SystemParamFetch<'a> for NonSendMutState<T> {
}
}

/// The [`SystemParamState`] of `Option<NonSendMut<T>>`.
pub struct OptionNonSendMutState<T>(NonSendMutState<T>);

impl<'a, T: 'static> SystemParam for Option<NonSendMut<'a, T>> {
type Fetch = OptionNonSendMutState<T>;
}

unsafe impl<T: 'static> SystemParamState for OptionNonSendMutState<T> {
type Config = ();

fn init(world: &mut World, system_meta: &mut SystemMeta, _config: Self::Config) -> Self {
Self(NonSendMutState::init(world, system_meta, ()))
}

fn default_config() {}
}

impl<'a, T: 'static> SystemParamFetch<'a> for OptionNonSendMutState<T> {
type Item = Option<NonSendMut<'a, T>>;

#[inline]
unsafe fn get_param(
state: &'a mut Self,
system_meta: &SystemMeta,
world: &'a World,
change_tick: u32,
) -> Self::Item {
world.validate_non_send_access::<T>();
world
.get_populated_resource_column(state.0.component_id)
.map(|column| NonSendMut {
value: &mut *column.get_data_ptr().cast::<T>().as_ptr(),
ticks: Ticks {
component_ticks: &mut *column.get_ticks_mut_ptr_unchecked(0),
last_change_tick: system_meta.last_change_tick,
change_tick,
},
})
}
}

impl<'a> SystemParam for &'a Archetypes {
type Fetch = ArchetypesState;
}
Expand Down

0 comments on commit f8af599

Please sign in to comment.