Add QueryState::get_single_unchecked_manual and its family (#4841)
# Objective - Rebase of #3159. - Fixes https://github.com/bevyengine/bevy/issues/3156 - add #[inline] to single related functions so that they matches with other function defs ## Solution * added functions to QueryState * get_single_unchecked_manual * get_single_unchecked * get_single * get_single_mut * single * single_mut * make Query::get_single use QueryState::get_single_unchecked_manual * added #[inline] --- ## Changelog ### Added Functions `QueryState::single`, `QueryState::get_single`, `QueryState::single_mut`, `QueryState::get_single_mut`, `QueryState::get_single_unchecked`, `QueryState::get_single_unchecked_manual`. ### Changed `QuerySingleError` is now in the `state` module. ## Migration Guide Change `query::QuerySingleError` to `state::QuerySingleError` Co-authored-by: 2ne1ugly <chattermin@gmail.com> Co-authored-by: 2ne1ugly <47616772+2ne1ugly@users.noreply.github.com>
This commit is contained in:
parent
e528b63e11
commit
c02beabe22
@ -258,7 +258,7 @@ struct QueryIterationCursor<'w, 's, Q: WorldQuery, QF: Fetch<'w, State = Q::Stat
|
||||
filter: QueryFetch<'w, F>,
|
||||
current_len: usize,
|
||||
current_index: usize,
|
||||
phantom: PhantomData<&'w Q>,
|
||||
phantom: PhantomData<(&'w (), Q)>,
|
||||
}
|
||||
|
||||
impl<'w, 's, Q: WorldQuery, QF, F: WorldQuery> Clone for QueryIterationCursor<'w, 's, Q, QF, F>
|
||||
|
||||
@ -944,6 +944,136 @@ impl<Q: WorldQuery, F: WorldQuery> QueryState<Q, F> {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// 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 [`single_mut`](Self::single_mut) for write-queries.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// 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]
|
||||
#[inline]
|
||||
pub fn single<'w>(&mut self, world: &'w World) -> ROQueryItem<'w, Q> {
|
||||
self.get_single(world).unwrap()
|
||||
}
|
||||
|
||||
/// 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.
|
||||
#[inline]
|
||||
pub fn get_single<'w>(
|
||||
&mut self,
|
||||
world: &'w World,
|
||||
) -> Result<ROQueryItem<'w, Q>, QuerySingleError> {
|
||||
self.update_archetypes(world);
|
||||
|
||||
// SAFETY: query is read only
|
||||
unsafe {
|
||||
self.get_single_unchecked_manual::<ROQueryFetch<'w, Q>>(
|
||||
world,
|
||||
world.last_change_tick(),
|
||||
world.read_change_tick(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// 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) -> QueryItem<'w, Q> {
|
||||
// SAFETY: query has unique world access
|
||||
self.get_single_mut(world).unwrap()
|
||||
}
|
||||
|
||||
/// Returns a single mutable query result when there is exactly one entity matching
|
||||
/// the query.
|
||||
///
|
||||
/// If the number of query results is not exactly one, a [`QuerySingleError`] is returned
|
||||
/// instead.
|
||||
#[inline]
|
||||
pub fn get_single_mut<'w>(
|
||||
&mut self,
|
||||
world: &'w mut World,
|
||||
) -> Result<QueryItem<'w, Q>, QuerySingleError> {
|
||||
self.update_archetypes(world);
|
||||
|
||||
// SAFETY: query has unique world access
|
||||
unsafe {
|
||||
self.get_single_unchecked_manual::<QueryFetch<'w, Q>>(
|
||||
world,
|
||||
world.last_change_tick(),
|
||||
world.read_change_tick(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a query result when there is exactly one entity matching the query.
|
||||
///
|
||||
/// If the number of query results is not exactly one, a [`QuerySingleError`] is returned
|
||||
/// instead.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// 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>(
|
||||
&mut self,
|
||||
world: &'w World,
|
||||
) -> Result<QueryItem<'w, Q>, QuerySingleError> {
|
||||
self.update_archetypes(world);
|
||||
|
||||
self.get_single_unchecked_manual::<QueryFetch<'w, Q>>(
|
||||
world,
|
||||
world.last_change_tick(),
|
||||
world.read_change_tick(),
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns a query result when there is exactly one entity matching the query,
|
||||
/// where the last change and the current change tick are given.
|
||||
///
|
||||
/// If the number of query results is not exactly one, a [`QuerySingleError`] is returned
|
||||
/// instead.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// 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_manual<'w, QF: Fetch<'w, State = Q::State>>(
|
||||
&self,
|
||||
world: &'w World,
|
||||
last_change_tick: u32,
|
||||
change_tick: u32,
|
||||
) -> Result<QF::Item, QuerySingleError> {
|
||||
let mut query = self.iter_unchecked_manual::<QF>(world, last_change_tick, change_tick);
|
||||
let first = query.next();
|
||||
let extra = query.next().is_some();
|
||||
|
||||
match (first, extra) {
|
||||
(Some(r), false) => Ok(r),
|
||||
(None, _) => Err(QuerySingleError::NoEntities(std::any::type_name::<Self>())),
|
||||
(Some(_), _) => Err(QuerySingleError::MultipleEntities(std::any::type_name::<
|
||||
Self,
|
||||
>())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An error that occurs when retrieving a specific [`Entity`]'s query result.
|
||||
@ -1074,3 +1204,24 @@ mod tests {
|
||||
let _panics = query_state.get_many_mut(&mut world_2, []);
|
||||
}
|
||||
}
|
||||
|
||||
/// An error that occurs when evaluating a [`QueryState`] as a single expected resulted via
|
||||
/// [`QueryState::single`] or [`QueryState::single_mut`].
|
||||
#[derive(Debug)]
|
||||
pub enum QuerySingleError {
|
||||
NoEntities(&'static str),
|
||||
MultipleEntities(&'static str),
|
||||
}
|
||||
|
||||
impl std::error::Error for QuerySingleError {}
|
||||
|
||||
impl std::fmt::Display for QuerySingleError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
match self {
|
||||
QuerySingleError::NoEntities(query) => write!(f, "No entities fit the query {}", query),
|
||||
QuerySingleError::MultipleEntities(query) => {
|
||||
write!(f, "Multiple entities fit the query {}!", query)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,7 +3,7 @@ use crate::{
|
||||
entity::Entity,
|
||||
query::{
|
||||
NopFetch, QueryCombinationIter, QueryEntityError, QueryFetch, QueryItem, QueryIter,
|
||||
QueryState, ROQueryFetch, ROQueryItem, ReadOnlyFetch, WorldQuery,
|
||||
QuerySingleError, QueryState, ROQueryFetch, ROQueryItem, ReadOnlyFetch, WorldQuery,
|
||||
},
|
||||
world::{Mut, World},
|
||||
};
|
||||
@ -968,7 +968,7 @@ impl<'w, 's, Q: WorldQuery, F: WorldQuery> Query<'w, 's, Q, F> {
|
||||
///
|
||||
/// ```
|
||||
/// # use bevy_ecs::prelude::*;
|
||||
/// # use bevy_ecs::system::QuerySingleError;
|
||||
/// # use bevy_ecs::query::QuerySingleError;
|
||||
/// # #[derive(Component)]
|
||||
/// # struct PlayerScore(i32);
|
||||
/// fn player_scoring_system(query: Query<&PlayerScore>) {
|
||||
@ -986,17 +986,14 @@ impl<'w, 's, Q: WorldQuery, F: WorldQuery> Query<'w, 's, Q, F> {
|
||||
/// }
|
||||
/// # bevy_ecs::system::assert_is_system(player_scoring_system);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn get_single(&self) -> Result<ROQueryItem<'_, Q>, QuerySingleError> {
|
||||
let mut query = self.iter();
|
||||
let first = query.next();
|
||||
let extra = query.next().is_some();
|
||||
|
||||
match (first, extra) {
|
||||
(Some(r), false) => Ok(r),
|
||||
(None, _) => Err(QuerySingleError::NoEntities(std::any::type_name::<Self>())),
|
||||
(Some(_), _) => Err(QuerySingleError::MultipleEntities(std::any::type_name::<
|
||||
Self,
|
||||
>())),
|
||||
unsafe {
|
||||
self.state.get_single_unchecked_manual::<ROQueryFetch<Q>>(
|
||||
self.world,
|
||||
self.last_change_tick,
|
||||
self.change_tick,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1051,17 +1048,14 @@ impl<'w, 's, Q: WorldQuery, F: WorldQuery> Query<'w, 's, Q, F> {
|
||||
/// }
|
||||
/// # bevy_ecs::system::assert_is_system(regenerate_player_health_system);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn get_single_mut(&mut self) -> Result<QueryItem<'_, Q>, QuerySingleError> {
|
||||
let mut query = self.iter_mut();
|
||||
let first = query.next();
|
||||
let extra = query.next().is_some();
|
||||
|
||||
match (first, extra) {
|
||||
(Some(r), false) => Ok(r),
|
||||
(None, _) => Err(QuerySingleError::NoEntities(std::any::type_name::<Self>())),
|
||||
(Some(_), _) => Err(QuerySingleError::MultipleEntities(std::any::type_name::<
|
||||
Self,
|
||||
>())),
|
||||
unsafe {
|
||||
self.state.get_single_unchecked_manual::<QueryFetch<Q>>(
|
||||
self.world,
|
||||
self.last_change_tick,
|
||||
self.change_tick,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1183,26 +1177,6 @@ impl std::fmt::Display for QueryComponentError {
|
||||
}
|
||||
}
|
||||
|
||||
/// An error that occurs when evaluating a [`Query`] as a single expected resulted via
|
||||
/// [`Query::single`] or [`Query::single_mut`].
|
||||
#[derive(Debug)]
|
||||
pub enum QuerySingleError {
|
||||
NoEntities(&'static str),
|
||||
MultipleEntities(&'static str),
|
||||
}
|
||||
|
||||
impl std::error::Error for QuerySingleError {}
|
||||
|
||||
impl std::fmt::Display for QuerySingleError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
match self {
|
||||
QuerySingleError::NoEntities(query) => write!(f, "No entities fit the query {}", query),
|
||||
QuerySingleError::MultipleEntities(query) => {
|
||||
write!(f, "Multiple entities fit the query {}!", query)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<'w, 's, Q: WorldQuery, F: WorldQuery> Query<'w, 's, Q, F>
|
||||
where
|
||||
QueryFetch<'w, Q>: ReadOnlyFetch,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user