From d96a9d15f6dd6730fe2908d44faa2c662711945c Mon Sep 17 00:00:00 2001 From: Pablo Reinhardt <126117294+pablo-lua@users.noreply.github.com> Date: Sun, 13 Oct 2024 17:32:06 -0300 Subject: [PATCH] Migrate from `Query::single` and friends to `Single` (#15872) # Objective - closes #15866 ## Solution - Simply migrate where possible. ## Testing - Expect that CI will do most of the work. Examples is another way of testing this, as most of the work is in that area. --- ## Notes For now, this PR doesn't migrate `QueryState::single` and friends as for now, this look like another issue. So for example, QueryBuilders that used single or `World::query` that used single wasn't migrated. If there is a easy way to migrate those, please let me know. Most of the uses of `Query::single` were removed, the only other uses that I found was related to tests of said methods, so will probably be removed when we remove `Query::single`. --- .../bevy_ecs/scheduling/run_condition.rs | 4 +- crates/bevy_app/src/app.rs | 16 +++--- crates/bevy_ecs/src/change_detection.rs | 10 ++-- crates/bevy_ecs/src/system/mod.rs | 26 ++++++---- crates/bevy_ecs/src/system/query.rs | 2 +- crates/bevy_ecs/src/system/system_param.rs | 5 +- crates/bevy_hierarchy/src/query_extension.rs | 10 ++-- examples/2d/2d_viewport_to_world.rs | 4 +- examples/2d/bloom_2d.rs | 11 ++-- examples/2d/bounding_2d.rs | 3 +- examples/2d/pixel_grid_snap.rs | 3 +- examples/2d/rotation.rs | 10 ++-- examples/2d/sprite_animation.rs | 4 +- examples/2d/wireframe_2d.rs | 4 +- examples/3d/3d_viewport_to_world.rs | 11 ++-- examples/3d/anti_aliasing.rs | 13 +++-- examples/3d/atmospheric_fog.rs | 4 +- examples/3d/auto_exposure.rs | 13 +++-- examples/3d/blend_modes.rs | 9 ++-- examples/3d/bloom_3d.rs | 11 ++-- examples/3d/color_grading.rs | 28 ++++------- examples/3d/deferred_rendering.rs | 4 +- examples/3d/fog.rs | 9 ++-- examples/3d/lighting.rs | 8 +-- examples/3d/load_gltf_extras.rs | 4 +- examples/3d/motion_blur.rs | 16 +++--- examples/3d/order_independent_transparency.rs | 4 +- examples/3d/parallax_mapping.rs | 15 +++--- examples/3d/shadow_biases.rs | 26 +++++----- examples/3d/spotlight.rs | 3 +- examples/3d/ssao.rs | 10 ++-- examples/3d/tonemapping.rs | 50 ++++++++----------- examples/3d/transmission.rs | 23 ++++----- examples/3d/wireframe.rs | 4 +- examples/app/log_layers_ecs.rs | 4 +- examples/audio/spatial_audio_2d.rs | 12 ++--- examples/audio/spatial_audio_3d.rs | 12 ++--- examples/camera/camera_orbit.rs | 9 ++-- examples/camera/projection_zoom.rs | 12 ++--- examples/ecs/iter_combinations.rs | 6 +-- examples/ecs/observers.rs | 7 ++- examples/ecs/one_shot_systems.rs | 16 +++--- examples/ecs/parallel_query.rs | 3 +- examples/games/alien_cake_addict.rs | 4 +- examples/games/breakout.rs | 11 ++-- examples/games/contributors.rs | 7 ++- examples/games/desk_toy.rs | 34 ++++++------- examples/games/game_menu.rs | 4 +- examples/games/loading_screen.rs | 4 +- examples/games/stepping.rs | 8 +-- examples/gizmos/light_gizmos.rs | 8 ++- examples/input/mouse_grab.rs | 4 +- examples/input/text_input.rs | 32 ++++++------ examples/math/custom_primitives.rs | 4 +- examples/math/random_sampling.rs | 3 +- examples/math/render_primitives.rs | 8 +-- examples/math/sampling_primitives.rs | 8 +-- examples/mobile/src/lib.rs | 20 +++----- examples/movement/smooth_follow.rs | 10 ++-- examples/remote/server.rs | 4 +- .../shader/compute_shader_game_of_life.rs | 3 +- .../shader_material_screenspace_texture.rs | 4 +- examples/shader/shader_prepass.rs | 9 ++-- examples/state/custom_transitions.rs | 4 +- examples/stress_tests/bevymark.rs | 19 +++---- .../stress_tests/many_animated_sprites.rs | 5 +- examples/stress_tests/many_cubes.rs | 3 +- examples/stress_tests/many_gizmos.rs | 6 +-- examples/stress_tests/many_lights.rs | 3 +- examples/stress_tests/many_sprites.rs | 5 +- examples/tools/gamepad_viewer.rs | 4 +- .../tools/scene_viewer/morph_viewer_plugin.rs | 4 +- examples/transforms/align.rs | 37 ++++++-------- examples/ui/overflow_debug.rs | 4 +- examples/ui/relative_cursor_position.rs | 8 ++- examples/ui/size_constraints.rs | 11 ++-- examples/ui/window_fallthrough.rs | 3 +- examples/window/low_power.rs | 7 ++- examples/window/scale_factor_override.rs | 15 ++---- examples/window/window_resizing.rs | 9 ++-- examples/window/window_settings.rs | 35 ++++--------- tests/window/minimising.rs | 3 +- tests/window/resizing.rs | 3 +- 83 files changed, 352 insertions(+), 483 deletions(-) diff --git a/benches/benches/bevy_ecs/scheduling/run_condition.rs b/benches/benches/bevy_ecs/scheduling/run_condition.rs index 1a033f36ef..c88d89b1fe 100644 --- a/benches/benches/bevy_ecs/scheduling/run_condition.rs +++ b/benches/benches/bevy_ecs/scheduling/run_condition.rs @@ -67,8 +67,8 @@ pub fn run_condition_yes_with_query(criterion: &mut Criterion) { group.warm_up_time(core::time::Duration::from_millis(500)); group.measurement_time(core::time::Duration::from_secs(3)); fn empty() {} - fn yes_with_query(query: Query<&TestBool>) -> bool { - query.single().0 + fn yes_with_query(query: Single<&TestBool>) -> bool { + query.0 } for amount in 0..21 { let mut schedule = Schedule::default(); diff --git a/crates/bevy_app/src/app.rs b/crates/bevy_app/src/app.rs index 7050c61d58..4cdc3a2473 100644 --- a/crates/bevy_app/src/app.rs +++ b/crates/bevy_app/src/app.rs @@ -800,8 +800,8 @@ impl App { /// commands.spawn(A); /// } /// - /// fn validate(query: Query<(&A, &B, &C)>) { - /// let (a, b, c) = query.single(); + /// fn validate(query: Option>) { + /// let (a, b, c) = query.unwrap().into_inner(); /// assert_eq!(b, &B(0)); /// assert_eq!(c, &C(0)); /// } @@ -863,8 +863,8 @@ impl App { /// commands.spawn(A); /// } /// - /// fn validate(query: Query<(&A, &B, &C)>) { - /// let (a, b, c) = query.single(); + /// fn validate(query: Option>) { + /// let (a, b, c) = query.unwrap().into_inner(); /// assert_eq!(b, &B(0)); /// assert_eq!(c, &C(2)); /// } @@ -928,8 +928,8 @@ impl App { /// commands.spawn(A); /// } /// - /// fn validate(query: Query<(&A, &B, &C)>) { - /// let (a, b, c) = query.single(); + /// fn validate(query: Option>) { + /// let (a, b, c) = query.unwrap().into_inner(); /// assert_eq!(b, &B(0)); /// assert_eq!(c, &C(0)); /// } @@ -993,8 +993,8 @@ impl App { /// commands.spawn(A); /// } /// - /// fn validate(query: Query<(&A, &B, &C)>) { - /// let (a, b, c) = query.single(); + /// fn validate(query: Option>) { + /// let (a, b, c) = query.unwrap().into_inner(); /// assert_eq!(b, &B(0)); /// assert_eq!(c, &C(2)); /// } diff --git a/crates/bevy_ecs/src/change_detection.rs b/crates/bevy_ecs/src/change_detection.rs index 5a3adac96f..025c3804e7 100644 --- a/crates/bevy_ecs/src/change_detection.rs +++ b/crates/bevy_ecs/src/change_detection.rs @@ -1206,7 +1206,7 @@ mod tests { Mut, NonSendMut, Ref, ResMut, TicksMut, CHECK_TICK_THRESHOLD, MAX_CHANGE_AGE, }, component::{Component, ComponentTicks, Tick}, - system::{IntoSystem, Query, System}, + system::{IntoSystem, Single, System}, world::World, }; @@ -1236,12 +1236,12 @@ mod tests { #[test] fn change_expiration() { - fn change_detected(query: Query>) -> bool { - query.single().is_changed() + fn change_detected(query: Option>>) -> bool { + query.unwrap().is_changed() } - fn change_expired(query: Query>) -> bool { - query.single().is_changed() + fn change_expired(query: Option>>) -> bool { + query.unwrap().is_changed() } let mut world = World::new(); diff --git a/crates/bevy_ecs/src/system/mod.rs b/crates/bevy_ecs/src/system/mod.rs index dd6a950f72..cd2452bcbc 100644 --- a/crates/bevy_ecs/src/system/mod.rs +++ b/crates/bevy_ecs/src/system/mod.rs @@ -328,7 +328,7 @@ mod tests { }, system::{ Commands, In, IntoSystem, Local, NonSend, NonSendMut, ParamSet, Query, Res, ResMut, - Resource, StaticSystemParam, System, SystemState, + Resource, Single, StaticSystemParam, System, SystemState, }, world::{EntityMut, FromWorld, World}, }; @@ -1157,12 +1157,15 @@ mod tests { world.insert_resource(A(42)); world.spawn(B(7)); - let mut system_state: SystemState<(Res, Query<&B>, ParamSet<(Query<&C>, Query<&D>)>)> = - SystemState::new(&mut world); + let mut system_state: SystemState<( + Res, + Option>, + ParamSet<(Query<&C>, Query<&D>)>, + )> = SystemState::new(&mut world); let (a, query, _) = system_state.get(&world); assert_eq!(*a, A(42), "returned resource matches initial value"); assert_eq!( - *query.single(), + **query.unwrap(), B(7), "returned component matches initial value" ); @@ -1180,16 +1183,16 @@ mod tests { world.insert_resource(A(42)); world.spawn(B(7)); - let mut system_state: SystemState<(ResMut, Query<&mut B>)> = + let mut system_state: SystemState<(ResMut, Option>)> = SystemState::new(&mut world); // The following line shouldn't compile because the parameters used are not ReadOnlySystemParam // let (a, query) = system_state.get(&world); - let (a, mut query) = system_state.get_mut(&mut world); + let (a, query) = system_state.get_mut(&mut world); assert_eq!(*a, A(42), "returned resource matches initial value"); assert_eq!( - *query.single_mut(), + **query.unwrap(), B(7), "returned component matches initial value" ); @@ -1203,21 +1206,22 @@ mod tests { let mut world = World::default(); let entity = world.spawn(A(1)).id(); - let mut system_state: SystemState>> = SystemState::new(&mut world); + let mut system_state: SystemState>>> = + SystemState::new(&mut world); { let query = system_state.get(&world); - assert_eq!(*query.single(), A(1)); + assert_eq!(**query.unwrap(), A(1)); } { let query = system_state.get(&world); - assert!(query.get_single().is_err()); + assert!(query.is_none()); } world.entity_mut(entity).get_mut::().unwrap().0 = 2; { let query = system_state.get(&world); - assert_eq!(*query.single(), A(2)); + assert_eq!(**query.unwrap(), A(2)); } } diff --git a/crates/bevy_ecs/src/system/query.rs b/crates/bevy_ecs/src/system/query.rs index f0116e60da..110f6b0b33 100644 --- a/crates/bevy_ecs/src/system/query.rs +++ b/crates/bevy_ecs/src/system/query.rs @@ -1384,7 +1384,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { /// * `&mut T` -> `&T` /// * `&mut T` -> `Ref` /// * [`EntityMut`](crate::world::EntityMut) -> [`EntityRef`](crate::world::EntityRef) - /// + /// /// [`EntityLocation`]: crate::entity::EntityLocation /// [`&Archetype`]: crate::archetype::Archetype #[track_caller] diff --git a/crates/bevy_ecs/src/system/system_param.rs b/crates/bevy_ecs/src/system/system_param.rs index 9d06aec04d..df98e49785 100644 --- a/crates/bevy_ecs/src/system/system_param.rs +++ b/crates/bevy_ecs/src/system/system_param.rs @@ -1214,18 +1214,17 @@ pub trait SystemBuffer: FromWorld + Send + 'static { /// /// // Sound the alarm if there are any criminals who pose a threat. /// fn alert_criminal( -/// settlements: Query<&Settlement>, +/// settlement: Single<&Settlement>, /// criminals: Query<&Criminal>, /// mut alarm: Deferred /// ) { -/// let settlement = settlements.single(); /// for criminal in &criminals { /// // Only sound the alarm if the criminal is a threat. /// // For this example, assume that this check is expensive to run. /// // Since the majority of this system's run-time is dominated /// // by calling `is_threat()`, we defer sounding the alarm to /// // allow this system to run in parallel with other alarm systems. -/// if criminal.is_threat(settlement) { +/// if criminal.is_threat(*settlement) { /// alarm.flag(); /// } /// } diff --git a/crates/bevy_hierarchy/src/query_extension.rs b/crates/bevy_hierarchy/src/query_extension.rs index 5cd8631310..6396ddcfb7 100644 --- a/crates/bevy_hierarchy/src/query_extension.rs +++ b/crates/bevy_hierarchy/src/query_extension.rs @@ -60,9 +60,8 @@ pub trait HierarchyQueryExt<'w, 's, D: QueryData, F: QueryFilter> { /// # use bevy_hierarchy::prelude::*; /// # #[derive(Component)] /// # struct Marker; - /// fn system(query: Query>, children_query: Query<&Children>) { - /// let entity = query.single(); - /// for descendant in children_query.iter_descendants(entity) { + /// fn system(entity: Single>, children_query: Query<&Children>) { + /// for descendant in children_query.iter_descendants(*entity) { /// // Do something! /// } /// } @@ -95,9 +94,8 @@ pub trait HierarchyQueryExt<'w, 's, D: QueryData, F: QueryFilter> { /// # use bevy_hierarchy::prelude::*; /// # #[derive(Component)] /// # struct Marker; - /// fn system(query: Query>, parent_query: Query<&Parent>) { - /// let entity = query.single(); - /// for ancestor in parent_query.iter_ancestors(entity) { + /// fn system(entity: Single>, parent_query: Query<&Parent>) { + /// for ancestor in parent_query.iter_ancestors(*entity) { /// // Do something! /// } /// } diff --git a/examples/2d/2d_viewport_to_world.rs b/examples/2d/2d_viewport_to_world.rs index 5648f30e87..5aa3db91e0 100644 --- a/examples/2d/2d_viewport_to_world.rs +++ b/examples/2d/2d_viewport_to_world.rs @@ -11,11 +11,11 @@ fn main() { } fn draw_cursor( - camera_query: Query<(&Camera, &GlobalTransform)>, + camera_query: Single<(&Camera, &GlobalTransform)>, windows: Query<&Window>, mut gizmos: Gizmos, ) { - let (camera, camera_transform) = camera_query.single(); + let (camera, camera_transform) = *camera_query; let Ok(window) = windows.get_single() else { return; diff --git a/examples/2d/bloom_2d.rs b/examples/2d/bloom_2d.rs index 1f75c0062e..3ffe6e1181 100644 --- a/examples/2d/bloom_2d.rs +++ b/examples/2d/bloom_2d.rs @@ -71,18 +71,17 @@ fn setup( // ------------------------------------------------------------------------------------------------ fn update_bloom_settings( - mut camera: Query<(Entity, Option<&mut Bloom>), With>, - mut text: Query<&mut Text>, + camera: Single<(Entity, Option<&mut Bloom>), With>, + mut text: Single<&mut Text>, mut commands: Commands, keycode: Res>, time: Res