Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate from Query::single and friends to Single #15872

Merged
merged 11 commits into from
Oct 13, 2024
4 changes: 2 additions & 2 deletions benches/benches/bevy_ecs/scheduling/run_condition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
16 changes: 8 additions & 8 deletions crates/bevy_app/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Single<(&A, &B, &C)>>) {
/// let (a, b, c) = query.unwrap().into_inner();
/// assert_eq!(b, &B(0));
/// assert_eq!(c, &C(0));
/// }
Expand Down Expand Up @@ -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<Single<(&A, &B, &C)>>) {
/// let (a, b, c) = query.unwrap().into_inner();
/// assert_eq!(b, &B(0));
/// assert_eq!(c, &C(2));
/// }
Expand Down Expand Up @@ -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<Single<(&A, &B, &C)>>) {
/// let (a, b, c) = query.unwrap().into_inner();
/// assert_eq!(b, &B(0));
/// assert_eq!(c, &C(0));
/// }
Expand Down Expand Up @@ -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<Single<(&A, &B, &C)>>) {
/// let (a, b, c) = query.unwrap().into_inner();
/// assert_eq!(b, &B(0));
/// assert_eq!(c, &C(2));
/// }
Expand Down
10 changes: 5 additions & 5 deletions crates/bevy_ecs/src/change_detection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};

Expand Down Expand Up @@ -1236,12 +1236,12 @@ mod tests {

#[test]
fn change_expiration() {
fn change_detected(query: Query<Ref<C>>) -> bool {
query.single().is_changed()
fn change_detected(query: Option<Single<Ref<C>>>) -> bool {
query.unwrap().is_changed()
}

fn change_expired(query: Query<Ref<C>>) -> bool {
query.single().is_changed()
fn change_expired(query: Option<Single<Ref<C>>>) -> bool {
query.unwrap().is_changed()
}

let mut world = World::new();
Expand Down
26 changes: 15 additions & 11 deletions crates/bevy_ecs/src/system/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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},
};
Expand Down Expand Up @@ -1157,12 +1157,15 @@ mod tests {
world.insert_resource(A(42));
world.spawn(B(7));

let mut system_state: SystemState<(Res<A>, Query<&B>, ParamSet<(Query<&C>, Query<&D>)>)> =
SystemState::new(&mut world);
let mut system_state: SystemState<(
Res<A>,
Option<Single<&B>>,
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"
);
Expand All @@ -1180,16 +1183,16 @@ mod tests {
world.insert_resource(A(42));
world.spawn(B(7));

let mut system_state: SystemState<(ResMut<A>, Query<&mut B>)> =
let mut system_state: SystemState<(ResMut<A>, Option<Single<&mut B>>)> =
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"
);
Expand All @@ -1203,21 +1206,22 @@ mod tests {
let mut world = World::default();
let entity = world.spawn(A(1)).id();

let mut system_state: SystemState<Query<&A, Changed<A>>> = SystemState::new(&mut world);
let mut system_state: SystemState<Option<Single<&A, Changed<A>>>> =
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::<A>().unwrap().0 = 2;
{
let query = system_state.get(&world);
assert_eq!(*query.single(), A(2));
assert_eq!(**query.unwrap(), A(2));
}
}

Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_ecs/src/system/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1384,7 +1384,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> {
/// * `&mut T` -> `&T`
/// * `&mut T` -> `Ref<T>`
/// * [`EntityMut`](crate::world::EntityMut) -> [`EntityRef`](crate::world::EntityRef)
///
///
/// [`EntityLocation`]: crate::entity::EntityLocation
/// [`&Archetype`]: crate::archetype::Archetype
#[track_caller]
Expand Down
5 changes: 2 additions & 3 deletions crates/bevy_ecs/src/system/system_param.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<AlarmFlag>
/// ) {
/// 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();
/// }
/// }
Expand Down
10 changes: 4 additions & 6 deletions crates/bevy_hierarchy/src/query_extension.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Entity, With<Marker>>, children_query: Query<&Children>) {
/// let entity = query.single();
/// for descendant in children_query.iter_descendants(entity) {
/// fn system(entity: Single<Entity, With<Marker>>, children_query: Query<&Children>) {
/// for descendant in children_query.iter_descendants(*entity) {
/// // Do something!
/// }
/// }
Expand Down Expand Up @@ -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<Entity, With<Marker>>, parent_query: Query<&Parent>) {
/// let entity = query.single();
/// for ancestor in parent_query.iter_ancestors(entity) {
/// fn system(entity: Single<Entity, With<Marker>>, parent_query: Query<&Parent>) {
/// for ancestor in parent_query.iter_ancestors(*entity) {
/// // Do something!
/// }
/// }
Expand Down
4 changes: 2 additions & 2 deletions examples/2d/2d_viewport_to_world.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
11 changes: 5 additions & 6 deletions examples/2d/bloom_2d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,18 +71,17 @@ fn setup(
// ------------------------------------------------------------------------------------------------

fn update_bloom_settings(
mut camera: Query<(Entity, Option<&mut Bloom>), With<Camera>>,
mut text: Query<&mut Text>,
camera: Single<(Entity, Option<&mut Bloom>), With<Camera>>,
mut text: Single<&mut Text>,
mut commands: Commands,
keycode: Res<ButtonInput<KeyCode>>,
time: Res<Time>,
) {
let bloom = camera.single_mut();
let mut text = text.single_mut();
let bloom = camera.into_inner();

match bloom {
(entity, Some(mut bloom)) => {
**text = "Bloom (Toggle: Space)\n".to_string();
text.0 = "Bloom (Toggle: Space)\n".to_string();
text.push_str(&format!("(Q/A) Intensity: {}\n", bloom.intensity));
text.push_str(&format!(
"(W/S) Low-frequency boost: {}\n",
Expand Down Expand Up @@ -173,7 +172,7 @@ fn update_bloom_settings(
}

(entity, None) => {
**text = "Bloom: Off (Toggle: Space)".to_string();
text.0 = "Bloom: Off (Toggle: Space)".to_string();

if keycode.just_pressed(KeyCode::Space) {
commands.entity(entity).insert(Bloom::default());
Expand Down
3 changes: 1 addition & 2 deletions examples/2d/bounding_2d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,11 @@ fn update_test_state(
state.set(next);
}

fn update_text(mut text: Query<&mut Text>, cur_state: Res<State<Test>>) {
fn update_text(mut text: Single<&mut Text>, cur_state: Res<State<Test>>) {
if !cur_state.is_changed() {
return;
}

let mut text = text.single_mut();
text.clear();

text.push_str("Intersection test:\n");
Expand Down
3 changes: 1 addition & 2 deletions examples/2d/pixel_grid_snap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,12 +144,11 @@ fn rotate(time: Res<Time>, mut transforms: Query<&mut Transform, With<Rotate>>)
/// Scales camera projection to fit the window (integer multiples only).
fn fit_canvas(
mut resize_events: EventReader<WindowResized>,
mut projections: Query<&mut OrthographicProjection, With<OuterCamera>>,
mut projection: Single<&mut OrthographicProjection, With<OuterCamera>>,
) {
for event in resize_events.read() {
let h_scale = event.width / RES_WIDTH as f32;
let v_scale = event.height / RES_HEIGHT as f32;
let mut projection = projections.single_mut();
projection.scaling_mode = ScalingMode::WindowSize(h_scale.min(v_scale).round());
}
}
10 changes: 4 additions & 6 deletions examples/2d/rotation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,9 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
fn player_movement_system(
time: Res<Time>,
keyboard_input: Res<ButtonInput<KeyCode>>,
mut query: Query<(&Player, &mut Transform)>,
query: Single<(&Player, &mut Transform)>,
) {
let (ship, mut transform) = query.single_mut();
let (ship, mut transform) = query.into_inner();

let mut rotation_factor = 0.0;
let mut movement_factor = 0.0;
Expand Down Expand Up @@ -143,9 +143,8 @@ fn player_movement_system(
/// Demonstrates snapping the enemy ship to face the player ship immediately.
fn snap_to_player_system(
mut query: Query<&mut Transform, (With<SnapToPlayer>, Without<Player>)>,
player_query: Query<&Transform, With<Player>>,
player_transform: Single<&Transform, With<Player>>,
) {
let player_transform = player_query.single();
// get the player translation in 2D
let player_translation = player_transform.translation.xy();

Expand Down Expand Up @@ -186,9 +185,8 @@ fn snap_to_player_system(
fn rotate_to_player_system(
time: Res<Time>,
mut query: Query<(&RotateToPlayer, &mut Transform), Without<Player>>,
player_query: Query<&Transform, With<Player>>,
player_transform: Single<&Transform, With<Player>>,
) {
let player_transform = player_query.single();
// get the player translation in 2D
let player_translation = player_transform.translation.xy();

Expand Down
4 changes: 1 addition & 3 deletions examples/2d/sprite_animation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,7 @@ fn main() {
}

// This system runs when the user clicks the left arrow key or right arrow key
fn trigger_animation<S: Component>(mut query: Query<&mut AnimationConfig, With<S>>) {
// we expect the Component of type S to be used as a marker Component by only a single entity
let mut animation = query.single_mut();
fn trigger_animation<S: Component>(mut animation: Single<&mut AnimationConfig, With<S>>) {
// we create a new timer when the animation is triggered
animation.frame_timer = AnimationConfig::timer_from_fps(animation.fps);
}
Expand Down
4 changes: 2 additions & 2 deletions examples/2d/wireframe_2d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,9 @@ fn update_colors(
keyboard_input: Res<ButtonInput<KeyCode>>,
mut config: ResMut<Wireframe2dConfig>,
mut wireframe_colors: Query<&mut Wireframe2dColor>,
mut text: Query<&mut Text>,
mut text: Single<&mut Text>,
) {
**text.single_mut() = format!(
text.0 = format!(
"Controls
---------------
Z - Toggle global
Expand Down
11 changes: 5 additions & 6 deletions examples/3d/3d_viewport_to_world.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,14 @@ fn main() {
}

fn draw_cursor(
camera_query: Query<(&Camera, &GlobalTransform)>,
ground_query: Query<&GlobalTransform, With<Ground>>,
windows: Query<&Window>,
camera_query: Single<(&Camera, &GlobalTransform)>,
ground: Single<&GlobalTransform, With<Ground>>,
windows: Single<&Window>,
mut gizmos: Gizmos,
) {
let (camera, camera_transform) = camera_query.single();
let ground = ground_query.single();
let (camera, camera_transform) = *camera_query;

let Some(cursor_position) = windows.single().cursor_position() else {
let Some(cursor_position) = windows.cursor_position() else {
return;
};

Expand Down
Loading