From 2ad5908e58f2145cd45c5c25cfd5462bd5d9634d Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Sun, 2 Mar 2025 14:51:56 -0500 Subject: [PATCH] Make Query::single (and friends) return a Result (#18082) # Objective As discussed in #14275, Bevy is currently too prone to panic, and makes the easy / beginner-friendly way to do a large number of operations just to panic on failure. This is seriously frustrating in library code, but also slows down development, as many of the `Query::single` panics can actually safely be an early return (these panics are often due to a small ordering issue or a change in game state. More critically, in most "finished" products, panics are unacceptable: any unexpected failures should be handled elsewhere. That's where the new With the advent of good system error handling, we can now remove this. Note: I was instrumental in a) introducing this idea in the first place and b) pushing to make the panicking variant the default. The introduction of both `let else` statements in Rust and the fancy system error handling work in 0.16 have changed my mind on the right balance here. ## Solution 1. Make `Query::single` and `Query::single_mut` (and other random related methods) return a `Result`. 2. Handle all of Bevy's internal usage of these APIs. 3. Deprecate `Query::get_single` and friends, since we've moved their functionality to the nice names. 4. Add detailed advice on how to best handle these errors. Generally I like the diff here, although `get_single().unwrap()` in tests is a bit of a downgrade. ## Testing I've done a global search for `.single` to track down any missed deprecated usages. As to whether or not all the migrations were successful, that's what CI is for :) ## Future work ~~Rename `Query::get_single` and friends to `Query::single`!~~ ~~I've opted not to do this in this PR, and smear it across two releases in order to ease the migration. Successive deprecations are much easier to manage than the semantics and types shifting under your feet.~~ Cart has convinced me to change my mind on this; see https://github.com/bevyengine/bevy/pull/18082#discussion_r1974536085. ## Migration guide `Query::single`, `Query::single_mut` and their `QueryState` equivalents now return a `Result`. Generally, you'll want to: 1. Use Bevy 0.16's system error handling to return a `Result` using the `?` operator. 2. Use a `let else Ok(data)` block to early return if it's an expected failure. 3. Use `unwrap()` or `Ok` destructuring inside of tests. The old `Query::get_single` (etc) methods which did this have been deprecated. --- crates/bevy_core_pipeline/src/oit/mod.rs | 2 +- crates/bevy_dev_tools/src/picking_debug.rs | 2 +- .../tests/ui/query_lifetime_safety.rs | 16 +- .../tests/ui/query_lifetime_safety.stderr | 8 +- .../tests/ui/query_to_readonly.rs | 6 +- .../tests/ui/query_transmute_safety.rs | 8 +- crates/bevy_ecs/src/change_detection.rs | 2 +- crates/bevy_ecs/src/query/builder.rs | 14 +- crates/bevy_ecs/src/query/error.rs | 2 +- crates/bevy_ecs/src/query/mod.rs | 8 +- crates/bevy_ecs/src/query/state.rs | 150 ++++++++++++------ crates/bevy_ecs/src/system/query.rs | 140 ++++------------ crates/bevy_ecs/src/system/system_param.rs | 8 +- crates/bevy_ecs/src/world/entity_ref.rs | 30 ++-- crates/bevy_input_focus/src/lib.rs | 2 +- .../src/light_probe/irradiance_volume.rs | 4 +- crates/bevy_picking/src/input.rs | 8 +- crates/bevy_picking/src/pointer.rs | 2 +- crates/bevy_render/src/lib.rs | 2 +- crates/bevy_render/src/sync_world.rs | 2 +- crates/bevy_scene/src/scene_spawner.rs | 8 +- crates/bevy_scene/src/serde.rs | 6 +- crates/bevy_sprite/src/picking_backend.rs | 2 +- crates/bevy_text/src/text2d.rs | 4 +- crates/bevy_ui/src/accessibility.rs | 2 +- crates/bevy_ui/src/layout/mod.rs | 4 +- crates/bevy_ui/src/picking_backend.rs | 2 +- crates/bevy_ui/src/ui_node.rs | 2 +- crates/bevy_winit/src/accessibility.rs | 2 +- crates/bevy_winit/src/state.rs | 4 +- examples/2d/2d_viewport_to_world.rs | 2 +- examples/3d/3d_viewport_to_world.rs | 2 +- examples/3d/generate_custom_mesh.rs | 2 +- examples/3d/tonemapping.rs | 2 +- examples/asset/multi_asset_sync.rs | 2 +- examples/audio/audio_control.rs | 8 +- examples/camera/2d_screen_shake.rs | 2 +- examples/ecs/entity_disabling.rs | 2 +- examples/ecs/observers.rs | 2 +- examples/ecs/parallel_query.rs | 2 +- examples/games/contributors.rs | 2 +- examples/helpers/camera_controller.rs | 2 +- examples/mobile/src/lib.rs | 2 +- examples/stress_tests/bevymark.rs | 4 +- examples/stress_tests/many_cameras_lights.rs | 5 +- examples/stress_tests/many_text2d.rs | 4 +- .../tools/scene_viewer/morph_viewer_plugin.rs | 2 +- examples/window/window_drag_move.rs | 10 +- tests/how_to_test_apps.rs | 22 ++- tests/window/change_window_mode.rs | 2 +- 50 files changed, 263 insertions(+), 270 deletions(-) diff --git a/crates/bevy_core_pipeline/src/oit/mod.rs b/crates/bevy_core_pipeline/src/oit/mod.rs index 63083f5ed7..982be9aa31 100644 --- a/crates/bevy_core_pipeline/src/oit/mod.rs +++ b/crates/bevy_core_pipeline/src/oit/mod.rs @@ -162,7 +162,7 @@ fn configure_depth_texture_usages( } // Find all the render target that potentially uses OIT - let primary_window = p.get_single().ok(); + let primary_window = p.single().ok(); let mut render_target_has_oit = >::default(); for (camera, has_oit) in &cameras { if has_oit { diff --git a/crates/bevy_dev_tools/src/picking_debug.rs b/crates/bevy_dev_tools/src/picking_debug.rs index 37defb5578..f72b70fc88 100644 --- a/crates/bevy_dev_tools/src/picking_debug.rs +++ b/crates/bevy_dev_tools/src/picking_debug.rs @@ -260,7 +260,7 @@ pub fn debug_draw( .map(|(entity, camera)| { ( entity, - camera.target.normalize(primary_window.get_single().ok()), + camera.target.normalize(primary_window.single().ok()), ) }) .filter_map(|(entity, target)| Some(entity).zip(target)) diff --git a/crates/bevy_ecs/compile_fail/tests/ui/query_lifetime_safety.rs b/crates/bevy_ecs/compile_fail/tests/ui/query_lifetime_safety.rs index a8db25b223..62d76bec16 100644 --- a/crates/bevy_ecs/compile_fail/tests/ui/query_lifetime_safety.rs +++ b/crates/bevy_ecs/compile_fail/tests/ui/query_lifetime_safety.rs @@ -27,29 +27,29 @@ fn main() { } { - let data: &Foo = query.single(); - let mut data2: Mut = query.single_mut(); + let data: &Foo = query.single().unwrap(); + let mut data2: Mut = query.single_mut().unwrap(); //~^ E0502 assert_eq!(data, &mut *data2); // oops UB } { - let mut data2: Mut = query.single_mut(); - let data: &Foo = query.single(); + let mut data2: Mut = query.single_mut().unwrap(); + let data: &Foo = query.single().unwrap(); //~^ E0502 assert_eq!(data, &mut *data2); // oops UB } { - let data: &Foo = query.get_single().unwrap(); - let mut data2: Mut = query.get_single_mut().unwrap(); + let data: &Foo = query.single().unwrap(); + let mut data2: Mut = query.single_mut().unwrap(); //~^ E0502 assert_eq!(data, &mut *data2); // oops UB } { - let mut data2: Mut = query.get_single_mut().unwrap(); - let data: &Foo = query.get_single().unwrap(); + let mut data2: Mut = query.single_mut().unwrap(); + let data: &Foo = query.single().unwrap(); //~^ E0502 assert_eq!(data, &mut *data2); // oops UB } diff --git a/crates/bevy_ecs/compile_fail/tests/ui/query_lifetime_safety.stderr b/crates/bevy_ecs/compile_fail/tests/ui/query_lifetime_safety.stderr index c634ea8a70..c39840127a 100644 --- a/crates/bevy_ecs/compile_fail/tests/ui/query_lifetime_safety.stderr +++ b/crates/bevy_ecs/compile_fail/tests/ui/query_lifetime_safety.stderr @@ -45,9 +45,9 @@ error[E0502]: cannot borrow `query` as immutable because it is also borrowed as error[E0502]: cannot borrow `query` as mutable because it is also borrowed as immutable --> tests/ui/query_lifetime_safety.rs:45:39 | -44 | let data: &Foo = query.get_single().unwrap(); +44 | let data: &Foo = query.single().unwrap(); | ----- immutable borrow occurs here -45 | let mut data2: Mut = query.get_single_mut().unwrap(); +45 | let mut data2: Mut = query.single_mut().unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here 46 | 47 | assert_eq!(data, &mut *data2); // oops UB @@ -56,9 +56,9 @@ error[E0502]: cannot borrow `query` as mutable because it is also borrowed as im error[E0502]: cannot borrow `query` as immutable because it is also borrowed as mutable --> tests/ui/query_lifetime_safety.rs:52:30 | -51 | let mut data2: Mut = query.get_single_mut().unwrap(); +51 | let mut data2: Mut = query.single_mut().unwrap(); | ----- mutable borrow occurs here -52 | let data: &Foo = query.get_single().unwrap(); +52 | let data: &Foo = query.single().unwrap(); | ^^^^^ immutable borrow occurs here 53 | 54 | assert_eq!(data, &mut *data2); // oops UB diff --git a/crates/bevy_ecs/compile_fail/tests/ui/query_to_readonly.rs b/crates/bevy_ecs/compile_fail/tests/ui/query_to_readonly.rs index e8c66cff30..923f7894fd 100644 --- a/crates/bevy_ecs/compile_fail/tests/ui/query_to_readonly.rs +++ b/crates/bevy_ecs/compile_fail/tests/ui/query_to_readonly.rs @@ -35,13 +35,13 @@ fn for_loops(mut query: Query<&mut Foo>) { fn single_mut_query(mut query: Query<&mut Foo>) { // this should fail to compile { - let mut mut_foo = query.single_mut(); + let mut mut_foo = query.single_mut().unwrap(); // This solves "temporary value dropped while borrowed" let readonly_query = query.as_readonly(); //~^ E0502 - let ref_foo = readonly_query.single(); + let ref_foo = readonly_query.single().unwrap(); *mut_foo = Foo; @@ -55,7 +55,7 @@ fn single_mut_query(mut query: Query<&mut Foo>) { let ref_foo = readonly_query.single(); - let mut mut_foo = query.single_mut(); + let mut mut_foo = query.single_mut().unwrap(); //~^ E0502 println!("{ref_foo:?}"); diff --git a/crates/bevy_ecs/compile_fail/tests/ui/query_transmute_safety.rs b/crates/bevy_ecs/compile_fail/tests/ui/query_transmute_safety.rs index 489c81d356..7518511fee 100644 --- a/crates/bevy_ecs/compile_fail/tests/ui/query_transmute_safety.rs +++ b/crates/bevy_ecs/compile_fail/tests/ui/query_transmute_safety.rs @@ -22,8 +22,8 @@ fn main() { let mut query_a = lens_a.query(); let mut query_b = lens_b.query(); - let a = query_a.single_mut(); - let b = query_b.single_mut(); // oops 2 mutable references to same Foo + let a = query_a.single_mut().unwrap(); + let b = query_b.single_mut().unwrap(); // oops 2 mutable references to same Foo assert_eq!(*a, *b); } @@ -34,8 +34,8 @@ fn main() { let mut query_b = lens.query(); //~^ E0499 - let a = query_a.single_mut(); - let b = query_b.single_mut(); // oops 2 mutable references to same Foo + let a = query_a.single_mut().unwrap(); + let b = query_b.single_mut().unwrap(); // oops 2 mutable references to same Foo assert_eq!(*a, *b); } } diff --git a/crates/bevy_ecs/src/change_detection.rs b/crates/bevy_ecs/src/change_detection.rs index 0bdecb593b..a0e00fdc15 100644 --- a/crates/bevy_ecs/src/change_detection.rs +++ b/crates/bevy_ecs/src/change_detection.rs @@ -1557,7 +1557,7 @@ mod tests { // Since the world is always ahead, as long as changes can't get older than `u32::MAX` (which we ensure), // the wrapping difference will always be positive, so wraparound doesn't matter. let mut query = world.query::>(); - assert!(query.single(&world).is_changed()); + assert!(query.single(&world).unwrap().is_changed()); } #[test] diff --git a/crates/bevy_ecs/src/query/builder.rs b/crates/bevy_ecs/src/query/builder.rs index 65ad02111c..428f6a63ed 100644 --- a/crates/bevy_ecs/src/query/builder.rs +++ b/crates/bevy_ecs/src/query/builder.rs @@ -33,7 +33,7 @@ use super::{FilteredAccess, QueryData, QueryFilter}; /// .build(); /// /// // Consume the QueryState -/// let (entity, b) = query.single(&world); +/// let (entity, b) = query.single(&world).unwrap(); /// ``` pub struct QueryBuilder<'w, D: QueryData = (), F: QueryFilter = ()> { access: FilteredAccess, @@ -297,13 +297,13 @@ mod tests { .with::() .without::() .build(); - assert_eq!(entity_a, query_a.single(&world)); + assert_eq!(entity_a, query_a.single(&world).unwrap()); let mut query_b = QueryBuilder::::new(&mut world) .with::() .without::() .build(); - assert_eq!(entity_b, query_b.single(&world)); + assert_eq!(entity_b, query_b.single(&world).unwrap()); } #[test] @@ -319,13 +319,13 @@ mod tests { .with_id(component_id_a) .without_id(component_id_c) .build(); - assert_eq!(entity_a, query_a.single(&world)); + assert_eq!(entity_a, query_a.single(&world).unwrap()); let mut query_b = QueryBuilder::::new(&mut world) .with_id(component_id_a) .without_id(component_id_b) .build(); - assert_eq!(entity_b, query_b.single(&world)); + assert_eq!(entity_b, query_b.single(&world).unwrap()); } #[test] @@ -385,7 +385,7 @@ mod tests { .data::<&B>() .build(); - let entity_ref = query.single(&world); + let entity_ref = query.single(&world).unwrap(); assert_eq!(entity, entity_ref.id()); @@ -408,7 +408,7 @@ mod tests { .ref_id(component_id_b) .build(); - let entity_ref = query.single(&world); + let entity_ref = query.single(&world).unwrap(); assert_eq!(entity, entity_ref.id()); diff --git a/crates/bevy_ecs/src/query/error.rs b/crates/bevy_ecs/src/query/error.rs index f1f9ddfe21..4b5544998c 100644 --- a/crates/bevy_ecs/src/query/error.rs +++ b/crates/bevy_ecs/src/query/error.rs @@ -104,7 +104,7 @@ impl<'w> PartialEq for QueryEntityError<'w> { impl<'w> Eq for QueryEntityError<'w> {} /// An error that occurs when evaluating a [`Query`](crate::system::Query) or [`QueryState`](crate::query::QueryState) as a single expected result via -/// [`get_single`](crate::system::Query::get_single) or [`get_single_mut`](crate::system::Query::get_single_mut). +/// [`single`](crate::system::Query::single) or [`single_mut`](crate::system::Query::single_mut). #[derive(Debug, Error)] pub enum QuerySingleError { /// No entity fits the query. diff --git a/crates/bevy_ecs/src/query/mod.rs b/crates/bevy_ecs/src/query/mod.rs index 7f304b7b71..9c8e2323c2 100644 --- a/crates/bevy_ecs/src/query/mod.rs +++ b/crates/bevy_ecs/src/query/mod.rs @@ -763,8 +763,8 @@ mod tests { let _: Option<&Foo> = q.get(&world, e).ok(); let _: Option<&Foo> = q.get_manual(&world, e).ok(); let _: Option<[&Foo; 1]> = q.get_many(&world, [e]).ok(); - let _: Option<&Foo> = q.get_single(&world).ok(); - let _: &Foo = q.single(&world); + let _: Option<&Foo> = q.single(&world).ok(); + let _: &Foo = q.single(&world).unwrap(); // system param let mut q = SystemState::>::new(&mut world); @@ -776,9 +776,9 @@ mod tests { let _: Option<&Foo> = q.get(e).ok(); let _: Option<[&Foo; 1]> = q.get_many([e]).ok(); - let _: Option<&Foo> = q.get_single().ok(); + let _: Option<&Foo> = q.single().ok(); let _: [&Foo; 1] = q.many([e]); - let _: &Foo = q.single(); + let _: &Foo = q.single().unwrap(); } // regression test for https://github.com/bevyengine/bevy/pull/8029 diff --git a/crates/bevy_ecs/src/query/state.rs b/crates/bevy_ecs/src/query/state.rs index 1dfcb922d3..ce58ee9cf4 100644 --- a/crates/bevy_ecs/src/query/state.rs +++ b/crates/bevy_ecs/src/query/state.rs @@ -1597,43 +1597,88 @@ impl QueryState { /// This can only be called for read-only queries, /// see [`single_mut`](Self::single_mut) for write-queries. /// - /// # Panics + /// If the number of query results is not exactly one, a [`QuerySingleError`] is returned + /// instead. /// - /// Panics if the number of query results is not exactly one. Use - /// [`get_single`](Self::get_single) to return a `Result` instead of panicking. - #[track_caller] + /// # Example + /// + /// Sometimes, you might want to handle the error in a specific way, + /// generally by spawning the missing entity. + /// + /// ```rust + /// use bevy_ecs::prelude::*; + /// use bevy_ecs::query::QuerySingleError; + /// + /// #[derive(Component)] + /// struct A(usize); + /// + /// fn my_system(query: Query<&A>, mut commands: Commands) { + /// match query.single() { + /// Ok(a) => (), // Do something with `a` + /// Err(err) => match err { + /// QuerySingleError::NoEntities(_) => { + /// commands.spawn(A(0)); + /// } + /// QuerySingleError::MultipleEntities(_) => panic!("Multiple entities found!"), + /// }, + /// } + /// } + /// ``` + /// + /// However in most cases, this error can simply be handled with a graceful early return. + /// If this is an expected failure mode, you can do this using the `let else` pattern like so: + /// ```rust + /// use bevy_ecs::prelude::*; + /// + /// #[derive(Component)] + /// struct A(usize); + /// + /// fn my_system(query: Query<&A>) { + /// let Ok(a) = query.single() else { + /// return; + /// }; + /// + /// // Do something with `a` + /// } + /// ``` + /// + /// If this is unexpected though, you should probably use the `?` operator + /// in combination with Bevy's error handling apparatus. + /// + /// ```rust + /// use bevy_ecs::prelude::*; + /// + /// #[derive(Component)] + /// struct A(usize); + /// + /// fn my_system(query: Query<&A>) -> Result { + /// let a = query.single()?; + /// + /// // Do something with `a` + /// Ok(()) + /// } + /// ``` + /// + /// This allows you to globally control how errors are handled in your application, + /// by setting up a custom error handler. + /// See the [`bevy_ecs::result`] module docs for more information! + /// Commonly, you might want to panic on an error during development, but log the error and continue + /// execution in production. + /// + /// Simply unwrapping the [`Result`] also works, but should generally be reserved for tests. #[inline] - pub fn single<'w>(&mut self, world: &'w World) -> ROQueryItem<'w, D> { + pub fn single<'w>(&mut self, world: &'w World) -> Result, QuerySingleError> { self.query(world).single_inner() } - /// Returns a single immutable query result when there is exactly one entity matching - /// the query. - /// - /// This can only be called for read-only queries, - /// see [`get_single_mut`](Self::get_single_mut) for write-queries. - /// - /// If the number of query results is not exactly one, a [`QuerySingleError`] is returned - /// instead. + /// A deprecated alias for [`QueryState::single`]. + #[deprecated(since = "0.16.0", note = "Please use `single` instead.")] #[inline] pub fn get_single<'w>( &mut self, world: &'w World, ) -> Result, QuerySingleError> { - self.query(world).get_single_inner() - } - - /// Returns a single mutable query result when there is exactly one entity matching - /// the query. - /// - /// # Panics - /// - /// Panics if the number of query results is not exactly one. Use - /// [`get_single_mut`](Self::get_single_mut) to return a `Result` instead of panicking. - #[track_caller] - #[inline] - pub fn single_mut<'w>(&mut self, world: &'w mut World) -> D::Item<'w> { - self.query_mut(world).single_inner() + self.single(world) } /// Returns a single mutable query result when there is exactly one entity matching @@ -1641,12 +1686,25 @@ impl QueryState { /// /// If the number of query results is not exactly one, a [`QuerySingleError`] is returned /// instead. + /// + /// # Examples + /// + /// Please see [`Query::single`] for advice on handling the error. #[inline] + pub fn single_mut<'w>( + &mut self, + world: &'w mut World, + ) -> Result, QuerySingleError> { + self.query_mut(world).single_inner() + } + + /// A deprecated alias for [`QueryState::single_mut`]. + #[deprecated(since = "0.16.0", note = "Please use `single` instead.")] pub fn get_single_mut<'w>( &mut self, world: &'w mut World, ) -> Result, QuerySingleError> { - self.query_mut(world).get_single_inner() + self.single_mut(world) } /// Returns a query result when there is exactly one entity matching the query. @@ -1659,11 +1717,11 @@ impl QueryState { /// This does not check for mutable query correctness. To be safe, make sure mutable queries /// have unique access to the components they query. #[inline] - pub unsafe fn get_single_unchecked<'w>( + pub unsafe fn single_unchecked<'w>( &mut self, world: UnsafeWorldCell<'w>, ) -> Result, QuerySingleError> { - self.query_unchecked(world).get_single_inner() + self.query_unchecked(world).single_inner() } /// Returns a query result when there is exactly one entity matching the query, @@ -1679,7 +1737,7 @@ impl QueryState { /// This does not validate that `world.id()` matches `self.world_id`. Calling this on a `world` /// with a mismatched [`WorldId`] is unsound. #[inline] - pub unsafe fn get_single_unchecked_manual<'w>( + pub unsafe fn single_unchecked_manual<'w>( &self, world: UnsafeWorldCell<'w>, last_run: Tick, @@ -1689,7 +1747,7 @@ impl QueryState { // - The caller ensured we have the correct access to the world. // - The caller ensured that the world matches. self.query_unchecked_manual_with_ticks(world, last_run, this_run) - .get_single_inner() + .single_inner() } } @@ -1753,7 +1811,7 @@ mod tests { let query_state = world.query::<(&A, &B)>(); let mut new_query_state = query_state.transmute::<&A>(&world); assert_eq!(new_query_state.iter(&world).len(), 1); - let a = new_query_state.single(&world); + let a = new_query_state.single(&world).unwrap(); assert_eq!(a.0, 1); } @@ -1767,7 +1825,7 @@ mod tests { let query_state = world.query_filtered::<(&A, &B), Without>(); let mut new_query_state = query_state.transmute::<&A>(&world); // even though we change the query to not have Without, we do not get the component with C. - let a = new_query_state.single(&world); + let a = new_query_state.single(&world).unwrap(); assert_eq!(a.0, 0); } @@ -1780,7 +1838,7 @@ mod tests { let q = world.query::<()>(); let mut q = q.transmute::(&world); - assert_eq!(q.single(&world), entity); + assert_eq!(q.single(&world).unwrap(), entity); } #[test] @@ -1790,7 +1848,7 @@ mod tests { let q = world.query::<&A>(); let mut new_q = q.transmute::>(&world); - assert!(new_q.single(&world).is_added()); + assert!(new_q.single(&world).unwrap().is_added()); let q = world.query::>(); let _ = q.transmute::<&A>(&world); @@ -1861,7 +1919,7 @@ mod tests { let query_state = world.query::>(); let mut new_query_state = query_state.transmute::<&A>(&world); - let x = new_query_state.single(&world); + let x = new_query_state.single(&world).unwrap(); assert_eq!(x.0, 1234); } @@ -1886,7 +1944,7 @@ mod tests { let mut query = query; // Our result is completely untyped - let entity_ref = query.single(&world); + let entity_ref = query.single(&world).unwrap(); assert_eq!(entity, entity_ref.id()); assert_eq!(0, entity_ref.get::().unwrap().0); @@ -1901,16 +1959,16 @@ mod tests { let mut query = QueryState::<(Entity, &A, Has)>::new(&mut world) .transmute_filtered::<(Entity, Has), Added>(&world); - assert_eq!((entity_a, false), query.single(&world)); + assert_eq!((entity_a, false), query.single(&world).unwrap()); world.clear_trackers(); let entity_b = world.spawn((A(0), B(0))).id(); - assert_eq!((entity_b, true), query.single(&world)); + assert_eq!((entity_b, true), query.single(&world).unwrap()); world.clear_trackers(); - assert!(query.get_single(&world).is_err()); + assert!(query.single(&world).is_err()); } #[test] @@ -1922,15 +1980,15 @@ mod tests { .transmute_filtered::>(&world); let mut change_query = QueryState::<&mut A>::new(&mut world); - assert_eq!(entity_a, detection_query.single(&world)); + assert_eq!(entity_a, detection_query.single(&world).unwrap()); world.clear_trackers(); - assert!(detection_query.get_single(&world).is_err()); + assert!(detection_query.single(&world).is_err()); - change_query.single_mut(&mut world).0 = 1; + change_query.single_mut(&mut world).unwrap().0 = 1; - assert_eq!(entity_a, detection_query.single(&world)); + assert_eq!(entity_a, detection_query.single(&world).unwrap()); } #[test] @@ -2017,7 +2075,7 @@ mod tests { let query_2 = QueryState::<&B, Without>::new(&mut world); let mut new_query: QueryState = query_1.join_filtered(&world, &query_2); - assert_eq!(new_query.single(&world), entity_ab); + assert_eq!(new_query.single(&world).unwrap(), entity_ab); } #[test] diff --git a/crates/bevy_ecs/src/system/query.rs b/crates/bevy_ecs/src/system/query.rs index a0457dc667..fff2a91b2f 100644 --- a/crates/bevy_ecs/src/system/query.rs +++ b/crates/bevy_ecs/src/system/query.rs @@ -270,7 +270,7 @@ use core::{ /// |[`iter_combinations`]\[[`_mut`][`iter_combinations_mut`]]|Returns an iterator over all combinations of a specified number of query items.| /// |[`get`]\[[`_mut`][`get_mut`]]|Returns the query item for the specified entity.| /// |[`many`]\[[`_mut`][`many_mut`]],
[`get_many`]\[[`_mut`][`get_many_mut`]]|Returns the query items for the specified entities.| -/// |[`single`]\[[`_mut`][`single_mut`]],
[`get_single`]\[[`_mut`][`get_single_mut`]]|Returns the query item while verifying that there aren't others.| +/// |[`single`]\[[`_mut`][`single_mut`]],
[`single`]\[[`_mut`][`single_mut`]]|Returns the query item while verifying that there aren't others.| /// /// There are two methods for each type of query operation: immutable and mutable (ending with `_mut`). /// When using immutable methods, the query items returned are of type [`ROQueryItem`], a read-only version of the query item. @@ -307,7 +307,7 @@ use core::{ /// |[`get`]\[[`_mut`][`get_mut`]]|O(1)| /// |([`get_`][`get_many`])[`many`]|O(k)| /// |([`get_`][`get_many_mut`])[`many_mut`]|O(k2)| -/// |[`single`]\[[`_mut`][`single_mut`]],
[`get_single`]\[[`_mut`][`get_single_mut`]]|O(a)| +/// |[`single`]\[[`_mut`][`single_mut`]],
[`single`]\[[`_mut`][`single_mut`]]|O(a)| /// |Archetype based filtering ([`With`], [`Without`], [`Or`])|O(a)| /// |Change detection filtering ([`Added`], [`Changed`])|O(a + n)| /// @@ -351,8 +351,8 @@ use core::{ /// [`get_many`]: Self::get_many /// [`get_many_mut`]: Self::get_many_mut /// [`get_mut`]: Self::get_mut -/// [`get_single`]: Self::get_single -/// [`get_single_mut`]: Self::get_single_mut +/// [`single`]: Self::single +/// [`single_mut`]: Self::single_mut /// [`iter`]: Self::iter /// [`iter_combinations`]: Self::iter_combinations /// [`iter_combinations_mut`]: Self::iter_combinations_mut @@ -947,7 +947,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { /// friends_query: Query<&Friends>, /// mut counter_query: Query<&mut Counter>, /// ) { - /// let friends = friends_query.single(); + /// let friends = friends_query.single().unwrap(); /// for mut counter in counter_query.iter_many_unique_inner(friends) { /// println!("Friend's counter: {:?}", counter.value); /// counter.value += 1; @@ -1706,36 +1706,6 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { unsafe { self.reborrow_unsafe() }.get_inner(entity) } - /// Returns a single read-only query item when there is exactly one entity matching the query. - /// - /// # Panics - /// - /// This method panics if the number of query items is **not** exactly one. - /// - /// # Example - /// - /// ``` - /// # use bevy_ecs::prelude::*; - /// # #[derive(Component)] - /// # struct Player; - /// # #[derive(Component)] - /// # struct Position(f32, f32); - /// fn player_system(query: Query<&Position, With>) { - /// let player_position = query.single(); - /// // do something with player_position - /// } - /// # bevy_ecs::system::assert_is_system(player_system); - /// ``` - /// - /// # See also - /// - /// - [`get_single`](Self::get_single) for the non-panicking version. - /// - [`single_mut`](Self::single_mut) to get the mutable query item. - #[track_caller] - pub fn single(&self) -> ROQueryItem<'_, D> { - self.get_single().unwrap() - } - /// Returns a single read-only query item when there is exactly one entity matching the query. /// /// If the number of query items is not exactly one, a [`QuerySingleError`] is returned instead. @@ -1748,7 +1718,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { /// # #[derive(Component)] /// # struct PlayerScore(i32); /// fn player_scoring_system(query: Query<&PlayerScore>) { - /// match query.get_single() { + /// match query.single() { /// Ok(PlayerScore(score)) => { /// println!("Score: {}", score); /// } @@ -1765,43 +1735,16 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { /// /// # See also /// - /// - [`get_single_mut`](Self::get_single_mut) to get the mutable query item. - /// - [`single`](Self::single) for the panicking version. + /// - [`single_mut`](Self::single_mut) to get the mutable query item. #[inline] - pub fn get_single(&self) -> Result, QuerySingleError> { - self.as_readonly().get_single_inner() + pub fn single(&self) -> Result, QuerySingleError> { + self.as_readonly().single_inner() } - /// Returns a single query item when there is exactly one entity matching the query. - /// - /// # Panics - /// - /// This method panics if the number of query items is **not** exactly one. - /// - /// # Example - /// - /// ``` - /// # use bevy_ecs::prelude::*; - /// # - /// # #[derive(Component)] - /// # struct Player; - /// # #[derive(Component)] - /// # struct Health(u32); - /// # - /// fn regenerate_player_health_system(mut query: Query<&mut Health, With>) { - /// let mut health = query.single_mut(); - /// health.0 += 1; - /// } - /// # bevy_ecs::system::assert_is_system(regenerate_player_health_system); - /// ``` - /// - /// # See also - /// - /// - [`get_single_mut`](Self::get_single_mut) for the non-panicking version. - /// - [`single`](Self::single) to get the read-only query item. - #[track_caller] - pub fn single_mut(&mut self) -> D::Item<'_> { - self.get_single_mut().unwrap() + /// A deprecated alias for [`single`](Self::single). + #[deprecated(note = "Please use `single` instead")] + pub fn get_single(&self) -> Result, QuerySingleError> { + self.single() } /// Returns a single query item when there is exactly one entity matching the query. @@ -1819,7 +1762,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { /// # struct Health(u32); /// # /// fn regenerate_player_health_system(mut query: Query<&mut Health, With>) { - /// let mut health = query.get_single_mut().expect("Error: Could not find a single player."); + /// let mut health = query.single_mut().expect("Error: Could not find a single player."); /// health.0 += 1; /// } /// # bevy_ecs::system::assert_is_system(regenerate_player_health_system); @@ -1827,19 +1770,22 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { /// /// # See also /// - /// - [`get_single`](Self::get_single) to get the read-only query item. - /// - [`single_mut`](Self::single_mut) for the panicking version. + /// - [`single`](Self::single) to get the read-only query item. #[inline] + pub fn single_mut(&mut self) -> Result, QuerySingleError> { + self.reborrow().single_inner() + } + + /// A deprecated alias for [`single_mut`](Self::single_mut). + #[deprecated(note = "Please use `single_mut` instead")] pub fn get_single_mut(&mut self) -> Result, QuerySingleError> { - self.reborrow().get_single_inner() + self.single_mut() } /// Returns a single query item when there is exactly one entity matching the query. /// This consumes the [`Query`] to return results with the actual "inner" world lifetime. /// - /// # Panics - /// - /// This method panics if the number of query items is **not** exactly one. + /// If the number of query items is not exactly one, a [`QuerySingleError`] is returned instead. /// /// # Example /// @@ -1852,7 +1798,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { /// # struct Health(u32); /// # /// fn regenerate_player_health_system(query: Query<&mut Health, With>) { - /// let mut health = query.single_inner(); + /// let mut health = query.single_inner().expect("Error: Could not find a single player."); /// health.0 += 1; /// } /// # bevy_ecs::system::assert_is_system(regenerate_player_health_system); @@ -1860,43 +1806,11 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { /// /// # See also /// - /// - [`get_single_inner`](Self::get_single_inner) for the non-panicking version. /// - [`single`](Self::single) to get the read-only query item. /// - [`single_mut`](Self::single_mut) to get the mutable query item. - #[track_caller] - pub fn single_inner(self) -> D::Item<'w> { - self.get_single_inner().unwrap() - } - - /// Returns a single query item when there is exactly one entity matching the query. - /// This consumes the [`Query`] to return results with the actual "inner" world lifetime. - /// - /// If the number of query items is not exactly one, a [`QuerySingleError`] is returned instead. - /// - /// # Example - /// - /// ``` - /// # use bevy_ecs::prelude::*; - /// # - /// # #[derive(Component)] - /// # struct Player; - /// # #[derive(Component)] - /// # struct Health(u32); - /// # - /// fn regenerate_player_health_system(query: Query<&mut Health, With>) { - /// let mut health = query.get_single_inner().expect("Error: Could not find a single player."); - /// health.0 += 1; - /// } - /// # bevy_ecs::system::assert_is_system(regenerate_player_health_system); - /// ``` - /// - /// # See also - /// - /// - [`get_single`](Self::get_single) to get the read-only query item. - /// - [`get_single_mut`](Self::get_single_mut) to get the mutable query item. /// - [`single_inner`](Self::single_inner) for the panicking version. #[inline] - pub fn get_single_inner(self) -> Result, QuerySingleError> { + pub fn single_inner(self) -> Result, QuerySingleError> { let mut query = self.into_iter(); let first = query.next(); let extra = query.next().is_some(); @@ -2001,7 +1915,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { /// # world.spawn((A(10), B(5))); /// # /// fn reusable_function(lens: &mut QueryLens<&A>) { - /// assert_eq!(lens.query().single().0, 10); + /// assert_eq!(lens.query().single().unwrap().0, 10); /// } /// /// // We can use the function in a system that takes the exact query. @@ -2160,7 +2074,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { /// # world.spawn((A(10), B(5))); /// # /// fn reusable_function(mut lens: QueryLens<&A>) { - /// assert_eq!(lens.query().single().0, 10); + /// assert_eq!(lens.query().single().unwrap().0, 10); /// } /// /// // We can use the function in a system that takes the exact query. diff --git a/crates/bevy_ecs/src/system/system_param.rs b/crates/bevy_ecs/src/system/system_param.rs index 8cf3cfb302..e7ef565e26 100644 --- a/crates/bevy_ecs/src/system/system_param.rs +++ b/crates/bevy_ecs/src/system/system_param.rs @@ -408,7 +408,7 @@ unsafe impl<'a, D: QueryData + 'static, F: QueryFilter + 'static> SystemParam fo state.query_unchecked_manual_with_ticks(world, system_meta.last_run, change_tick) }; let single = query - .get_single_inner() + .single_inner() .expect("The query was expected to contain exactly one matching entity."); Single { item: single, @@ -432,7 +432,7 @@ unsafe impl<'a, D: QueryData + 'static, F: QueryFilter + 'static> SystemParam fo world.change_tick(), ) }; - let is_valid = query.get_single_inner().is_ok(); + let is_valid = query.single_inner().is_ok(); if !is_valid { system_meta.try_warn_param::(); } @@ -474,7 +474,7 @@ unsafe impl<'a, D: QueryData + 'static, F: QueryFilter + 'static> SystemParam let query = unsafe { state.query_unchecked_manual_with_ticks(world, system_meta.last_run, change_tick) }; - match query.get_single_inner() { + match query.single_inner() { Ok(single) => Some(Single { item: single, _filter: PhantomData, @@ -500,7 +500,7 @@ unsafe impl<'a, D: QueryData + 'static, F: QueryFilter + 'static> SystemParam world.change_tick(), ) }; - let result = query.get_single_inner(); + let result = query.single_inner(); let is_valid = !matches!(result, Err(QuerySingleError::MultipleEntities(_))); if !is_valid { system_meta.try_warn_param::(); diff --git a/crates/bevy_ecs/src/world/entity_ref.rs b/crates/bevy_ecs/src/world/entity_ref.rs index b4fe20b3a4..ab4b9dd4de 100644 --- a/crates/bevy_ecs/src/world/entity_ref.rs +++ b/crates/bevy_ecs/src/world/entity_ref.rs @@ -2430,11 +2430,11 @@ impl<'w> EntityWorldMut<'w> { /// let mut entity = world.spawn_empty(); /// entity.entry().or_insert_with(|| Comp(4)); /// # let entity_id = entity.id(); - /// assert_eq!(world.query::<&Comp>().single(&world).0, 4); + /// assert_eq!(world.query::<&Comp>().single(&world).unwrap().0, 4); /// /// # let mut entity = world.get_entity_mut(entity_id).unwrap(); /// entity.entry::().and_modify(|mut c| c.0 += 1); - /// assert_eq!(world.query::<&Comp>().single(&world).0, 5); + /// assert_eq!(world.query::<&Comp>().single(&world).unwrap().0, 5); /// ``` /// /// # Panics @@ -2714,7 +2714,7 @@ impl<'w, 'a, T: Component> Entry<'w, 'a, T> { /// let mut entity = world.spawn(Comp(0)); /// /// entity.entry::().and_modify(|mut c| c.0 += 1); - /// assert_eq!(world.query::<&Comp>().single(&world).0, 1); + /// assert_eq!(world.query::<&Comp>().single(&world).unwrap().0, 1); /// ``` #[inline] pub fn and_modify)>(self, f: F) -> Self { @@ -2773,11 +2773,11 @@ impl<'w, 'a, T: Component> Entry<'w, 'a, T> { /// /// entity.entry().or_insert(Comp(4)); /// # let entity_id = entity.id(); - /// assert_eq!(world.query::<&Comp>().single(&world).0, 4); + /// assert_eq!(world.query::<&Comp>().single(&world).unwrap().0, 4); /// /// # let mut entity = world.get_entity_mut(entity_id).unwrap(); /// entity.entry().or_insert(Comp(15)).into_mut().0 *= 2; - /// assert_eq!(world.query::<&Comp>().single(&world).0, 8); + /// assert_eq!(world.query::<&Comp>().single(&world).unwrap().0, 8); /// ``` #[inline] pub fn or_insert(self, default: T) -> OccupiedEntry<'w, 'a, T> { @@ -2801,7 +2801,7 @@ impl<'w, 'a, T: Component> Entry<'w, 'a, T> { /// let mut entity = world.spawn_empty(); /// /// entity.entry().or_insert_with(|| Comp(4)); - /// assert_eq!(world.query::<&Comp>().single(&world).0, 4); + /// assert_eq!(world.query::<&Comp>().single(&world).unwrap().0, 4); /// ``` #[inline] pub fn or_insert_with T>(self, default: F) -> OccupiedEntry<'w, 'a, T> { @@ -2827,7 +2827,7 @@ impl<'w, 'a, T: Component + Default> Entry<'w, 'a, T> { /// let mut entity = world.spawn_empty(); /// /// entity.entry::().or_default(); - /// assert_eq!(world.query::<&Comp>().single(&world).0, 0); + /// assert_eq!(world.query::<&Comp>().single(&world).unwrap().0, 0); /// ``` #[inline] pub fn or_default(self) -> OccupiedEntry<'w, 'a, T> { @@ -2885,7 +2885,7 @@ impl<'w, 'a, T: Component> OccupiedEntry<'w, 'a, T> { /// o.insert(Comp(10)); /// } /// - /// assert_eq!(world.query::<&Comp>().single(&world).0, 10); + /// assert_eq!(world.query::<&Comp>().single(&world).unwrap().0, 10); /// ``` #[inline] pub fn insert(&mut self, component: T) { @@ -2943,7 +2943,7 @@ impl<'w, 'a, T: Component> OccupiedEntry<'w, 'a, T> { /// o.get_mut().0 += 2 /// } /// - /// assert_eq!(world.query::<&Comp>().single(&world).0, 17); + /// assert_eq!(world.query::<&Comp>().single(&world).unwrap().0, 17); /// ``` #[inline] pub fn get_mut(&mut self) -> Mut<'_, T> { @@ -2972,7 +2972,7 @@ impl<'w, 'a, T: Component> OccupiedEntry<'w, 'a, T> { /// o.into_mut().0 += 10; /// } /// - /// assert_eq!(world.query::<&Comp>().single(&world).0, 15); + /// assert_eq!(world.query::<&Comp>().single(&world).unwrap().0, 15); /// ``` #[inline] pub fn into_mut(self) -> Mut<'a, T> { @@ -3004,7 +3004,7 @@ impl<'w, 'a, T: Component> VacantEntry<'w, 'a, T> { /// v.insert(Comp(10)); /// } /// - /// assert_eq!(world.query::<&Comp>().single(&world).0, 10); + /// assert_eq!(world.query::<&Comp>().single(&world).unwrap().0, 10); /// ``` #[inline] pub fn insert(self, component: T) -> OccupiedEntry<'w, 'a, T> { @@ -3036,7 +3036,7 @@ impl<'w, 'a, T: Component> VacantEntry<'w, 'a, T> { /// .data::<&A>() /// .build(); /// -/// let filtered_entity: FilteredEntityRef = query.single(&mut world); +/// let filtered_entity: FilteredEntityRef = query.single(&mut world).unwrap(); /// let component: &A = filtered_entity.get().unwrap(); /// /// // Here `FilteredEntityRef` is nested in a tuple, so it does not have access to `&A`. @@ -3044,7 +3044,7 @@ impl<'w, 'a, T: Component> VacantEntry<'w, 'a, T> { /// .data::<&A>() /// .build(); /// -/// let (_, filtered_entity) = query.single(&mut world); +/// let (_, filtered_entity) = query.single(&mut world).unwrap(); /// assert!(filtered_entity.get::
().is_none()); /// ``` #[derive(Clone)] @@ -3367,7 +3367,7 @@ unsafe impl TrustedEntityBorrow for FilteredEntityRef<'_> {} /// .data::<&mut A>() /// .build(); /// -/// let mut filtered_entity: FilteredEntityMut = query.single_mut(&mut world); +/// let mut filtered_entity: FilteredEntityMut = query.single_mut(&mut world).unwrap(); /// let component: Mut = filtered_entity.get_mut().unwrap(); /// /// // Here `FilteredEntityMut` is nested in a tuple, so it does not have access to `&mut A`. @@ -3375,7 +3375,7 @@ unsafe impl TrustedEntityBorrow for FilteredEntityRef<'_> {} /// .data::<&mut A>() /// .build(); /// -/// let (_, mut filtered_entity) = query.single_mut(&mut world); +/// let (_, mut filtered_entity) = query.single_mut(&mut world).unwrap(); /// assert!(filtered_entity.get_mut::().is_none()); /// ``` pub struct FilteredEntityMut<'w> { diff --git a/crates/bevy_input_focus/src/lib.rs b/crates/bevy_input_focus/src/lib.rs index ee88635c0b..573ce56d89 100644 --- a/crates/bevy_input_focus/src/lib.rs +++ b/crates/bevy_input_focus/src/lib.rs @@ -226,7 +226,7 @@ pub fn dispatch_focused_input( windows: Query>, mut commands: Commands, ) { - if let Ok(window) = windows.get_single() { + if let Ok(window) = windows.single() { // If an element has keyboard focus, then dispatch the input event to that element. if let Some(focused_entity) = focus.0 { for ev in key_events.read() { diff --git a/crates/bevy_pbr/src/light_probe/irradiance_volume.rs b/crates/bevy_pbr/src/light_probe/irradiance_volume.rs index 246321ff84..c7722eb3db 100644 --- a/crates/bevy_pbr/src/light_probe/irradiance_volume.rs +++ b/crates/bevy_pbr/src/light_probe/irradiance_volume.rs @@ -251,7 +251,7 @@ impl<'a> RenderViewIrradianceVolumeBindGroupEntries<'a> { fallback_image, ) } else { - RenderViewIrradianceVolumeBindGroupEntries::get_single( + RenderViewIrradianceVolumeBindGroupEntries::single( render_view_irradiance_volumes, images, fallback_image, @@ -295,7 +295,7 @@ impl<'a> RenderViewIrradianceVolumeBindGroupEntries<'a> { /// Looks up and returns the bindings for any irradiance volumes visible in /// the view, as well as the sampler. This is the version used when binding /// arrays aren't available on the current platform. - fn get_single( + fn single( render_view_irradiance_volumes: Option<&RenderViewLightProbes>, images: &'a RenderAssets, fallback_image: &'a FallbackImage, diff --git a/crates/bevy_picking/src/input.rs b/crates/bevy_picking/src/input.rs index 02bea5a258..19c0cf24c2 100644 --- a/crates/bevy_picking/src/input.rs +++ b/crates/bevy_picking/src/input.rs @@ -118,7 +118,7 @@ pub fn mouse_pick_events( WindowEvent::CursorMoved(event) => { let location = Location { target: match RenderTarget::Window(WindowRef::Entity(event.window)) - .normalize(primary_window.get_single().ok()) + .normalize(primary_window.single().ok()) { Some(target) => target, None => continue, @@ -138,7 +138,7 @@ pub fn mouse_pick_events( WindowEvent::MouseButtonInput(input) => { let location = Location { target: match RenderTarget::Window(WindowRef::Entity(input.window)) - .normalize(primary_window.get_single().ok()) + .normalize(primary_window.single().ok()) { Some(target) => target, None => continue, @@ -162,7 +162,7 @@ pub fn mouse_pick_events( let location = Location { target: match RenderTarget::Window(WindowRef::Entity(window)) - .normalize(primary_window.get_single().ok()) + .normalize(primary_window.single().ok()) { Some(target) => target, None => continue, @@ -195,7 +195,7 @@ pub fn touch_pick_events( let pointer = PointerId::Touch(touch.id); let location = Location { target: match RenderTarget::Window(WindowRef::Entity(touch.window)) - .normalize(primary_window.get_single().ok()) + .normalize(primary_window.single().ok()) { Some(target) => target, None => continue, diff --git a/crates/bevy_picking/src/pointer.rs b/crates/bevy_picking/src/pointer.rs index dcaaf6060b..1b14a19525 100644 --- a/crates/bevy_picking/src/pointer.rs +++ b/crates/bevy_picking/src/pointer.rs @@ -224,7 +224,7 @@ impl Location { ) -> bool { if camera .target - .normalize(Some(match primary_window.get_single() { + .normalize(Some(match primary_window.single() { Ok(w) => w, Err(_) => return false, })) diff --git a/crates/bevy_render/src/lib.rs b/crates/bevy_render/src/lib.rs index 4a91686dfb..fcb8e62460 100644 --- a/crates/bevy_render/src/lib.rs +++ b/crates/bevy_render/src/lib.rs @@ -317,7 +317,7 @@ impl Plugin for RenderPlugin { let primary_window = app .world_mut() .query_filtered::<&RawHandleWrapperHolder, With>() - .get_single(app.world()) + .single(app.world()) .ok() .cloned(); let settings = render_creation.clone(); diff --git a/crates/bevy_render/src/sync_world.rs b/crates/bevy_render/src/sync_world.rs index 3c9dc57ff8..8d4bb89f5a 100644 --- a/crates/bevy_render/src/sync_world.rs +++ b/crates/bevy_render/src/sync_world.rs @@ -539,7 +539,7 @@ mod tests { // Only one synchronized entity assert!(q.iter(&render_world).count() == 1); - let render_entity = q.get_single(&render_world).unwrap(); + let render_entity = q.single(&render_world).unwrap(); let render_entity_component = main_world.get::(main_entity).unwrap(); assert!(render_entity_component.id() == render_entity); diff --git a/crates/bevy_scene/src/scene_spawner.rs b/crates/bevy_scene/src/scene_spawner.rs index cf8195e676..aa725ccf6b 100644 --- a/crates/bevy_scene/src/scene_spawner.rs +++ b/crates/bevy_scene/src/scene_spawner.rs @@ -588,7 +588,8 @@ mod tests { let (scene_entity, scene_component_a) = app .world_mut() .query::<(Entity, &ComponentA)>() - .single(app.world()); + .single(app.world()) + .unwrap(); assert_eq!(scene_component_a.x, 3.0); assert_eq!(scene_component_a.y, 4.0); assert_eq!( @@ -631,7 +632,10 @@ mod tests { // clone only existing entity let mut scene_spawner = SceneSpawner::default(); - let entity = world.query_filtered::>().single(&world); + let entity = world + .query_filtered::>() + .single(&world) + .unwrap(); let scene = DynamicSceneBuilder::from_world(&world) .extract_entity(entity) .build(); diff --git a/crates/bevy_scene/src/serde.rs b/crates/bevy_scene/src/serde.rs index 8e26863e79..103e48e50a 100644 --- a/crates/bevy_scene/src/serde.rs +++ b/crates/bevy_scene/src/serde.rs @@ -763,12 +763,12 @@ mod tests { let bar_to_foo = dst_world .query_filtered::<&MyEntityRef, Without>() - .get_single(&dst_world) + .single(&dst_world) .cloned() .unwrap(); let foo = dst_world .query_filtered::>() - .get_single(&dst_world) + .single(&dst_world) .unwrap(); assert_eq!(foo, bar_to_foo.0); @@ -793,7 +793,7 @@ mod tests { deserialized_scene .write_to_world(&mut world, &mut EntityHashMap::default()) .unwrap(); - assert_eq!(&qux, world.query::<&Qux>().single(&world)); + assert_eq!(&qux, world.query::<&Qux>().single(&world).unwrap()); } #[test] diff --git a/crates/bevy_sprite/src/picking_backend.rs b/crates/bevy_sprite/src/picking_backend.rs index 332327defa..83e8f0eaae 100644 --- a/crates/bevy_sprite/src/picking_backend.rs +++ b/crates/bevy_sprite/src/picking_backend.rs @@ -115,7 +115,7 @@ fn sprite_picking( -transform.translation().z }); - let primary_window = primary_window.get_single().ok(); + let primary_window = primary_window.single().ok(); for (pointer, location) in pointers.iter().filter_map(|(pointer, pointer_location)| { pointer_location.location().map(|loc| (pointer, loc)) diff --git a/crates/bevy_text/src/text2d.rs b/crates/bevy_text/src/text2d.rs index 952627a6b7..13e9760f29 100644 --- a/crates/bevy_text/src/text2d.rs +++ b/crates/bevy_text/src/text2d.rs @@ -153,7 +153,7 @@ pub fn extract_text2d_sprite( ) { // TODO: Support window-independent scaling: https://github.com/bevyengine/bevy/issues/5621 let scale_factor = windows - .get_single() + .single() .map(|window| window.resolution.scale_factor()) .unwrap_or(1.0); let scaling = GlobalTransform::from_scale(Vec2::splat(scale_factor.recip()).extend(1.)); @@ -256,7 +256,7 @@ pub fn update_text2d_layout( ) { // TODO: Support window-independent scaling: https://github.com/bevyengine/bevy/issues/5621 let scale_factor = windows - .get_single() + .single() .ok() .map(|window| window.resolution.scale_factor()) .or(*last_scale_factor) diff --git a/crates/bevy_ui/src/accessibility.rs b/crates/bevy_ui/src/accessibility.rs index 95686530ce..aca16a53a7 100644 --- a/crates/bevy_ui/src/accessibility.rs +++ b/crates/bevy_ui/src/accessibility.rs @@ -43,7 +43,7 @@ fn calc_bounds( Ref, )>, ) { - if let Ok((camera, camera_transform)) = camera.get_single() { + if let Ok((camera, camera_transform)) = camera.single() { for (mut accessible, node, transform) in &mut nodes { if node.is_changed() || transform.is_changed() { if let Ok(translation) = diff --git a/crates/bevy_ui/src/layout/mod.rs b/crates/bevy_ui/src/layout/mod.rs index 99a0d7f910..1b74b90f33 100644 --- a/crates/bevy_ui/src/layout/mod.rs +++ b/crates/bevy_ui/src/layout/mod.rs @@ -726,7 +726,7 @@ mod tests { mut cameras: Query<&mut Camera>, ) { let primary_window = primary_window_query - .get_single() + .single() .expect("missing primary window"); let camera_count = cameras.iter().len(); for (camera_index, mut camera) in cameras.iter_mut().enumerate() { @@ -783,7 +783,7 @@ mod tests { ui_schedule.run(world); let (ui_node_entity, UiTargetCamera(target_camera_entity)) = world .query_filtered::<(Entity, &UiTargetCamera), With>() - .get_single(world) + .single(world) .expect("missing MovingUiNode"); assert_eq!(expected_camera_entity, target_camera_entity); let mut ui_surface = world.resource_mut::(); diff --git a/crates/bevy_ui/src/picking_backend.rs b/crates/bevy_ui/src/picking_backend.rs index 0a60cba1e5..09acc000ea 100644 --- a/crates/bevy_ui/src/picking_backend.rs +++ b/crates/bevy_ui/src/picking_backend.rs @@ -84,7 +84,7 @@ pub fn ui_picking( .map(|(entity, camera, _)| { ( entity, - camera.target.normalize(primary_window.get_single().ok()), + camera.target.normalize(primary_window.single().ok()), ) }) .filter_map(|(entity, target)| Some(entity).zip(target)) diff --git a/crates/bevy_ui/src/ui_node.rs b/crates/bevy_ui/src/ui_node.rs index 96d9d2aeb2..2b5d517587 100644 --- a/crates/bevy_ui/src/ui_node.rs +++ b/crates/bevy_ui/src/ui_node.rs @@ -2691,7 +2691,7 @@ pub struct DefaultUiCamera<'w, 's> { impl<'w, 's> DefaultUiCamera<'w, 's> { pub fn get(&self) -> Option { - self.default_cameras.get_single().ok().or_else(|| { + self.default_cameras.single().ok().or_else(|| { // If there isn't a single camera and the query isn't empty, there is two or more cameras queried. if !self.default_cameras.is_empty() { once!(warn!("Two or more Entities with IsDefaultUiCamera found when only one Camera with this marker is allowed.")); diff --git a/crates/bevy_winit/src/accessibility.rs b/crates/bevy_winit/src/accessibility.rs index df7d012ff0..c2545d249a 100644 --- a/crates/bevy_winit/src/accessibility.rs +++ b/crates/bevy_winit/src/accessibility.rs @@ -183,7 +183,7 @@ fn update_accessibility_nodes( )>, node_entities: Query>, ) { - let Ok((primary_window_id, primary_window)) = primary_window.get_single() else { + let Ok((primary_window_id, primary_window)) = primary_window.single() else { return; }; let Some(adapter) = adapters.get_mut(&primary_window_id) else { diff --git a/crates/bevy_winit/src/state.rs b/crates/bevy_winit/src/state.rs index 525a5f22d3..a98909871c 100644 --- a/crates/bevy_winit/src/state.rs +++ b/crates/bevy_winit/src/state.rs @@ -551,7 +551,7 @@ impl WinitAppRunnerState { let mut query = self .world_mut() .query_filtered::>(); - let entity = query.single(&self.world()); + let entity = query.single(&self.world()).unwrap(); self.world_mut() .entity_mut(entity) .remove::(); @@ -571,7 +571,7 @@ impl WinitAppRunnerState { // handle wrapper removed when the app was suspended. let mut query = self.world_mut() .query_filtered::<(Entity, &Window), (With, Without)>(); - if let Ok((entity, window)) = query.get_single(&self.world()) { + if let Ok((entity, window)) = query.single(&self.world()) { let window = window.clone(); let mut create_window = diff --git a/examples/2d/2d_viewport_to_world.rs b/examples/2d/2d_viewport_to_world.rs index 6647437be3..3169b93bba 100644 --- a/examples/2d/2d_viewport_to_world.rs +++ b/examples/2d/2d_viewport_to_world.rs @@ -15,7 +15,7 @@ fn draw_cursor( window: Query<&Window>, mut gizmos: Gizmos, ) { - let Ok(window) = window.get_single() else { + let Ok(window) = window.single() else { return; }; diff --git a/examples/3d/3d_viewport_to_world.rs b/examples/3d/3d_viewport_to_world.rs index ef6da961d7..9aabd6f629 100644 --- a/examples/3d/3d_viewport_to_world.rs +++ b/examples/3d/3d_viewport_to_world.rs @@ -16,7 +16,7 @@ fn draw_cursor( windows: Query<&Window>, mut gizmos: Gizmos, ) { - let Ok(windows) = windows.get_single() else { + let Ok(windows) = windows.single() else { return; }; diff --git a/examples/3d/generate_custom_mesh.rs b/examples/3d/generate_custom_mesh.rs index 2222486ba1..9776f1accf 100644 --- a/examples/3d/generate_custom_mesh.rs +++ b/examples/3d/generate_custom_mesh.rs @@ -78,7 +78,7 @@ fn input_handler( time: Res