Improve documentation for UnsafeWorldCell::world_mut (#8587)

# Objective

The method `UnsafeWorldCell::world_mut` is a special case, since its
safety contract is more difficult to satisfy than the other methods on
`UnsafeWorldCell`. Rewrite its documentation to be specific about when
it can and cannot be used. Provide examples and emphasize that it is
unsound to call in most cases.
This commit is contained in:
JoJoJet 2023-05-10 20:31:26 -04:00 committed by GitHub
parent 35240fe4f8
commit 76fe2b40c6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -92,15 +92,49 @@ impl<'w> UnsafeWorldCell<'w> {
Self(world as *mut World, PhantomData) Self(world as *mut World, PhantomData)
} }
/// This `&mut World` counts as a mutable borrow of every resource and component for the purposes /// Gets a mutable reference to the [`World`] this [`UnsafeWorldCell`] belongs to.
/// of safety invariants that talk about borrows on component/resource data not existing. This is /// This is an incredibly error-prone operation and is only valid in a small number of circumstances.
/// true even for methods that do not explicitly call out `&mut World` as problematic.
/// ///
/// # Safety /// # Safety
/// - must have permission to access everything mutably /// - `self` must have been obtained from a call to [`World::as_unsafe_world_cell`]
/// - there must be no other borrows on world /// (*not* `as_unsafe_world_cell_readonly` or any other method of construction that
/// - returned borrow must not be used in any way if the world is accessed /// does not provide mutable access to the entire world).
/// through other means than the `&mut World` after this call. /// - This means that if you have an `UnsafeWorldCell` that you didn't create yourself,
/// it is likely *unsound* to call this method.
/// - The returned `&mut World` *must* be unique: it must never be allowed to exist
/// at the same time as any other borrows of the world or any accesses to its data.
/// This includes safe ways of accessing world data, such as [`UnsafeWorldCell::archetypes`]:
/// - Note that the `&mut World` *may* exist at the same time as instances of `UnsafeWorldCell`,
/// so long as none of those instances are used to access world data in any way
/// while the mutable borrow is active.
///
/// [//]: # (This test fails miri.)
/// ```no_run
/// # use bevy_ecs::prelude::*;
/// # #[derive(Component)] struct Player;
/// # fn store_but_dont_use<T>(_: T) {}
/// # let mut world = World::new();
/// // Make an UnsafeWorldCell.
/// let world_cell = world.as_unsafe_world_cell();
///
/// // SAFETY: `world_cell` was originally created from `&mut World`.
/// // We must be sure not to access any world data while `world_mut` is active.
/// let world_mut = unsafe { world_cell.world_mut() };
///
/// // We can still use `world_cell` so long as we don't access the world with it.
/// store_but_dont_use(world_cell);
///
/// // !!This is unsound!! Even though this method is safe, we cannot call it until
/// // `world_mut` is no longer active.
/// let tick = world_cell.read_change_tick();
///
/// // Use mutable access to spawn an entity.
/// world_mut.spawn(Player);
///
/// // Since we never use `world_mut` after this, the borrow is released
/// // and we are once again allowed to access the world using `world_cell`.
/// let archetypes = world_cell.archetypes();
/// ```
#[inline] #[inline]
pub unsafe fn world_mut(self) -> &'w mut World { pub unsafe fn world_mut(self) -> &'w mut World {
// SAFETY: // SAFETY: