-
-
Notifications
You must be signed in to change notification settings - Fork 4k
Introduce methods on QueryState to obtain a Query #15858
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
Merged
Merged
Changes from 6 commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
4a210c6
Introduce methods on QueryState to obtain a Query, and methods on Que…
chescock 29ccc79
Merge remote-tracking branch 'remotes/origin/main' into querystate-query
chescock cfe03a1
Replace `Borrow<Entity>` with `EntityBorrow` in `iter_many_inner()`.
chescock 616ddd6
Merge remote-tracking branch 'remotes/origin/main' into HEAD
chescock cfebde7
Fix bad merge on QueryManyIter::sort_impl.
chescock b3251d1
Fix bad fix on QueryManyIter::sort_impl.
chescock 8a3b6be
Fix issues found in review.
chescock File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,6 +10,7 @@ use crate::{ | |
WorldQuery, | ||
}, | ||
storage::{SparseSetIndex, TableId}, | ||
system::Query, | ||
world::{unsafe_world_cell::UnsafeWorldCell, World, WorldId}, | ||
}; | ||
|
||
|
@@ -154,9 +155,7 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> { | |
pub fn matched_archetypes(&self) -> impl Iterator<Item = ArchetypeId> + '_ { | ||
self.matched_archetypes.ones().map(ArchetypeId::new) | ||
} | ||
} | ||
|
||
impl<D: QueryData, F: QueryFilter> QueryState<D, F> { | ||
/// Creates a new [`QueryState`] from a given [`World`] and inherits the result of `world.id()`. | ||
pub fn new(world: &mut World) -> Self { | ||
let mut state = Self::new_uninitialized(world); | ||
|
@@ -319,6 +318,123 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> { | |
state | ||
} | ||
|
||
/// Creates a [`Query`] from the given [`QueryState`] and [`World`]. | ||
/// | ||
/// This can only be called for read-only queries, see [`Self::query_mut`] for write-queries. | ||
pub fn query<'w, 's>(&'s mut self, world: &'w World) -> Query<'w, 's, D::ReadOnly, F> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh my gosh finally. |
||
self.update_archetypes(world); | ||
self.query_manual(world) | ||
} | ||
|
||
/// Creates a [`Query`] from the given [`QueryState`] and [`World`]. | ||
/// | ||
/// This method is slightly more efficient than [`QueryState::query`] in some situations, since | ||
/// it does not update this instance's internal cache. The resulting query may skip an entity that | ||
/// belongs to an archetype that has not been cached. | ||
/// | ||
/// To ensure that the cache is up to date, call [`QueryState::update_archetypes`] before this method. | ||
/// The cache is also updated in [`QueryState::new`], `QueryState::get`, or any method with mutable | ||
chescock marked this conversation as resolved.
Show resolved
Hide resolved
|
||
/// access to `self`. | ||
/// | ||
/// This can only be called for read-only queries, see [`Self::query_mut`] for mutable queries. | ||
pub fn query_manual<'w, 's>(&'s self, world: &'w World) -> Query<'w, 's, D::ReadOnly, F> { | ||
// SAFETY: We have read access to the entire world, and we call `as_readonly()` so the query only performs read access. | ||
unsafe { | ||
self.as_readonly() | ||
.query_unchecked_manual(world.as_unsafe_world_cell_readonly()) | ||
} | ||
} | ||
|
||
/// Creates a [`Query`] from the given [`QueryState`] and [`World`]. | ||
pub fn query_mut<'w, 's>(&'s mut self, world: &'w mut World) -> Query<'w, 's, D, F> { | ||
let last_run = world.last_change_tick(); | ||
let this_run = world.change_tick(); | ||
// SAFETY: We have exclusive access to the entire world. | ||
unsafe { self.query_unchecked_with_ticks(world.as_unsafe_world_cell(), last_run, this_run) } | ||
} | ||
|
||
/// Creates a [`Query`] from the given [`QueryState`] and [`World`]. | ||
/// | ||
/// # Safety | ||
/// | ||
/// This does not check for mutable query correctness. To be safe, make sure mutable queries | ||
/// have unique access to the components they query. | ||
pub unsafe fn query_unchecked<'w, 's>( | ||
&'s mut self, | ||
world: UnsafeWorldCell<'w>, | ||
) -> Query<'w, 's, D, F> { | ||
self.update_archetypes_unsafe_world_cell(world); | ||
self.query_unchecked_manual(world) | ||
chescock marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
/// Creates a [`Query`] from the given [`QueryState`] and [`World`]. | ||
/// | ||
/// This method is slightly more efficient than [`QueryState::query_unchecked`] in some situations, since | ||
/// it does not update this instance's internal cache. The resulting query may skip an entity that | ||
/// belongs to an archetype that has not been cached. | ||
/// | ||
/// To ensure that the cache is up to date, call [`QueryState::update_archetypes`] before this method. | ||
/// The cache is also updated in [`QueryState::new`], `QueryState::get`, or any method with mutable | ||
/// access to `self`. | ||
/// | ||
/// # Safety | ||
/// | ||
/// This does not check for mutable query correctness. To be safe, make sure mutable queries | ||
/// have unique access to the components they query. | ||
pub unsafe fn query_unchecked_manual<'w, 's>( | ||
&'s self, | ||
world: UnsafeWorldCell<'w>, | ||
) -> Query<'w, 's, D, F> { | ||
let last_run = world.last_change_tick(); | ||
let this_run = world.change_tick(); | ||
// SAFETY: The caller ensured we have the correct access to the world. | ||
unsafe { self.query_unchecked_manual_with_ticks(world, last_run, this_run) } | ||
} | ||
|
||
/// Creates a [`Query`] from the given [`QueryState`] and [`World`]. | ||
/// | ||
/// # Safety | ||
/// | ||
/// This does not check for mutable query correctness. To be safe, make sure mutable queries | ||
/// have unique access to the components they query. | ||
pub unsafe fn query_unchecked_with_ticks<'w, 's>( | ||
&'s mut self, | ||
world: UnsafeWorldCell<'w>, | ||
last_run: Tick, | ||
this_run: Tick, | ||
) -> Query<'w, 's, D, F> { | ||
self.update_archetypes_unsafe_world_cell(world); | ||
// SAFETY: The caller ensured we have the correct access to the world. | ||
unsafe { self.query_unchecked_manual_with_ticks(world, last_run, this_run) } | ||
} | ||
|
||
/// Creates a [`Query`] from the given [`QueryState`] and [`World`]. | ||
/// | ||
/// This method is slightly more efficient than [`QueryState::query_unchecked_with_ticks`] in some situations, since | ||
/// it does not update this instance's internal cache. The resulting query may skip an entity that | ||
/// belongs to an archetype that has not been cached. | ||
/// | ||
/// To ensure that the cache is up to date, call [`QueryState::update_archetypes`] before this method. | ||
/// The cache is also updated in [`QueryState::new`], `QueryState::get`, or any method with mutable | ||
/// access to `self`. | ||
/// | ||
/// # Safety | ||
/// | ||
/// This does not check for mutable query correctness. To be safe, make sure mutable queries | ||
/// have unique access to the components they query. | ||
pub unsafe fn query_unchecked_manual_with_ticks<'w, 's>( | ||
&'s self, | ||
world: UnsafeWorldCell<'w>, | ||
last_run: Tick, | ||
this_run: Tick, | ||
) -> Query<'w, 's, D, F> { | ||
self.validate_world(world.id()); | ||
// SAFETY: | ||
// - The caller ensured we have the correct access to the world. | ||
// - `validate_world` did not panic, so the world matches. | ||
unsafe { Query::new(world, self, last_run, this_run) } | ||
} | ||
|
||
/// Checks if the query is empty for the given [`World`], where the last change and current tick are given. | ||
/// | ||
/// This is equivalent to `self.iter().next().is_none()`, and thus the worst case runtime will be `O(n)` | ||
|
@@ -624,7 +740,7 @@ impl<D: QueryData, F: QueryFilter> QueryState<D, F> { | |
/// You should not call [`update_archetypes`](Self::update_archetypes) on the returned [`QueryState`] as the result will be unpredictable. | ||
/// You might end up with a mix of archetypes that only matched the original query + archetypes that only match | ||
/// the new [`QueryState`]. Most of the safe methods on [`QueryState`] call [`QueryState::update_archetypes`] internally, so this | ||
/// best used through a [`Query`](crate::system::Query). | ||
/// best used through a [`Query`] | ||
pub fn transmute<'a, NewD: QueryData>( | ||
&self, | ||
world: impl Into<UnsafeWorldCell<'a>>, | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -334,7 +334,7 @@ mod tests { | |
archetype::{ArchetypeComponentId, Archetypes}, | ||
bundle::Bundles, | ||
change_detection::DetectChanges, | ||
component::{Component, Components, Tick}, | ||
component::{Component, Components}, | ||
entity::{Entities, Entity}, | ||
prelude::{AnyOf, EntityRef}, | ||
query::{Added, Changed, Or, With, Without}, | ||
|
@@ -1361,7 +1361,7 @@ mod tests { | |
fn mutable_query(mut query: Query<&mut A>) { | ||
for _ in &mut query {} | ||
|
||
immutable_query(query.to_readonly()); | ||
immutable_query(query.as_readonly()); | ||
} | ||
|
||
fn immutable_query(_: Query<&A>) {} | ||
|
@@ -1376,7 +1376,7 @@ mod tests { | |
fn mutable_query(mut query: Query<Option<&mut A>>) { | ||
for _ in &mut query {} | ||
|
||
immutable_query(query.to_readonly()); | ||
immutable_query(query.as_readonly()); | ||
} | ||
|
||
fn immutable_query(_: Query<Option<&A>>) {} | ||
|
@@ -1391,7 +1391,7 @@ mod tests { | |
fn mutable_query(mut query: Query<(&mut A, &B)>) { | ||
for _ in &mut query {} | ||
|
||
immutable_query(query.to_readonly()); | ||
immutable_query(query.as_readonly()); | ||
} | ||
|
||
fn immutable_query(_: Query<(&A, &B)>) {} | ||
|
@@ -1406,7 +1406,7 @@ mod tests { | |
fn mutable_query(mut query: Query<(&mut A, &mut B)>) { | ||
for _ in &mut query {} | ||
|
||
immutable_query(query.to_readonly()); | ||
immutable_query(query.as_readonly()); | ||
} | ||
|
||
fn immutable_query(_: Query<(&A, &B)>) {} | ||
|
@@ -1421,7 +1421,7 @@ mod tests { | |
fn mutable_query(mut query: Query<(&mut A, &mut B), With<C>>) { | ||
for _ in &mut query {} | ||
|
||
immutable_query(query.to_readonly()); | ||
immutable_query(query.as_readonly()); | ||
} | ||
|
||
fn immutable_query(_: Query<(&A, &B), With<C>>) {} | ||
|
@@ -1436,7 +1436,7 @@ mod tests { | |
fn mutable_query(mut query: Query<(&mut A, &mut B), Without<C>>) { | ||
for _ in &mut query {} | ||
|
||
immutable_query(query.to_readonly()); | ||
immutable_query(query.as_readonly()); | ||
} | ||
|
||
fn immutable_query(_: Query<(&A, &B), Without<C>>) {} | ||
|
@@ -1451,7 +1451,7 @@ mod tests { | |
fn mutable_query(mut query: Query<(&mut A, &mut B), Added<C>>) { | ||
for _ in &mut query {} | ||
|
||
immutable_query(query.to_readonly()); | ||
immutable_query(query.as_readonly()); | ||
} | ||
|
||
fn immutable_query(_: Query<(&A, &B), Added<C>>) {} | ||
|
@@ -1466,7 +1466,7 @@ mod tests { | |
fn mutable_query(mut query: Query<(&mut A, &mut B), Changed<C>>) { | ||
for _ in &mut query {} | ||
|
||
immutable_query(query.to_readonly()); | ||
immutable_query(query.as_readonly()); | ||
} | ||
|
||
fn immutable_query(_: Query<(&A, &B), Changed<C>>) {} | ||
|
@@ -1572,24 +1572,6 @@ mod tests { | |
}); | ||
} | ||
|
||
#[test] | ||
#[should_panic = "Encountered a mismatched World."] | ||
fn query_validates_world_id() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why remove this test? Is it no longer applicable? |
||
let mut world1 = World::new(); | ||
let world2 = World::new(); | ||
let qstate = world1.query::<()>(); | ||
// SAFETY: doesnt access anything | ||
let query = unsafe { | ||
Query::new( | ||
world2.as_unsafe_world_cell_readonly(), | ||
&qstate, | ||
Tick::new(0), | ||
Tick::new(0), | ||
) | ||
}; | ||
query.iter(); | ||
} | ||
|
||
#[test] | ||
#[should_panic] | ||
fn assert_system_does_not_conflict() { | ||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.