diff --git a/framework_crates/bones_ecs/src/system.rs b/framework_crates/bones_ecs/src/system.rs index 4d54353df6..64f81653d6 100644 --- a/framework_crates/bones_ecs/src/system.rs +++ b/framework_crates/bones_ecs/src/system.rs @@ -126,7 +126,7 @@ pub struct In(pub T); /// [`SystemParam`] for getting read access to a resource. /// -/// Use [`Res`] if you want to automatically initialize the resource. +/// Use [`ResInit`] if you want to automatically initialize the resource. pub struct Res<'a, T: HasSchema>(Ref<'a, T>); impl<'a, T: HasSchema> std::ops::Deref for Res<'a, T> { type Target = T; @@ -203,6 +203,21 @@ impl<'a, T: HasSchema> SystemParam for Res<'a, T> { } } +impl<'a, T: HasSchema> SystemParam for Option> { + type State = Option>; + type Param<'p> = Option>; + + fn initialize(_world: &mut World) {} + + fn get_state(world: &World) -> Self::State { + world.resources.get_cell::() + } + + fn borrow<'s>(_world: &'s World, state: &'s mut Self::State) -> Self::Param<'s> { + state.as_ref().map(|state| Res(state.borrow())) + } +} + impl<'a, T: HasSchema + FromWorld> SystemParam for ResInit<'a, T> { type State = AtomicResource; type Param<'p> = ResInit<'p, T>; @@ -245,6 +260,21 @@ impl<'a, T: HasSchema> SystemParam for ResMut<'a, T> { } } +impl<'a, T: HasSchema> SystemParam for Option> { + type State = Option>; + type Param<'p> = Option>; + + fn initialize(_world: &mut World) {} + + fn get_state(world: &World) -> Self::State { + world.resources.get_cell::() + } + + fn borrow<'s>(_world: &'s World, state: &'s mut Self::State) -> Self::Param<'s> { + state.as_mut().map(|state| ResMut(state.borrow_mut())) + } +} + impl<'a, T: HasSchema + FromWorld> SystemParam for ResMutInit<'a, T> { type State = AtomicResource; type Param<'p> = ResMutInit<'p, T>; @@ -476,6 +506,26 @@ mod tests { fn sys(_var1: Res) {} fn send(_t: T) {} + #[test] + fn optional_resource() { + fn access_resource( + a: Option>, + b: Option>, + c: Option>, + d: Option>, + ) { + assert!(a.as_deref() == None); + assert!(b.as_deref() == Some(&1)); + assert!(c.as_deref() == None); + assert!(d.as_deref() == Some(&mut 2)); + } + + let mut world = World::new(); + world.insert_resource(1u16); + world.insert_resource(2u64); + world.run_system(access_resource, ()); + } + #[test] fn in_and_out() { fn mul_by_res(n: In, r: Res) -> usize {