Skip to content

Commit

Permalink
Add infallible resource getters for WorldCell (#4104)
Browse files Browse the repository at this point in the history
# Objective

- Eliminate all `worldcell.get_resource().unwrap()` cases.
- Provide helpful messages on panic.

## Solution

- Adds infallible resource getters to `WorldCell`, mirroring `World`.
  • Loading branch information
aevyrie committed Apr 25, 2022
1 parent 989fb8a commit 4aa5605
Show file tree
Hide file tree
Showing 8 changed files with 140 additions and 74 deletions.
112 changes: 96 additions & 16 deletions crates/bevy_ecs/src/world/world_cell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ impl<'w> WorldCell<'w> {
}
}

/// Gets a reference to the resource of the given type
pub fn get_resource<T: Resource>(&self) -> Option<WorldBorrow<'_, T>> {
let component_id = self.world.components.get_resource_id(TypeId::of::<T>())?;
let resource_archetype = self.world.archetypes.resource();
Expand All @@ -192,6 +193,26 @@ impl<'w> WorldCell<'w> {
))
}

/// Gets a reference to the resource of the given type
///
/// # Panics
///
/// Panics if the resource does not exist. Use [`get_resource`](WorldCell::get_resource) instead
/// if you want to handle this case.
pub fn resource<T: Resource>(&self) -> WorldBorrow<'_, T> {
match self.get_resource() {
Some(x) => x,
None => panic!(
"Requested resource {} does not exist in the `World`.
Did you forget to add it using `app.add_resource` / `app.init_resource`?
Resources are also implicitly added via `app.add_event`,
and can be added by plugins.",
std::any::type_name::<T>()
),
}
}

/// Gets a mutable reference to the resource of the given type
pub fn get_resource_mut<T: Resource>(&self) -> Option<WorldBorrowMut<'_, T>> {
let component_id = self.world.components.get_resource_id(TypeId::of::<T>())?;
let resource_archetype = self.world.archetypes.resource();
Expand All @@ -207,7 +228,27 @@ impl<'w> WorldCell<'w> {
))
}

pub fn get_non_send<T: 'static>(&self) -> Option<WorldBorrow<'_, T>> {
/// Gets a mutable reference to the resource of the given type
///
/// # Panics
///
/// Panics if the resource does not exist. Use [`get_resource_mut`](WorldCell::get_resource_mut)
/// instead if you want to handle this case.
pub fn resource_mut<T: Resource>(&self) -> WorldBorrowMut<'_, T> {
match self.get_resource_mut() {
Some(x) => x,
None => panic!(
"Requested resource {} does not exist in the `World`.
Did you forget to add it using `app.add_resource` / `app.init_resource`?
Resources are also implicitly added via `app.add_event`,
and can be added by plugins.",
std::any::type_name::<T>()
),
}
}

/// Gets an immutable reference to the non-send resource of the given type, if it exists.
pub fn get_non_send_resource<T: 'static>(&self) -> Option<WorldBorrow<'_, T>> {
let component_id = self.world.components.get_resource_id(TypeId::of::<T>())?;
let resource_archetype = self.world.archetypes.resource();
let archetype_component_id = resource_archetype.get_archetype_component_id(component_id)?;
Expand All @@ -219,7 +260,27 @@ impl<'w> WorldCell<'w> {
))
}

pub fn get_non_send_mut<T: 'static>(&self) -> Option<WorldBorrowMut<'_, T>> {
/// Gets an immutable reference to the non-send resource of the given type, if it exists.
///
/// # Panics
///
/// Panics if the resource does not exist. Use
/// [`get_non_send_resource`](WorldCell::get_non_send_resource) instead if you want to handle
/// this case.
pub fn non_send_resource<T: 'static>(&self) -> WorldBorrow<'_, T> {
match self.get_non_send_resource() {
Some(x) => x,
None => panic!(
"Requested non-send resource {} does not exist in the `World`.
Did you forget to add it using `app.add_non_send_resource` / `app.init_non_send_resource`?
Non-send resources can also be be added by plugins.",
std::any::type_name::<T>()
),
}
}

/// Gets a mutable reference to the non-send resource of the given type, if it exists.
pub fn get_non_send_resource_mut<T: 'static>(&self) -> Option<WorldBorrowMut<'_, T>> {
let component_id = self.world.components.get_resource_id(TypeId::of::<T>())?;
let resource_archetype = self.world.archetypes.resource();
let archetype_component_id = resource_archetype.get_archetype_component_id(component_id)?;
Expand All @@ -233,6 +294,25 @@ impl<'w> WorldCell<'w> {
self.access.clone(),
))
}

/// Gets a mutable reference to the non-send resource of the given type, if it exists.
///
/// # Panics
///
/// Panics if the resource does not exist. Use
/// [`get_non_send_resource_mut`](WorldCell::get_non_send_resource_mut) instead if you want to
/// handle this case.
pub fn non_send_resource_mut<T: 'static>(&self) -> WorldBorrowMut<'_, T> {
match self.get_non_send_resource_mut() {
Some(x) => x,
None => panic!(
"Requested non-send resource {} does not exist in the `World`.
Did you forget to add it using `app.add_non_send_resource` / `app.init_non_send_resource`?
Non-send resources can also be be added by plugins.",
std::any::type_name::<T>()
),
}
}
}

#[cfg(test)]
Expand All @@ -248,28 +328,28 @@ mod tests {
world.insert_resource(1u64);
let cell = world.cell();
{
let mut a = cell.get_resource_mut::<u32>().unwrap();
let mut a = cell.resource_mut::<u32>();
assert_eq!(1, *a);
*a = 2;
}
{
let a = cell.get_resource::<u32>().unwrap();
let a = cell.resource::<u32>();
assert_eq!(2, *a, "ensure access is dropped");

let b = cell.get_resource::<u32>().unwrap();
let b = cell.resource::<u32>();
assert_eq!(
2, *b,
"ensure multiple immutable accesses can occur at the same time"
);
}
{
let a = cell.get_resource_mut::<u32>().unwrap();
let a = cell.resource_mut::<u32>();
assert_eq!(
2, *a,
"ensure both immutable accesses are dropped, enabling a new mutable access"
);

let b = cell.get_resource::<u64>().unwrap();
let b = cell.resource::<u64>();
assert_eq!(
1, *b,
"ensure multiple non-conflicting mutable accesses can occur at the same time"
Expand All @@ -284,7 +364,7 @@ mod tests {
{
let cell = world.cell();
{
let mut a = cell.get_resource_mut::<u32>().unwrap();
let mut a = cell.resource_mut::<u32>();
assert_eq!(1, *a);
*a = 2;
}
Expand Down Expand Up @@ -315,8 +395,8 @@ mod tests {
let mut world = World::default();
world.insert_resource(1u32);
let cell = world.cell();
let _value_a = cell.get_resource_mut::<u32>().unwrap();
let _value_b = cell.get_resource_mut::<u32>().unwrap();
let _value_a = cell.resource_mut::<u32>();
let _value_b = cell.resource_mut::<u32>();
}

#[test]
Expand All @@ -325,8 +405,8 @@ mod tests {
let mut world = World::default();
world.insert_resource(1u32);
let cell = world.cell();
let _value_a = cell.get_resource::<u32>().unwrap();
let _value_b = cell.get_resource_mut::<u32>().unwrap();
let _value_a = cell.resource::<u32>();
let _value_b = cell.resource_mut::<u32>();
}

#[test]
Expand All @@ -335,8 +415,8 @@ mod tests {
let mut world = World::default();
world.insert_resource(1u32);
let cell = world.cell();
let _value_a = cell.get_resource_mut::<u32>().unwrap();
let _value_b = cell.get_resource::<u32>().unwrap();
let _value_a = cell.resource_mut::<u32>();
let _value_b = cell.resource::<u32>();
}

#[test]
Expand All @@ -345,7 +425,7 @@ mod tests {
let mut world = World::default();
world.insert_resource(1u32);
let cell = world.cell();
let _value_a = cell.get_resource_mut::<u32>().unwrap();
let _value_b = cell.get_resource::<u32>().unwrap();
let _value_a = cell.resource_mut::<u32>();
let _value_b = cell.resource::<u32>();
}
}
4 changes: 2 additions & 2 deletions crates/bevy_pbr/src/render/light.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ pub struct ShadowPipeline {
impl FromWorld for ShadowPipeline {
fn from_world(world: &mut World) -> Self {
let world = world.cell();
let render_device = world.get_resource::<RenderDevice>().unwrap();
let render_device = world.resource::<RenderDevice>();

let view_layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
entries: &[
Expand All @@ -255,7 +255,7 @@ impl FromWorld for ShadowPipeline {
label: Some("shadow_view_layout"),
});

let mesh_pipeline = world.get_resource::<MeshPipeline>().unwrap();
let mesh_pipeline = world.resource::<MeshPipeline>();
let skinned_mesh_layout = mesh_pipeline.skinned_mesh_layout.clone();

ShadowPipeline {
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_sprite/src/render/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ pub struct SpritePipeline {
impl FromWorld for SpritePipeline {
fn from_world(world: &mut World) -> Self {
let world = world.cell();
let render_device = world.get_resource::<RenderDevice>().unwrap();
let render_device = world.resource::<RenderDevice>();

let view_layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
entries: &[BindGroupLayoutEntry {
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_ui/src/render/pipeline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ pub struct UiPipeline {
impl FromWorld for UiPipeline {
fn from_world(world: &mut World) -> Self {
let world = world.cell();
let render_device = world.get_resource::<RenderDevice>().unwrap();
let render_device = world.resource::<RenderDevice>();

let view_layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
entries: &[BindGroupLayoutEntry {
Expand Down
Loading

0 comments on commit 4aa5605

Please sign in to comment.