Skip to content

Commit 557ab98

Browse files
Make get_resource (and friends) infallible (#4047)
# Objective - In the large majority of cases, users were calling `.unwrap()` immediately after `.get_resource`. - Attempting to add more helpful error messages here resulted in endless manual boilerplate (see #3899 and the linked PRs). ## Solution - Add an infallible variant named `.resource` and so on. - Use these infallible variants over `.get_resource().unwrap()` across the code base. ## Notes I did not provide equivalent methods on `WorldCell`, in favor of removing it entirely in #3939. ## Migration Guide Infallible variants of `.get_resource` have been added that implicitly panic, rather than needing to be unwrapped. Replace `world.get_resource::<Foo>().unwrap()` with `world.resource::<Foo>()`. ## Impact - `.unwrap` search results before: 1084 - `.unwrap` search results after: 942 - internal `unwrap_or_else` calls added: 4 - trivial unwrap calls removed from tests and code: 146 - uses of the new `try_get_resource` API: 11 - percentage of the time the unwrapping API was used internally: 93%
1 parent 44bf66e commit 557ab98

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+277
-276
lines changed

crates/bevy_app/src/app.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -839,10 +839,7 @@ impl App {
839839
#[cfg(feature = "bevy_reflect")]
840840
pub fn register_type<T: bevy_reflect::GetTypeRegistration>(&mut self) -> &mut Self {
841841
{
842-
let registry = self
843-
.world
844-
.get_resource_mut::<bevy_reflect::TypeRegistryArc>()
845-
.unwrap();
842+
let registry = self.world.resource_mut::<bevy_reflect::TypeRegistryArc>();
846843
registry.write().register::<T>();
847844
}
848845
self

crates/bevy_asset/src/asset_server.rs

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -794,24 +794,18 @@ mod test {
794794
app.add_system(update_asset_storage_system::<PngAsset>.after(FreeUnusedAssets));
795795

796796
fn load_asset(path: AssetPath, world: &World) -> HandleUntyped {
797-
let asset_server = world.get_resource::<AssetServer>().unwrap();
797+
let asset_server = world.resource::<AssetServer>();
798798
let id = futures_lite::future::block_on(asset_server.load_async(path.clone(), true))
799799
.unwrap();
800800
asset_server.get_handle_untyped(id)
801801
}
802802

803803
fn get_asset(id: impl Into<HandleId>, world: &World) -> Option<&PngAsset> {
804-
world
805-
.get_resource::<Assets<PngAsset>>()
806-
.unwrap()
807-
.get(id.into())
804+
world.resource::<Assets<PngAsset>>().get(id.into())
808805
}
809806

810807
fn get_load_state(id: impl Into<HandleId>, world: &World) -> LoadState {
811-
world
812-
.get_resource::<AssetServer>()
813-
.unwrap()
814-
.get_load_state(id.into())
808+
world.resource::<AssetServer>().get_load_state(id.into())
815809
}
816810

817811
// ---

crates/bevy_asset/src/assets.rs

Lines changed: 9 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ impl AddAsset for App {
287287
return self;
288288
}
289289
let assets = {
290-
let asset_server = self.world.get_resource::<AssetServer>().unwrap();
290+
let asset_server = self.world.resource::<AssetServer>();
291291
asset_server.register_asset_type::<T>()
292292
};
293293

@@ -307,8 +307,7 @@ impl AddAsset for App {
307307
self.add_system(crate::debug_asset_server::sync_debug_assets::<T>);
308308
let mut app = self
309309
.world
310-
.get_non_send_resource_mut::<crate::debug_asset_server::DebugAssetApp>()
311-
.unwrap();
310+
.non_send_resource_mut::<crate::debug_asset_server::DebugAssetApp>();
312311
app.add_asset::<T>()
313312
.init_resource::<crate::debug_asset_server::HandleMap<T>>();
314313
}
@@ -331,8 +330,7 @@ impl AddAsset for App {
331330
{
332331
let mut app = self
333332
.world
334-
.get_non_send_resource_mut::<crate::debug_asset_server::DebugAssetApp>()
335-
.unwrap();
333+
.non_send_resource_mut::<crate::debug_asset_server::DebugAssetApp>();
336334
app.init_asset_loader::<T>();
337335
}
338336
self
@@ -342,10 +340,7 @@ impl AddAsset for App {
342340
where
343341
T: AssetLoader,
344342
{
345-
self.world
346-
.get_resource_mut::<AssetServer>()
347-
.expect("AssetServer does not exist. Consider adding it as a resource.")
348-
.add_loader(loader);
343+
self.world.resource_mut::<AssetServer>().add_loader(loader);
349344
self
350345
}
351346
}
@@ -357,8 +352,7 @@ macro_rules! load_internal_asset {
357352
{
358353
let mut debug_app = $app
359354
.world
360-
.get_non_send_resource_mut::<bevy_asset::debug_asset_server::DebugAssetApp>()
361-
.unwrap();
355+
.non_send_resource_mut::<bevy_asset::debug_asset_server::DebugAssetApp>();
362356
bevy_asset::debug_asset_server::register_handle_with_loader(
363357
$loader,
364358
&mut debug_app,
@@ -367,10 +361,7 @@ macro_rules! load_internal_asset {
367361
$path_str,
368362
);
369363
}
370-
let mut assets = $app
371-
.world
372-
.get_resource_mut::<bevy_asset::Assets<_>>()
373-
.unwrap();
364+
let mut assets = $app.world.resource_mut::<bevy_asset::Assets<_>>();
374365
assets.set_untracked($handle, ($loader)(include_str!($path_str)));
375366
}};
376367
}
@@ -379,10 +370,7 @@ macro_rules! load_internal_asset {
379370
#[macro_export]
380371
macro_rules! load_internal_asset {
381372
($app: ident, $handle: ident, $path_str: expr, $loader: expr) => {{
382-
let mut assets = $app
383-
.world
384-
.get_resource_mut::<bevy_asset::Assets<_>>()
385-
.unwrap();
373+
let mut assets = $app.world.resource_mut::<bevy_asset::Assets<_>>();
386374
assets.set_untracked($handle, ($loader)(include_str!($path_str)));
387375
}};
388376
}
@@ -402,10 +390,10 @@ mod tests {
402390
app.add_plugin(bevy_core::CorePlugin)
403391
.add_plugin(crate::AssetPlugin);
404392
app.add_asset::<MyAsset>();
405-
let mut assets_before = app.world.get_resource_mut::<Assets<MyAsset>>().unwrap();
393+
let mut assets_before = app.world.resource_mut::<Assets<MyAsset>>();
406394
let handle = assets_before.add(MyAsset);
407395
app.add_asset::<MyAsset>(); // Ensure this doesn't overwrite the Asset
408-
let assets_after = app.world.get_resource_mut::<Assets<MyAsset>>().unwrap();
396+
let assets_after = app.world.resource_mut::<Assets<MyAsset>>();
409397
assert!(assets_after.get(handle).is_some());
410398
}
411399
}

crates/bevy_asset/src/lib.rs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -81,13 +81,8 @@ pub fn create_platform_default_asset_io(app: &mut App) -> Box<dyn AssetIo> {
8181

8282
impl Plugin for AssetPlugin {
8383
fn build(&self, app: &mut App) {
84-
if app.world.get_resource::<AssetServer>().is_none() {
85-
let task_pool = app
86-
.world
87-
.get_resource::<IoTaskPool>()
88-
.expect("`IoTaskPool` resource not found.")
89-
.0
90-
.clone();
84+
if !app.world.contains_resource::<AssetServer>() {
85+
let task_pool = app.world.resource::<IoTaskPool>().0.clone();
9186

9287
let source = create_platform_default_asset_io(app);
9388

crates/bevy_core/src/time/fixed_timestep.rs

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ impl System for FixedTimestep {
209209
)));
210210
self.internal_system.initialize(world);
211211
if let Some(ref label) = self.state.label {
212-
let mut fixed_timesteps = world.get_resource_mut::<FixedTimesteps>().unwrap();
212+
let mut fixed_timesteps = world.resource_mut::<FixedTimesteps>();
213213
fixed_timesteps.fixed_timesteps.insert(
214214
label.clone(),
215215
FixedTimestepState {
@@ -257,25 +257,25 @@ mod test {
257257
// if time does not progress, the step does not run
258258
schedule.run(&mut world);
259259
schedule.run(&mut world);
260-
assert_eq!(0, *world.get_resource::<Count>().unwrap());
260+
assert_eq!(0, *world.resource::<Count>());
261261
assert_eq!(0., get_accumulator_deciseconds(&world));
262262

263263
// let's progress less than one step
264264
advance_time(&mut world, instance, 0.4);
265265
schedule.run(&mut world);
266-
assert_eq!(0, *world.get_resource::<Count>().unwrap());
266+
assert_eq!(0, *world.resource::<Count>());
267267
assert_eq!(4., get_accumulator_deciseconds(&world));
268268

269269
// finish the first step with 0.1s above the step length
270270
advance_time(&mut world, instance, 0.6);
271271
schedule.run(&mut world);
272-
assert_eq!(1, *world.get_resource::<Count>().unwrap());
272+
assert_eq!(1, *world.resource::<Count>());
273273
assert_eq!(1., get_accumulator_deciseconds(&world));
274274

275275
// runs multiple times if the delta is multiple step lengths
276276
advance_time(&mut world, instance, 1.7);
277277
schedule.run(&mut world);
278-
assert_eq!(3, *world.get_resource::<Count>().unwrap());
278+
assert_eq!(3, *world.resource::<Count>());
279279
assert_eq!(2., get_accumulator_deciseconds(&world));
280280
}
281281

@@ -285,15 +285,13 @@ mod test {
285285

286286
fn advance_time(world: &mut World, instance: Instant, seconds: f32) {
287287
world
288-
.get_resource_mut::<Time>()
289-
.unwrap()
288+
.resource_mut::<Time>()
290289
.update_with_instant(instance.add(Duration::from_secs_f32(seconds)));
291290
}
292291

293292
fn get_accumulator_deciseconds(world: &World) -> f64 {
294293
world
295-
.get_resource::<FixedTimesteps>()
296-
.unwrap()
294+
.resource::<FixedTimesteps>()
297295
.get(LABEL)
298296
.unwrap()
299297
.accumulator

crates/bevy_core_pipeline/src/clear_pass.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@ impl Node for ClearPassNode {
5050
world: &World,
5151
) -> Result<(), NodeRunError> {
5252
let mut cleared_targets = HashSet::new();
53-
let clear_color = world.get_resource::<ClearColor>().unwrap();
54-
let render_target_clear_colors = world.get_resource::<RenderTargetClearColors>().unwrap();
53+
let clear_color = world.resource::<ClearColor>();
54+
let render_target_clear_colors = world.resource::<RenderTargetClearColors>();
5555

5656
// This gets all ViewTargets and ViewDepthTextures and clears its attachments
5757
// TODO: This has the potential to clear the same target multiple times, if there
@@ -89,8 +89,8 @@ impl Node for ClearPassNode {
8989
// TODO: This is a hack to ensure we don't call present() on frames without any work,
9090
// which will cause panics. The real fix here is to clear "render targets" directly
9191
// instead of "views". This should be removed once full RenderTargets are implemented.
92-
let windows = world.get_resource::<ExtractedWindows>().unwrap();
93-
let images = world.get_resource::<RenderAssets<Image>>().unwrap();
92+
let windows = world.resource::<ExtractedWindows>();
93+
let images = world.resource::<RenderAssets<Image>>();
9494
for target in render_target_clear_colors.colors.keys().cloned().chain(
9595
windows
9696
.values()

crates/bevy_core_pipeline/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ impl Plugin for CorePipelinePlugin {
145145
let clear_pass_node = ClearPassNode::new(&mut render_app.world);
146146
let pass_node_2d = MainPass2dNode::new(&mut render_app.world);
147147
let pass_node_3d = MainPass3dNode::new(&mut render_app.world);
148-
let mut graph = render_app.world.get_resource_mut::<RenderGraph>().unwrap();
148+
let mut graph = render_app.world.resource_mut::<RenderGraph>();
149149

150150
let mut draw_2d_graph = RenderGraph::default();
151151
draw_2d_graph.add_node(draw_2d_graph::node::MAIN_PASS, pass_node_2d);

crates/bevy_core_pipeline/src/main_pass_2d.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,7 @@ impl Node for MainPass2dNode {
5353
depth_stencil_attachment: None,
5454
};
5555

56-
let draw_functions = world
57-
.get_resource::<DrawFunctions<Transparent2d>>()
58-
.unwrap();
56+
let draw_functions = world.resource::<DrawFunctions<Transparent2d>>();
5957

6058
let render_pass = render_context
6159
.command_encoder

crates/bevy_core_pipeline/src/main_pass_3d.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ impl Node for MainPass3dNode {
7575
}),
7676
};
7777

78-
let draw_functions = world.get_resource::<DrawFunctions<Opaque3d>>().unwrap();
78+
let draw_functions = world.resource::<DrawFunctions<Opaque3d>>();
7979

8080
let render_pass = render_context
8181
.command_encoder
@@ -109,7 +109,7 @@ impl Node for MainPass3dNode {
109109
}),
110110
};
111111

112-
let draw_functions = world.get_resource::<DrawFunctions<AlphaMask3d>>().unwrap();
112+
let draw_functions = world.resource::<DrawFunctions<AlphaMask3d>>();
113113

114114
let render_pass = render_context
115115
.command_encoder
@@ -145,9 +145,7 @@ impl Node for MainPass3dNode {
145145
}),
146146
};
147147

148-
let draw_functions = world
149-
.get_resource::<DrawFunctions<Transparent3d>>()
150-
.unwrap();
148+
let draw_functions = world.resource::<DrawFunctions<Transparent3d>>();
151149

152150
let render_pass = render_context
153151
.command_encoder

crates/bevy_core_pipeline/src/main_pass_driver.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ impl Node for MainPassDriverNode {
1414
_render_context: &mut RenderContext,
1515
world: &World,
1616
) -> Result<(), NodeRunError> {
17-
let extracted_cameras = world.get_resource::<ExtractedCameraNames>().unwrap();
17+
let extracted_cameras = world.resource::<ExtractedCameraNames>();
1818
if let Some(camera_2d) = extracted_cameras.entities.get(CameraPlugin::CAMERA_2D) {
1919
graph.run_sub_graph(
2020
crate::draw_2d_graph::NAME,

crates/bevy_ecs/src/lib.rs

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1010,29 +1010,26 @@ mod tests {
10101010
.get_archetype_component_id(resource_id)
10111011
.unwrap();
10121012

1013-
assert_eq!(*world.get_resource::<i32>().expect("resource exists"), 123);
1013+
assert_eq!(*world.resource::<i32>(), 123);
10141014
assert!(world.contains_resource::<i32>());
10151015
assert!(world.is_resource_added::<i32>());
10161016
assert!(world.is_resource_changed::<i32>());
10171017

10181018
world.insert_resource(456u64);
1019-
assert_eq!(
1020-
*world.get_resource::<u64>().expect("resource exists"),
1021-
456u64
1022-
);
1019+
assert_eq!(*world.resource::<u64>(), 456u64);
10231020

10241021
world.insert_resource(789u64);
1025-
assert_eq!(*world.get_resource::<u64>().expect("resource exists"), 789);
1022+
assert_eq!(*world.resource::<u64>(), 789);
10261023

10271024
{
1028-
let mut value = world.get_resource_mut::<u64>().expect("resource exists");
1025+
let mut value = world.resource_mut::<u64>();
10291026
assert_eq!(*value, 789);
10301027
*value = 10;
10311028
}
10321029

10331030
assert_eq!(
1034-
world.get_resource::<u64>(),
1035-
Some(&10),
1031+
world.resource::<u64>(),
1032+
&10,
10361033
"resource changes are preserved"
10371034
);
10381035

@@ -1183,8 +1180,8 @@ mod tests {
11831180
let mut world = World::default();
11841181
world.insert_non_send_resource(123i32);
11851182
world.insert_non_send_resource(456i64);
1186-
assert_eq!(*world.get_non_send_resource::<i32>().unwrap(), 123);
1187-
assert_eq!(*world.get_non_send_resource_mut::<i64>().unwrap(), 456);
1183+
assert_eq!(*world.non_send_resource::<i32>(), 123);
1184+
assert_eq!(*world.non_send_resource_mut::<i64>(), 456);
11881185
}
11891186

11901187
#[test]
@@ -1193,7 +1190,7 @@ mod tests {
11931190
let mut world = World::default();
11941191
world.insert_non_send_resource(0i32);
11951192
std::thread::spawn(move || {
1196-
let _ = world.get_non_send_resource_mut::<i32>();
1193+
let _ = world.non_send_resource_mut::<i32>();
11971194
})
11981195
.join()
11991196
.unwrap();
@@ -1323,7 +1320,7 @@ mod tests {
13231320
*value += 1;
13241321
assert!(!world.contains_resource::<i32>());
13251322
});
1326-
assert_eq!(*world.get_resource::<i32>().unwrap(), 1);
1323+
assert_eq!(*world.resource::<i32>(), 1);
13271324
}
13281325

13291326
#[test]
@@ -1389,7 +1386,7 @@ mod tests {
13891386
"world should not have any entities"
13901387
);
13911388
assert_eq!(
1392-
*world.get_resource::<i32>().unwrap(),
1389+
*world.resource::<i32>(),
13931390
0,
13941391
"world should still contain resources"
13951392
);

crates/bevy_ecs/src/schedule/executor_parallel.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -350,11 +350,7 @@ mod tests {
350350

351351
fn receive_events(world: &World) -> Vec<SchedulingEvent> {
352352
let mut events = Vec::new();
353-
while let Ok(event) = world
354-
.get_resource::<Receiver<SchedulingEvent>>()
355-
.unwrap()
356-
.try_recv()
357-
{
353+
while let Ok(event) = world.resource::<Receiver<SchedulingEvent>>().try_recv() {
358354
events.push(event);
359355
}
360356
events

0 commit comments

Comments
 (0)