Require read-only queries in QueryState::par_iter (#8832)

# Objective

The method `QueryState::par_iter` does not currently force the query to
be read-only. This means you can unsoundly mutate a world through an
immutable reference in safe code.

```rust
fn bad_system(world: &World, mut query: Local<QueryState<&mut T>>) {
    query.par_iter(world).for_each_mut(|mut x| *x = unsoundness);
}
```

## Solution

Use read-only versions of the `WorldQuery` types.

---

## Migration Guide

The function `QueryState::par_iter` now forces any world accesses to be
read-only, similar to how `QueryState::iter` works. Any code that
previously mutated the world using this method was *unsound*. If you
need to mutate the world, use `par_iter_mut` instead.
This commit is contained in:
JoJoJet 2023-06-12 21:17:40 -04:00 committed by GitHub
parent c475e271be
commit 3fba34c9e6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -865,11 +865,14 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> {
/// ///
/// [`par_iter_mut`]: Self::par_iter_mut /// [`par_iter_mut`]: Self::par_iter_mut
#[inline] #[inline]
pub fn par_iter<'w, 's>(&'s mut self, world: &'w World) -> QueryParIter<'w, 's, Q, F> { pub fn par_iter<'w, 's>(
&'s mut self,
world: &'w World,
) -> QueryParIter<'w, 's, Q::ReadOnly, F::ReadOnly> {
self.update_archetypes(world); self.update_archetypes(world);
QueryParIter { QueryParIter {
world, world,
state: self, state: self.as_readonly(),
last_run: world.last_change_tick(), last_run: world.last_change_tick(),
this_run: world.read_change_tick(), this_run: world.read_change_tick(),
batching_strategy: BatchingStrategy::new(), batching_strategy: BatchingStrategy::new(),