Skip to content

Commit

Permalink
impl SystemParam for Option<Res<T>> / Option<ResMut<T>> (bevyengine#1494
Browse files Browse the repository at this point in the history
)

This allows users to write systems that do not panic if a resource does not exist at runtime (such as if it has not been inserted yet).

This is a copy-paste of the impls for `Res` and `ResMut`, with an extra check to see if the resource exists.

There might be a cleaner way to do it than this check. I don't know.
  • Loading branch information
inodentry committed Mar 8, 2021
1 parent d9b8b3e commit 13aef05
Showing 1 changed file with 72 additions and 0 deletions.
72 changes: 72 additions & 0 deletions crates/bevy_ecs/src/system/system_param.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,11 @@ pub struct QuerySetState<T>(T);

impl_query_set!();

/// Shared borrow of a Resource
///
/// When used as a system parameter, panics if resource does not exist.
///
/// Use `Option<Res<T>>` if the resource might not always exist.
pub struct Res<'w, T> {
value: &'w T,
flags: ComponentFlags,
Expand Down Expand Up @@ -235,6 +240,42 @@ impl<'a, T: Component> SystemParamFetch<'a> for ResState<T> {
}
}

pub struct OptionResState<T>(ResState<T>);

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

unsafe impl<T: Component> SystemParamState for OptionResState<T> {
type Config = ();
fn init(world: &mut World, system_state: &mut SystemState, _config: Self::Config) -> Self {
Self(ResState::init(world, system_state, ()))
}
}

impl<'a, T: Component> SystemParamFetch<'a> for OptionResState<T> {
type Item = Option<Res<'a, T>>;

#[inline]
unsafe fn get_param(
state: &'a mut Self,
_system_state: &'a SystemState,
world: &'a World,
) -> Self::Item {
world
.get_populated_resource_column(state.0.component_id)
.map(|column| Res {
value: &*column.get_ptr().as_ptr().cast::<T>(),
flags: *column.get_flags_mut_ptr(),
})
}
}

/// Unique borrow of a Resource
///
/// When used as a system parameter, panics if resource does not exist.
///
/// Use `Option<ResMut<T>>` if the resource might not always exist.
pub struct ResMut<'w, T> {
value: &'w mut T,
flags: &'w mut ComponentFlags,
Expand Down Expand Up @@ -334,6 +375,37 @@ impl<'a, T: Component> SystemParamFetch<'a> for ResMutState<T> {
}
}

pub struct OptionResMutState<T>(ResMutState<T>);

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

unsafe impl<T: Component> SystemParamState for OptionResMutState<T> {
type Config = ();
fn init(world: &mut World, system_state: &mut SystemState, _config: Self::Config) -> Self {
Self(ResMutState::init(world, system_state, ()))
}
}

impl<'a, T: Component> SystemParamFetch<'a> for OptionResMutState<T> {
type Item = Option<ResMut<'a, T>>;

#[inline]
unsafe fn get_param(
state: &'a mut Self,
_system_state: &'a SystemState,
world: &'a World,
) -> Self::Item {
world
.get_resource_unchecked_mut_with_id(state.0.component_id)
.map(|value| ResMut {
value: value.value,
flags: value.flags,
})
}
}

impl<'a> SystemParam for Commands<'a> {
type Fetch = CommandQueue;
}
Expand Down

0 comments on commit 13aef05

Please sign in to comment.