Skip to content

Simplify the implementation of UnsafeWorldCell #8727

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

Closed
wants to merge 2 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 13 additions & 14 deletions crates/bevy_ecs/src/world/unsafe_world_cell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ use crate::{
system::Resource,
};
use bevy_ptr::Ptr;
use std::{any::TypeId, cell::UnsafeCell, marker::PhantomData};
use bevy_utils::syncunsafecell::SyncUnsafeCell;
use std::any::TypeId;

/// Variant of the [`World`] where resource and component accesses take `&self`, and the responsibility to avoid
/// aliasing violations are given to the caller instead of being checked at compile-time by rust's unique XOR shared rule.
Expand Down Expand Up @@ -71,24 +72,22 @@ use std::{any::TypeId, cell::UnsafeCell, marker::PhantomData};
/// }
/// ```
#[derive(Copy, Clone)]
pub struct UnsafeWorldCell<'w>(*mut World, PhantomData<(&'w World, &'w UnsafeCell<World>)>);

// SAFETY: `&World` and `&mut World` are both `Send`
unsafe impl Send for UnsafeWorldCell<'_> {}
// SAFETY: `&World` and `&mut World` are both `Sync`
unsafe impl Sync for UnsafeWorldCell<'_> {}
pub struct UnsafeWorldCell<'w>(&'w SyncUnsafeCell<World>);

impl<'w> UnsafeWorldCell<'w> {
/// Creates a [`UnsafeWorldCell`] that can be used to access everything immutably
/// Creates an [`UnsafeWorldCell`] that can be used to access everything immutably.
#[inline]
pub(crate) fn new_readonly(world: &'w World) -> Self {
UnsafeWorldCell(world as *const World as *mut World, PhantomData)
// SAFETY: `SyncUnsafeCell<World>` has the same representation as `World`,
// so we can safely cast the latter to the former.
// The caller is forbidden from mutating the world with the returned value.
Self(unsafe { &*(world as *const _ as *const _) })
}

/// Creates [`UnsafeWorldCell`] that can be used to access everything mutably
/// Creates an [`UnsafeWorldCell`] that can be used to access everything mutably.
#[inline]
pub(crate) fn new_mutable(world: &'w mut World) -> Self {
Self(world as *mut World, PhantomData)
Self(SyncUnsafeCell::from_mut(world))
}

/// Gets a mutable reference to the [`World`] this [`UnsafeWorldCell`] belongs to.
Expand Down Expand Up @@ -138,7 +137,7 @@ impl<'w> UnsafeWorldCell<'w> {
pub unsafe fn world_mut(self) -> &'w mut World {
// SAFETY:
// - caller ensures the created `&mut World` is the only borrow of world
unsafe { &mut *self.0 }
unsafe { &mut *self.0.get() }
}

/// Gets a reference to the [`&World`](crate::world::World) this [`UnsafeWorldCell`] belongs to.
Expand All @@ -154,7 +153,7 @@ impl<'w> UnsafeWorldCell<'w> {
// - caller ensures there is no `&mut World` this makes it okay to make a `&World`
// - caller ensures there is no mutable borrows of world data, this means the caller cannot
// misuse the returned `&World`
unsafe { &*self.0 }
unsafe { &*self.0.get() }
}

/// Gets a reference to the [`World`] this [`UnsafeWorldCell`] belong to.
Expand Down Expand Up @@ -187,7 +186,7 @@ impl<'w> UnsafeWorldCell<'w> {
// SAFETY:
// - caller ensures that the returned `&World` is not used in a way that would conflict
// with any existing mutable borrows of world data
unsafe { &*self.0 }
unsafe { &*self.0.get() }
}

/// Retrieves this world's unique [ID](WorldId).
Expand Down