From 85ced1ec779fed2eb99116a24ef3d313b166ac82 Mon Sep 17 00:00:00 2001 From: TheRawMeatball Date: Tue, 19 Jan 2021 19:44:43 +0300 Subject: [PATCH 01/14] get_unique and get_unique_mut --- .../bevy_ecs/src/system/query/extensions.rs | 59 +++++++++++++++++++ crates/bevy_ecs/src/system/query/mod.rs | 1 + 2 files changed, 60 insertions(+) create mode 100644 crates/bevy_ecs/src/system/query/extensions.rs diff --git a/crates/bevy_ecs/src/system/query/extensions.rs b/crates/bevy_ecs/src/system/query/extensions.rs new file mode 100644 index 0000000000000..da293e84c426f --- /dev/null +++ b/crates/bevy_ecs/src/system/query/extensions.rs @@ -0,0 +1,59 @@ +use std::fmt::Debug; + +use thiserror::Error; + +use crate::{Fetch, Query, QueryFilter, ReadOnlyFetch, WorldQuery}; + +impl<'a, Q: WorldQuery, F: QueryFilter> Query<'a, Q, F> { + pub fn get_unique(&self) -> Result<>::Item, OnlyQueryError<'_, Q>> + where + Q::Fetch: ReadOnlyFetch, + { + let mut query = self.iter(); + let first = query.next(); + let extra_count = query.count(); + + match (first, extra_count) { + (Some(r), 0) => Ok(r), + (None, _) => Err(OnlyQueryError::NoEntities(std::any::type_name::())), + (Some(r), extra) => Err(OnlyQueryError::MultipleEntities( + r, + extra, + std::any::type_name::(), + )), + } + } + + pub fn get_unique_mut(&mut self) -> Result<>::Item, OnlyQueryError<'_, Q>> { + let mut query = self.iter_mut(); + let first = query.next(); + let extra_count = query.count(); + + match (first, extra_count) { + (Some(r), 0) => Ok(r), + (None, _) => Err(OnlyQueryError::NoEntities(std::any::type_name::())), + (Some(r), extra) => Err(OnlyQueryError::MultipleEntities( + r, + extra, + std::any::type_name::(), + )), + } + } +} + +#[derive(Error)] +pub enum OnlyQueryError<'a, Q: WorldQuery> { + #[error("No entities fit the query {0}")] + NoEntities(&'static str), + #[error("Multiple entities ({1} extra) fit the query {2}!")] + MultipleEntities(>::Item, usize, &'static str), +} + +impl<'a, Q: WorldQuery> Debug for OnlyQueryError<'a, Q> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + OnlyQueryError::NoEntities(_) => f.debug_tuple("NoEntities").finish(), + OnlyQueryError::MultipleEntities(_, _, _) => f.debug_tuple("MultipleEntities").finish(), + } + } +} diff --git a/crates/bevy_ecs/src/system/query/mod.rs b/crates/bevy_ecs/src/system/query/mod.rs index 60a309a029b76..40a37b995105b 100644 --- a/crates/bevy_ecs/src/system/query/mod.rs +++ b/crates/bevy_ecs/src/system/query/mod.rs @@ -1,4 +1,5 @@ mod query_set; +mod extensions; pub use query_set::*; use crate::{ From 573f293048edbd4133dc3b04e4616bab91bc2f29 Mon Sep 17 00:00:00 2001 From: TheRawMeatball Date: Tue, 19 Jan 2021 20:50:06 +0300 Subject: [PATCH 02/14] Documentation + update breakout example --- crates/bevy_ecs/src/system/query/extensions.rs | 6 +++++- crates/bevy_ecs/src/system/query/mod.rs | 2 +- examples/game/breakout.rs | 10 ++++------ 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/crates/bevy_ecs/src/system/query/extensions.rs b/crates/bevy_ecs/src/system/query/extensions.rs index da293e84c426f..8022d86ada2ff 100644 --- a/crates/bevy_ecs/src/system/query/extensions.rs +++ b/crates/bevy_ecs/src/system/query/extensions.rs @@ -5,6 +5,7 @@ use thiserror::Error; use crate::{Fetch, Query, QueryFilter, ReadOnlyFetch, WorldQuery}; impl<'a, Q: WorldQuery, F: QueryFilter> Query<'a, Q, F> { + /// Takes exactly one result from the query. If there is 0 or <1 results, this will return an error instead. pub fn get_unique(&self) -> Result<>::Item, OnlyQueryError<'_, Q>> where Q::Fetch: ReadOnlyFetch, @@ -24,7 +25,10 @@ impl<'a, Q: WorldQuery, F: QueryFilter> Query<'a, Q, F> { } } - pub fn get_unique_mut(&mut self) -> Result<>::Item, OnlyQueryError<'_, Q>> { + /// See [`Query::get_unique`] + pub fn get_unique_mut( + &mut self, + ) -> Result<>::Item, OnlyQueryError<'_, Q>> { let mut query = self.iter_mut(); let first = query.next(); let extra_count = query.count(); diff --git a/crates/bevy_ecs/src/system/query/mod.rs b/crates/bevy_ecs/src/system/query/mod.rs index 40a37b995105b..9c0fe694f077b 100644 --- a/crates/bevy_ecs/src/system/query/mod.rs +++ b/crates/bevy_ecs/src/system/query/mod.rs @@ -1,5 +1,5 @@ -mod query_set; mod extensions; +mod query_set; pub use query_set::*; use crate::{ diff --git a/examples/game/breakout.rs b/examples/game/breakout.rs index 3d52641803c56..e4b5765f26fd8 100644 --- a/examples/game/breakout.rs +++ b/examples/game/breakout.rs @@ -162,7 +162,7 @@ fn paddle_movement_system( keyboard_input: Res>, mut query: Query<(&Paddle, &mut Transform)>, ) { - for (paddle, mut transform) in query.iter_mut() { + if let Ok((paddle, mut transform)) = query.get_unique_mut() { let mut direction = 0.0; if keyboard_input.pressed(KeyCode::Left) { direction -= 1.0; @@ -184,15 +184,13 @@ fn ball_movement_system(time: Res