Struct bevy_ecs::world::unsafe_world_cell::UnsafeWorldCell
source · pub struct UnsafeWorldCell<'w>(/* private fields */);
Expand description
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.
Rationale
In rust, having a &mut World
means that there are absolutely no other references to the safe world alive at the same time,
without exceptions. Not even unsafe code can change this.
But there are situations where careful shared mutable access through a type is possible and safe. For this, rust provides the UnsafeCell
escape hatch, which allows you to get a *mut T
from a &UnsafeCell<T>
and around which safe abstractions can be built.
Access to resources and components can be done uniquely using World::resource_mut
and World::entity_mut
, and shared using World::resource
and World::entity
.
These methods use lifetimes to check at compile time that no aliasing rules are being broken.
This alone is not enough to implement bevy systems where multiple systems can access disjoint parts of the world concurrently. For this, bevy stores all values of
resources and components (and ComponentTicks
) in UnsafeCell
s, and carefully validates disjoint access patterns using
APIs like System::component_access
.
A system then can be executed using System::run_unsafe
with a &World
and use methods with interior mutability to access resource values.
Example Usage
UnsafeWorldCell
can be used as a building block for writing APIs that safely allow disjoint access into the world.
In the following example, the world is split into a resource access half and a component access half, where each one can
safely hand out mutable references.
use bevy_ecs::world::World;
use bevy_ecs::change_detection::Mut;
use bevy_ecs::system::Resource;
use bevy_ecs::world::unsafe_world_cell::UnsafeWorldCell;
// INVARIANT: existence of this struct means that users of it are the only ones being able to access resources in the world
struct OnlyResourceAccessWorld<'w>(UnsafeWorldCell<'w>);
// INVARIANT: existence of this struct means that users of it are the only ones being able to access components in the world
struct OnlyComponentAccessWorld<'w>(UnsafeWorldCell<'w>);
impl<'w> OnlyResourceAccessWorld<'w> {
fn get_resource_mut<T: Resource>(&mut self) -> Option<Mut<'_, T>> {
// SAFETY: resource access is allowed through this UnsafeWorldCell
unsafe { self.0.get_resource_mut::<T>() }
}
}
// impl<'w> OnlyComponentAccessWorld<'w> {
// ...
// }
// the two `UnsafeWorldCell`s borrow from the `&mut World`, so it cannot be accessed while they are live
fn split_world_access(world: &mut World) -> (OnlyResourceAccessWorld<'_>, OnlyComponentAccessWorld<'_>) {
let unsafe_world_cell = world.as_unsafe_world_cell();
let resource_access = OnlyResourceAccessWorld(unsafe_world_cell);
let component_access = OnlyComponentAccessWorld(unsafe_world_cell);
(resource_access, component_access)
}
Implementations§
source§impl<'w> UnsafeWorldCell<'w>
impl<'w> UnsafeWorldCell<'w>
sourcepub unsafe fn world_mut(self) -> &'w mut World
pub unsafe fn world_mut(self) -> &'w mut World
Gets a mutable reference to the World
this UnsafeWorldCell
belongs to.
This is an incredibly error-prone operation and is only valid in a small number of circumstances.
Safety
self
must have been obtained from a call toWorld::as_unsafe_world_cell
(notas_unsafe_world_cell_readonly
or any other method of construction that does not provide mutable access to the entire world).- This means that if you have an
UnsafeWorldCell
that you didn’t create yourself, it is likely unsound to call this method.
- This means that if you have an
- 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 asUnsafeWorldCell::archetypes
.- Note that the
&mut World
may exist at the same time as instances ofUnsafeWorldCell
, so long as none of those instances are used to access world data in any way while the mutable borrow is active.
- Note that the
// 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.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();
sourcepub unsafe fn world(self) -> &'w World
pub unsafe fn world(self) -> &'w World
Gets a reference to the &World
this UnsafeWorldCell
belongs to.
This can be used for arbitrary shared/readonly access.
Safety
- must have permission to access the whole world immutably
- there must be no live exclusive borrows on world data
- there must be no live exclusive borrow of world
sourcepub unsafe fn world_metadata(self) -> &'w World
pub unsafe fn world_metadata(self) -> &'w World
Gets a reference to the World
this UnsafeWorldCell
belong to.
This can be used for arbitrary read only access of world metadata
You should attempt to use various safe methods on UnsafeWorldCell
for
metadata access before using this method.
Safety
- must only be used to access world metadata
sourcepub fn archetypes(self) -> &'w Archetypes
pub fn archetypes(self) -> &'w Archetypes
Retrieves this world’s Archetypes
collection.
sourcepub fn components(self) -> &'w Components
pub fn components(self) -> &'w Components
Retrieves this world’s Components
collection.
sourcepub fn removed_components(self) -> &'w RemovedComponentEvents
pub fn removed_components(self) -> &'w RemovedComponentEvents
Retrieves this world’s collection of removed components.
sourcepub fn change_tick(self) -> Tick
pub fn change_tick(self) -> Tick
Gets the current change tick of this world.
sourcepub fn last_change_tick(self) -> Tick
pub fn last_change_tick(self) -> Tick
Returns the Tick
indicating the last time that World::clear_trackers
was called.
If this UnsafeWorldCell
was created from inside of an exclusive system (a System
that
takes &mut World
as its first parameter), this will instead return the Tick
indicating
the last time the system was run.
sourcepub fn increment_change_tick(self) -> Tick
pub fn increment_change_tick(self) -> Tick
Increments the world’s current change tick and returns the old value.
sourcepub unsafe fn storages(self) -> &'w Storages
pub unsafe fn storages(self) -> &'w Storages
Provides unchecked access to the internal data stores of the World
.
Safety
The caller must ensure that this is only used to access world data
that this UnsafeWorldCell
is allowed to.
As always, any mutable access to a component must not exist at the same
time as any other accesses to that same component.
sourcepub fn get_entity(self, entity: Entity) -> Option<UnsafeEntityCell<'w>>
pub fn get_entity(self, entity: Entity) -> Option<UnsafeEntityCell<'w>>
Retrieves an UnsafeEntityCell
that exposes read and write operations for the given entity
.
Similar to the UnsafeWorldCell
, you are in charge of making sure that no aliasing rules are violated.
sourcepub unsafe fn get_resource<R: Resource>(self) -> Option<&'w R>
pub unsafe fn get_resource<R: Resource>(self) -> Option<&'w R>
Gets a reference to the resource of the given type if it exists
Safety
It is the callers responsibility to ensure that
- the
UnsafeWorldCell
has permission to access the resource - no mutable reference to the resource exists at the same time
sourcepub unsafe fn get_resource_ref<R: Resource>(self) -> Option<Res<'w, R>>
pub unsafe fn get_resource_ref<R: Resource>(self) -> Option<Res<'w, R>>
Gets a reference including change detection to the resource of the given type if it exists.
Safety
It is the callers responsibility to ensure that
- the
UnsafeWorldCell
has permission to access the resource - no mutable reference to the resource exists at the same time
sourcepub unsafe fn get_resource_by_id(
self,
component_id: ComponentId
) -> Option<Ptr<'w>>
pub unsafe fn get_resource_by_id( self, component_id: ComponentId ) -> Option<Ptr<'w>>
Gets a pointer to the resource with the id ComponentId
if it exists.
The returned pointer must not be used to modify the resource, and must not be
dereferenced after the borrow of the World
ends.
You should prefer to use the typed API UnsafeWorldCell::get_resource
where possible and only
use this in cases where the actual types are not known at compile time.
Safety
It is the callers responsibility to ensure that
- the
UnsafeWorldCell
has permission to access the resource - no mutable reference to the resource exists at the same time
sourcepub unsafe fn get_non_send_resource<R: 'static>(self) -> Option<&'w R>
pub unsafe fn get_non_send_resource<R: 'static>(self) -> Option<&'w R>
Gets a reference to the non-send resource of the given type if it exists
Safety
It is the callers responsibility to ensure that
- the
UnsafeWorldCell
has permission to access the resource - no mutable reference to the resource exists at the same time
sourcepub unsafe fn get_non_send_resource_by_id(
self,
component_id: ComponentId
) -> Option<Ptr<'w>>
pub unsafe fn get_non_send_resource_by_id( self, component_id: ComponentId ) -> Option<Ptr<'w>>
Gets a !Send
resource to the resource with the id ComponentId
if it exists.
The returned pointer must not be used to modify the resource, and must not be
dereferenced after the immutable borrow of the World
ends.
You should prefer to use the typed API UnsafeWorldCell::get_non_send_resource
where possible and only
use this in cases where the actual types are not known at compile time.
Panics
This function will panic if it isn’t called from the same thread that the resource was inserted from.
Safety
It is the callers responsibility to ensure that
- the
UnsafeWorldCell
has permission to access the resource - no mutable reference to the resource exists at the same time
sourcepub unsafe fn get_resource_mut<R: Resource>(self) -> Option<Mut<'w, R>>
pub unsafe fn get_resource_mut<R: Resource>(self) -> Option<Mut<'w, R>>
Gets a mutable reference to the resource of the given type if it exists
Safety
It is the callers responsibility to ensure that
- the
UnsafeWorldCell
has permission to access the resource mutably - no other references to the resource exist at the same time
sourcepub unsafe fn get_resource_mut_by_id(
self,
component_id: ComponentId
) -> Option<MutUntyped<'w>>
pub unsafe fn get_resource_mut_by_id( self, component_id: ComponentId ) -> Option<MutUntyped<'w>>
Gets a pointer to the resource with the id ComponentId
if it exists.
The returned pointer may be used to modify the resource, as long as the mutable borrow
of the UnsafeWorldCell
is still valid.
You should prefer to use the typed API UnsafeWorldCell::get_resource_mut
where possible and only
use this in cases where the actual types are not known at compile time.
Safety
It is the callers responsibility to ensure that
- the
UnsafeWorldCell
has permission to access the resource mutably - no other references to the resource exist at the same time
sourcepub unsafe fn get_non_send_resource_mut<R: 'static>(self) -> Option<Mut<'w, R>>
pub unsafe fn get_non_send_resource_mut<R: 'static>(self) -> Option<Mut<'w, R>>
Gets a mutable reference to the non-send resource of the given type if it exists
Safety
It is the callers responsibility to ensure that
- the
UnsafeWorldCell
has permission to access the resource mutably - no other references to the resource exist at the same time
sourcepub unsafe fn get_non_send_resource_mut_by_id(
self,
component_id: ComponentId
) -> Option<MutUntyped<'w>>
pub unsafe fn get_non_send_resource_mut_by_id( self, component_id: ComponentId ) -> Option<MutUntyped<'w>>
Gets a !Send
resource to the resource with the id ComponentId
if it exists.
The returned pointer may be used to modify the resource, as long as the mutable borrow
of the World
is still valid.
You should prefer to use the typed API UnsafeWorldCell::get_non_send_resource_mut
where possible and only
use this in cases where the actual types are not known at compile time.
Panics
This function will panic if it isn’t called from the same thread that the resource was inserted from.
Safety
It is the callers responsibility to ensure that
- the
UnsafeWorldCell
has permission to access the resource mutably - no other references to the resource exist at the same time
Trait Implementations§
source§impl<'w> Clone for UnsafeWorldCell<'w>
impl<'w> Clone for UnsafeWorldCell<'w>
source§fn clone(&self) -> UnsafeWorldCell<'w>
fn clone(&self) -> UnsafeWorldCell<'w>
1.0.0 · source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source
. Read moresource§impl Debug for UnsafeWorldCell<'_>
impl Debug for UnsafeWorldCell<'_>
impl<'w> Copy for UnsafeWorldCell<'w>
impl Send for UnsafeWorldCell<'_>
impl Sync for UnsafeWorldCell<'_>
Auto Trait Implementations§
impl<'w> !RefUnwindSafe for UnsafeWorldCell<'w>
impl<'w> Unpin for UnsafeWorldCell<'w>
impl<'w> !UnwindSafe for UnsafeWorldCell<'w>
Blanket Implementations§
source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait>
(where Trait: Downcast
) to Box<dyn Any>
. Box<dyn Any>
can
then be further downcast
into Box<ConcreteType>
where ConcreteType
implements Trait
.source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait>
(where Trait: Downcast
) to Rc<Any>
. Rc<Any>
can then be
further downcast
into Rc<ConcreteType>
where ConcreteType
implements Trait
.source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &Any
’s vtable from &Trait
’s.source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &mut Any
’s vtable from &mut Trait
’s.