-
-
Notifications
You must be signed in to change notification settings - Fork 3.9k
Store QueryState
in Query
as a Cow
and remove distinct QueryLens
type
#15848
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
Conversation
It's probably worth moving this change to a separate pr. Makes this pr a bit hard to review. |
Going to take a different approach to merging |
# Objective Simplify and expand the API for `QueryState`. `QueryState` has a lot of methods that mirror those on `Query`. These are then multiplied by variants that take `&World`, `&mut World`, and `UnsafeWorldCell`. In addition, many of them have `_manual` variants that take `&QueryState` and avoid calling `update_archetypes()`. Not all of the combinations exist, however, so some operations are not possible. ## Solution Introduce methods to get a `Query` from a `QueryState`. That will reduce duplication between the types, and ensure that the full `Query` API is always available for `QueryState`. Introduce methods on `Query` that consume the query to return types with the full `'w` lifetime. This avoids issues with borrowing where things like `query_state.query(&world).get(entity)` don't work because they borrow from the temporary `Query`. Finally, implement `Copy` for read-only `Query`s. `get_inner` and `iter_inner` currently take `&self`, so changing them to consume `self` would be a breaking change. By making `Query: Copy`, they can consume a copy of `self` and continue to work. The consuming methods also let us simplify the implementation of methods on `Query`, by doing `fn foo(&self) { self.as_readonly().foo_inner() }` and `fn foo_mut(&mut self) { self.reborrow().foo_inner() }`. That structure makes it more difficult to accidentally extend lifetimes, since the safe `as_readonly()` and `reborrow()` methods shrink them appropriately. The optimizer is able to see that they are both identity functions and inline them, so there should be no performance cost. Note that this change would conflict with #15848. If `QueryState` is stored as a `Cow`, then the consuming methods cannot be implemented, and `Copy` cannot be implemented. ## Future Work The next step is to mark the methods on `QueryState` as `#[deprecated]`, and move the implementations into `Query`. ## Migration Guide `Query::to_readonly` has been renamed to `Query::as_readonly`.
# Objective Simplify and expand the API for `QueryState`. `QueryState` has a lot of methods that mirror those on `Query`. These are then multiplied by variants that take `&World`, `&mut World`, and `UnsafeWorldCell`. In addition, many of them have `_manual` variants that take `&QueryState` and avoid calling `update_archetypes()`. Not all of the combinations exist, however, so some operations are not possible. ## Solution Introduce methods to get a `Query` from a `QueryState`. That will reduce duplication between the types, and ensure that the full `Query` API is always available for `QueryState`. Introduce methods on `Query` that consume the query to return types with the full `'w` lifetime. This avoids issues with borrowing where things like `query_state.query(&world).get(entity)` don't work because they borrow from the temporary `Query`. Finally, implement `Copy` for read-only `Query`s. `get_inner` and `iter_inner` currently take `&self`, so changing them to consume `self` would be a breaking change. By making `Query: Copy`, they can consume a copy of `self` and continue to work. The consuming methods also let us simplify the implementation of methods on `Query`, by doing `fn foo(&self) { self.as_readonly().foo_inner() }` and `fn foo_mut(&mut self) { self.reborrow().foo_inner() }`. That structure makes it more difficult to accidentally extend lifetimes, since the safe `as_readonly()` and `reborrow()` methods shrink them appropriately. The optimizer is able to see that they are both identity functions and inline them, so there should be no performance cost. Note that this change would conflict with bevyengine#15848. If `QueryState` is stored as a `Cow`, then the consuming methods cannot be implemented, and `Copy` cannot be implemented. ## Future Work The next step is to mark the methods on `QueryState` as `#[deprecated]`, and move the implementations into `Query`. ## Migration Guide `Query::to_readonly` has been renamed to `Query::as_readonly`.
I made an attempt at doing this with type parameters: #18162 |
Objective
The
QueryLens
type is basically aQuery
, except it stores theQueryState
itself rather than a reference to it. We can unifyQuery
andQueryLens
by allowingQuery
to hold either a reference or a value, whichCow
provides. As a byproduct, we can also now also returnQuery
s fromWorld::query
, rather thanQueryState
s.Solution
The following changes have been made:
QueryState
can now beClone
d (required byCow
)WorldQuery::State
types are now required to beClone
.Query
returning's
have been replaced with'_
.World::query
/World::query_filtered
functions have been renamed toWorld::query_state
/World::query_state_filtered
.World::query
/World::query_filtered
functions have been added that returnQuery
instead ofQueryState
.Query<D, F>::into_state(self) -> QueryState<D, F>
(clones the state if it was borrowed)QueryState<D, F>::as_query(&mut self, &mut World) -> Query<D, F>
QueryState<D, F>::as_readonly_query(&self, &World) -> Query<D::ReadOnly, F>
QueryState<D, F>::into_query(self, &mut World) -> Query<D, F>
QueryState<D, F>::into_readonly_query(self, &World) -> Query<D::ReadOnly, F>
QueryState<D, F>::into_readonly(self) -> QueryState<D::ReadOnly, F>
QueryState::as_readonly
, but by value instead of by reference.QueryLens
type has been removed.Query
can function exactly like it.Query::transmute_lens_filtered(&mut self) -> QueryLens
changed toQuery::transmute_filtered(&mut self) -> Query
Query::transmute_lens(&mut self) -> QueryLens
changed toQuery::transmute(&mut self) -> Query
Query::join(&mut self, other: &mut Query) -> QueryLens
changed toQuery::join(&mut self, other: &mut Query) -> Query
Query::join_filtered(&mut self, other: &mut Query) -> QueryLens
changed toQuery::join_filtered(&mut self, other: &mut Query) -> Query
QueryData
/QueryFilter
derives nowimpl Clone
.Testing
Showcase
TODO?
Migration Guide
QueryLens
usages should be replaced withQuery
.Query::transmute_lens_filtered(&mut self) -> QueryLens
changed toQuery::transmute_filtered(&mut self) -> Query
Query::transmute_lens(&mut self) -> QueryLens
changed toQuery::transmute(&mut self) -> Query
Query::join(&mut self, other: &mut Query) -> QueryLens
changed toQuery::join(&mut self, other: &mut Query) -> Query
Query::join_filtered(&mut self, other: &mut Query) -> QueryLens
changed toQuery::join_filtered(&mut self, other: &mut Query) -> Query
WorldQuery::State
types are now required to implementClone
.World::query
andWorld::query_filtered
functions were renamed toWorld::query_state
andWorld::query_state_filtered
, respectively.Query
functions returning data with a's
now return'_
, i.e. the query state lifetime is now bound by theQuery
instance rather than the containedQueryState
.