Skip to content
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 by Bors] - Add get_multiple and get_multiple_mut APIs for Query and QueryState #4298

Closed

Conversation

alice-i-cecile
Copy link
Member

@alice-i-cecile alice-i-cecile commented Mar 22, 2022

Objective

  • The inability to have multiple active mutable borrows into a query is a common source of borrow-checker pain for users.
  • This is a pointless restriction if and only if we can guarantee that the entities they are accessing are unique.
  • This could already by bypassed with get_unchecked, but that is an extremely unsafe API.
  • Closes Safe method for multiple mutable references to components from Query #2042.

Solution

  • Add get_multiple, get_multiple_mut and their unchecked equivalents (multiple and multiple_mut) to Query and QueryState.
  • Improve the QueryEntityError type to provide more useful error information.

Changelog

  • Added get_multiple, get_multiple_mut and their unchecked equivalents (multiple and multiple_mut) to Query and QueryState.

Migration Guide

  • The QueryEntityError enum now has a `AliasedMutability variant, and returns the offending entity.

Context

This is a fresh attempt at #3333; rebasing was behaving very badly and it was important to rebase on top of the recent query soundness fixes. Many thanks to all the reviewers in that thread, especially @BoxyUwU for the help with lifetimes.

To-do

  • Add compile fail tests
  • Successfully deduplicate code
  • Decide what to do about failing doc tests
  • Get some reviews for lifetime soundness

@alice-i-cecile alice-i-cecile added A-ECS Entities, components, systems, and events C-Usability A simple quality-of-life change that makes Bevy easier to use labels Mar 22, 2022
@alice-i-cecile alice-i-cecile added this to the Bevy 0.7 milestone Mar 22, 2022
@github-actions github-actions bot added the S-Needs-Triage This issue needs to be labelled label Mar 22, 2022
@alice-i-cecile alice-i-cecile added C-Breaking-Change A breaking change to Bevy's public API that needs to be noted in a migration guide and removed S-Needs-Triage This issue needs to be labelled labels Mar 22, 2022
Copy link
Member

@BoxyUwU BoxyUwU left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hopefully this doesnt result in a bunch of unreadable compiler errors 🤦‍♀️

crates/bevy_ecs/src/system/query.rs Outdated Show resolved Hide resolved
crates/bevy_ecs/src/system/query.rs Outdated Show resolved Hide resolved
crates/bevy_ecs/src/system/query.rs Outdated Show resolved Hide resolved
Co-authored-by: Boxy <supbscripter@gmail.com>
@alice-i-cecile alice-i-cecile marked this pull request as draft March 23, 2022 00:12
@nakedible
Copy link
Contributor

I can just say that looks good and even better than the last one, thanks for continuing this. I did read through the pull once to know exactly what was in there, but don't have time for a proper review now.

@BoxyUwU BoxyUwU added the S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it label Mar 25, 2022
Copy link
Member

@cart cart left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me! Just one comment on world validation.

last_change_tick: u32,
change_tick: u32,
) -> Result<[<Q::Fetch as Fetch<'w, 's>>::Item; N], QueryEntityError> {
self.validate_world(world);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The _unchecked_manual variants don't validate World in any other cases. This saves us on a lot of redundant work, as functions like Query::get() might get called hundreds of thousands of times, even in a single system. Instead, we (currently) put the burden on the scheduler to do this.

Sadly I didn't include this in the Safety docs in QueryState (or in System::run_unsafe) and theres a gap here because the "safe" System::run doesn't validate world.

Obviously thats not good. But I'd prefer to solve the problem holistically / leave the current pattern in-tact. I think validating world at the System::run_unsafe level (and updating the _unchecked_manual safety docs) has my preference here, given that we are embracing the "just run a system" pattern.

Barring any conflicting thoughts on this (this feels like it will be a divisive topic), can you move validate_world "up a level" and out of the _unchecked_manual variants?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of the other _manual stuff validates world so I think it would be weird for this PR to go and update everything to work differently

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

manual validates. manual_unchecked does not. I'm only talking about manual_unchecked here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops: unchecked_manual, not manual_unchecked

Copy link
Member

@cart cart Mar 30, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"manual" means you're on the hook to update archetypes (but by default should be assumed to be "safe"). "unchecked" is "fast / unvalidated / unsafe baseline impl"

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm definitely not asking for changes to unrelated code here. Just for consistency (despite the fact that the pattern being used has some holes, as previously stated).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm okay yeah I guess we are missing a lot of methods here so its hard to see a pattern 🤣 _unchecked not validating world seems fine I guess 🤔

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Barring any conflicting thoughts on this (this feels like it will be a divisive topic), can you move validate_world "up a level" and out of the _unchecked_manual variants?

Yep, can do.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(leaving unresolved so the link in #4363 works nicely)

@cart
Copy link
Member

cart commented Mar 30, 2022

So, I fixed this @cart, by making the underlying QueryState::get_read_only_manual unsafe.

You didn't fix that. Query::get_multiple will still call validate_world() internally, when it definitely shouldn't. Query::get_multiple_mut is fixed though.

Co-authored-by: Boxy <supbscripter@gmail.com>
@alice-i-cecile
Copy link
Member Author

There we go... Thanks @BoxyUwU.

@cart
Copy link
Member

cart commented Mar 30, 2022

bors r+

bors bot pushed a commit that referenced this pull request Mar 30, 2022
…4298)

# Objective

- The inability to have multiple active mutable borrows into a query is a common source of borrow-checker pain for users.
- This is a pointless restriction if and only if we can guarantee that the entities they are accessing are unique.
- This could already by bypassed with get_unchecked, but that is an extremely unsafe API.
- Closes #2042.

## Solution

- Add `get_multiple`, `get_multiple_mut` and their unchecked equivalents (`multiple` and `multiple_mut`) to `Query` and `QueryState`.
- Improve the `QueryEntityError` type to provide more useful error information.

## Changelog

- Added `get_multiple`, `get_multiple_mut` and their unchecked equivalents (`multiple` and `multiple_mut`) to Query and QueryState.

## Migration Guide

- The `QueryEntityError` enum now has a `AliasedMutability variant, and returns the offending entity.

## Context

This is a fresh attempt at #3333; rebasing was behaving very badly and it was important to rebase on top of the recent query soundness fixes. Many thanks to all the reviewers in that thread, especially @BoxyUwU for the help with lifetimes.

## To-do

- [x] Add compile fail tests
- [x] Successfully deduplicate code
- [x] Decide what to do about failing doc tests
- [x] Get some reviews for lifetime soundness
@bors bors bot changed the title Add get_multiple and get_multiple_mut APIs for Query and QueryState [Merged by Bors] - Add get_multiple and get_multiple_mut APIs for Query and QueryState Mar 30, 2022
@bors bors bot closed this Mar 30, 2022
aevyrie pushed a commit to aevyrie/bevy that referenced this pull request Jun 7, 2022
…evyengine#4298)

# Objective

- The inability to have multiple active mutable borrows into a query is a common source of borrow-checker pain for users.
- This is a pointless restriction if and only if we can guarantee that the entities they are accessing are unique.
- This could already by bypassed with get_unchecked, but that is an extremely unsafe API.
- Closes bevyengine#2042.

## Solution

- Add `get_multiple`, `get_multiple_mut` and their unchecked equivalents (`multiple` and `multiple_mut`) to `Query` and `QueryState`.
- Improve the `QueryEntityError` type to provide more useful error information.

## Changelog

- Added `get_multiple`, `get_multiple_mut` and their unchecked equivalents (`multiple` and `multiple_mut`) to Query and QueryState.

## Migration Guide

- The `QueryEntityError` enum now has a `AliasedMutability variant, and returns the offending entity.

## Context

This is a fresh attempt at bevyengine#3333; rebasing was behaving very badly and it was important to rebase on top of the recent query soundness fixes. Many thanks to all the reviewers in that thread, especially @BoxyUwU for the help with lifetimes.

## To-do

- [x] Add compile fail tests
- [x] Successfully deduplicate code
- [x] Decide what to do about failing doc tests
- [x] Get some reviews for lifetime soundness
ItsDoot pushed a commit to ItsDoot/bevy that referenced this pull request Feb 1, 2023
…evyengine#4298)

# Objective

- The inability to have multiple active mutable borrows into a query is a common source of borrow-checker pain for users.
- This is a pointless restriction if and only if we can guarantee that the entities they are accessing are unique.
- This could already by bypassed with get_unchecked, but that is an extremely unsafe API.
- Closes bevyengine#2042.

## Solution

- Add `get_multiple`, `get_multiple_mut` and their unchecked equivalents (`multiple` and `multiple_mut`) to `Query` and `QueryState`.
- Improve the `QueryEntityError` type to provide more useful error information.

## Changelog

- Added `get_multiple`, `get_multiple_mut` and their unchecked equivalents (`multiple` and `multiple_mut`) to Query and QueryState.

## Migration Guide

- The `QueryEntityError` enum now has a `AliasedMutability variant, and returns the offending entity.

## Context

This is a fresh attempt at bevyengine#3333; rebasing was behaving very badly and it was important to rebase on top of the recent query soundness fixes. Many thanks to all the reviewers in that thread, especially @BoxyUwU for the help with lifetimes.

## To-do

- [x] Add compile fail tests
- [x] Successfully deduplicate code
- [x] Decide what to do about failing doc tests
- [x] Get some reviews for lifetime soundness
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-ECS Entities, components, systems, and events C-Breaking-Change A breaking change to Bevy's public API that needs to be noted in a migration guide C-Usability A simple quality-of-life change that makes Bevy easier to use S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Safe method for multiple mutable references to components from Query
5 participants