-
-
Notifications
You must be signed in to change notification settings - Fork 3.6k
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
use UnsafeWorldCell
internally
#6972
use UnsafeWorldCell
internally
#6972
Conversation
@jakobhellermann can you rebase this? I'd like to prioritize this for review and merging due to its impact on ECS internals clarity. |
5ce7cbe
to
7cc5b86
Compare
7cc5b86
to
ebc7198
Compare
8abb3cf
to
93dbca5
Compare
InteriorMutableWorld
internallyUnsafeWorldCell
internally
93dbca5
to
f7606e9
Compare
I'm unsure if we can get this reviewed and merged appropriately without stopping the train. Impact is mostly internal, so I've bumped it from the 0.10 milestone. |
@@ -158,8 +162,18 @@ impl<Q: WorldQuery, F: ReadOnlyWorldQuery> QueryState<Q, F> { | |||
} | |||
} | |||
|
|||
fn update_archetypes_unsafe_world_cell(&mut self, world: UnsafeWorldCell<'_>) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fn update_archetypes_unsafe_world_cell(&mut self, world: UnsafeWorldCell<'_>) { | |
pub fn update_archetypes_unsafe_world_cell(&mut self, world: UnsafeWorldCell<'_>) { |
and also implement update_archetypes
in terms of this method rather than the way it is now perhaps
self.validate_world_unsafe_world_cell(world.as_unsafe_world_cell_readonly()) | ||
} | ||
#[inline] | ||
pub fn validate_world_unsafe_world_cell(&self, world: UnsafeWorldCell<'_>) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pub fn validate_world_unsafe_world_cell(&self, world: UnsafeWorldCell<'_>) { | |
pub fn validate_unsafe_world_cell(&self, world: UnsafeWorldCell<'_>) { |
@@ -309,6 +310,9 @@ impl MultiThreadedExecutor { | |||
break; | |||
} | |||
|
|||
// TODO: do this earlier? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, you want to replace the cell: &'scope SyncUnsafeCell<World>
with cell: UnsafeWorldCell<'scope>
I believe.
.sparse_sets | ||
.get(component_id) | ||
.debug_checked_unwrap() | ||
// SAFETY: TODO |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to be a non-TODO comment.
.sparse_sets | ||
.get(component_id) | ||
.debug_checked_unwrap() | ||
// SAFETY: world has access to |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This placeholder needs to be fully written.
#[inline] | ||
pub fn validate_world(&self, world: &World) { | ||
self.validate_world_unsafe_world_cell(world.as_unsafe_world_cell_readonly()) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
} | |
} | |
self.validate_world_unsafe_world_cell(world.as_unsafe_world_cell_readonly()) | ||
} | ||
#[inline] | ||
pub fn validate_world_unsafe_world_cell(&self, world: UnsafeWorldCell<'_>) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this is to be public, please document what this function does. Alternatively, we could just have validate_world
take a WorldId
instead, which should be accessible from both.
Closing in favor of #8833. |
# Objective Follow-up to #6404 and #8292. Mutating the world through a shared reference is surprising, and it makes the meaning of `&World` unclear: sometimes it gives read-only access to the entire world, and sometimes it gives interior mutable access to only part of it. This is an up-to-date version of #6972. ## Solution Use `UnsafeWorldCell` for all interior mutability. Now, `&World` *always* gives you read-only access to the entire world. --- ## Changelog TODO - do we still care about changelogs? ## Migration Guide Mutating any world data using `&World` is now considered unsound -- the type `UnsafeWorldCell` must be used to achieve interior mutability. The following methods now accept `UnsafeWorldCell` instead of `&World`: - `QueryState`: `get_unchecked`, `iter_unchecked`, `iter_combinations_unchecked`, `for_each_unchecked`, `get_single_unchecked`, `get_single_unchecked_manual`. - `SystemState`: `get_unchecked_manual` ```rust let mut world = World::new(); let mut query = world.query::<&mut T>(); // Before: let t1 = query.get_unchecked(&world, entity_1); let t2 = query.get_unchecked(&world, entity_2); // After: let world_cell = world.as_unsafe_world_cell(); let t1 = query.get_unchecked(world_cell, entity_1); let t2 = query.get_unchecked(world_cell, entity_2); ``` The methods `QueryState::validate_world` and `SystemState::matches_world` now take a `WorldId` instead of `&World`: ```rust // Before: query_state.validate_world(&world); // After: query_state.validate_world(world.id()); ``` The methods `QueryState::update_archetypes` and `SystemState::update_archetypes` now take `UnsafeWorldCell` instead of `&World`: ```rust // Before: query_state.update_archetypes(&world); // After: query_state.update_archetypes(world.as_unsafe_world_cell_readonly()); ```
builds on #6404 (and #6402)
important commits:
System
andParamState
QueryState
/Query
Objective
UnsafeWorldCell
abstraction #6404 and the issue Abstraction for working with a&World
and interior mutability #5956, but the TLDR is:&World
is sometimes used internally to mean "world that is shared with others but the access is distinct"get_resource
that is unsound because the&World
doesn't actually give accessSolution
UnsafeWorldCell
whenever we use&World
as shared mutableSystem
machinery and forQuery
/WorldQuery
Changelog
bevy now uses the
UnsafeWorldCell
type in places where we previously used&World
to mean "shared mutable access, but ensured to be distinct by systems".This means that systems and queries now get a
UnsafeWorldCell
where every method is unsafe, so you need to reason correctly about every access.Usually this is done like