-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
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
QueryLenstype is basically aQuery, except it stores theQueryStateitself rather than a reference to it. We can unifyQueryandQueryLensby allowingQueryto hold either a reference or a value, whichCowprovides. As a byproduct, we can also now also returnQuerys fromWorld::query, rather thanQueryStates.Solution
The following changes have been made:
QueryStatecan now beCloned (required byCow)WorldQuery::Statetypes are now required to beClone.Queryreturning'shave been replaced with'_.World::query/World::query_filteredfunctions have been renamed toWorld::query_state/World::query_state_filtered.World::query/World::query_filteredfunctions have been added that returnQueryinstead 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.QueryLenstype has been removed.Querycan function exactly like it.Query::transmute_lens_filtered(&mut self) -> QueryLenschanged toQuery::transmute_filtered(&mut self) -> QueryQuery::transmute_lens(&mut self) -> QueryLenschanged toQuery::transmute(&mut self) -> QueryQuery::join(&mut self, other: &mut Query) -> QueryLenschanged toQuery::join(&mut self, other: &mut Query) -> QueryQuery::join_filtered(&mut self, other: &mut Query) -> QueryLenschanged toQuery::join_filtered(&mut self, other: &mut Query) -> QueryQueryData/QueryFilterderives nowimpl Clone.Testing
Showcase
TODO?
Migration Guide
QueryLensusages should be replaced withQuery.Query::transmute_lens_filtered(&mut self) -> QueryLenschanged toQuery::transmute_filtered(&mut self) -> QueryQuery::transmute_lens(&mut self) -> QueryLenschanged toQuery::transmute(&mut self) -> QueryQuery::join(&mut self, other: &mut Query) -> QueryLenschanged toQuery::join(&mut self, other: &mut Query) -> QueryQuery::join_filtered(&mut self, other: &mut Query) -> QueryLenschanged toQuery::join_filtered(&mut self, other: &mut Query) -> QueryWorldQuery::Statetypes are now required to implementClone.World::queryandWorld::query_filteredfunctions were renamed toWorld::query_stateandWorld::query_state_filtered, respectively.Queryfunctions returning data with a'snow return'_, i.e. the query state lifetime is now bound by theQueryinstance rather than the containedQueryState.