Struct valence::ecs::world::unsafe_world_cell::UnsafeWorldCell
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§
§impl<'w> UnsafeWorldCell<'w>
impl<'w> UnsafeWorldCell<'w>
pub unsafe fn into_deferred(self) -> DeferredWorld<'w>
pub unsafe fn into_deferred(self) -> DeferredWorld<'w>
Turn self into a DeferredWorld
§Safety
Caller must ensure there are no outstanding mutable references to world and no outstanding references to the world’s command queue, resource or component data
§impl<'w> UnsafeWorldCell<'w>
impl<'w> UnsafeWorldCell<'w>
pub 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();
pub 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
pub 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
pub fn archetypes(self) -> &'w Archetypes
pub fn archetypes(self) -> &'w Archetypes
Retrieves this world’s Archetypes
collection.
pub fn components(self) -> &'w Components
pub fn components(self) -> &'w Components
Retrieves this world’s Components
collection.
pub fn removed_components(self) -> &'w RemovedComponentEvents
pub fn removed_components(self) -> &'w RemovedComponentEvents
Retrieves this world’s collection of removed components.
pub fn change_tick(self) -> Tick
pub fn change_tick(self) -> Tick
Gets the current change tick of this world.
pub 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.
pub 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.
pub 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.
pub 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.
pub unsafe fn get_resource<R>(self) -> Option<&'w R>where
R: Resource,
pub unsafe fn get_resource<R>(self) -> Option<&'w R>where
R: Resource,
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
pub unsafe fn get_resource_ref<R>(self) -> Option<Res<'w, R>>where
R: Resource,
pub unsafe fn get_resource_ref<R>(self) -> Option<Res<'w, R>>where
R: Resource,
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
pub 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
pub unsafe fn get_non_send_resource<R>(self) -> Option<&'w R>where
R: 'static,
pub unsafe fn get_non_send_resource<R>(self) -> Option<&'w R>where
R: 'static,
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
pub 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
pub unsafe fn get_resource_mut<R>(self) -> Option<Mut<'w, R>>where
R: Resource,
pub unsafe fn get_resource_mut<R>(self) -> Option<Mut<'w, R>>where
R: Resource,
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
pub 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
pub unsafe fn get_non_send_resource_mut<R>(self) -> Option<Mut<'w, R>>where
R: 'static,
pub unsafe fn get_non_send_resource_mut<R>(self) -> Option<Mut<'w, R>>where
R: 'static,
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
pub 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§
§impl<'w> Clone for UnsafeWorldCell<'w>
impl<'w> Clone for UnsafeWorldCell<'w>
§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 more§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> Freeze for UnsafeWorldCell<'w>
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> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
source§unsafe fn clone_to_uninit(&self, dst: *mut T)
unsafe fn clone_to_uninit(&self, dst: *mut T)
clone_to_uninit
)§impl<T> Conv for T
impl<T> Conv for T
§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
§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
.§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
.§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.§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.§impl<T> DowncastSync for T
impl<T> DowncastSync for T
§impl<T> FmtForward for T
impl<T> FmtForward for T
§fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
self
to use its Binary
implementation when Debug
-formatted.§fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
self
to use its Display
implementation when
Debug
-formatted.§fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
self
to use its LowerExp
implementation when
Debug
-formatted.§fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
self
to use its LowerHex
implementation when
Debug
-formatted.§fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
self
to use its Octal
implementation when Debug
-formatted.§fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
self
to use its Pointer
implementation when
Debug
-formatted.§fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
self
to use its UpperExp
implementation when
Debug
-formatted.§fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
self
to use its UpperHex
implementation when
Debug
-formatted.§fn fmt_list(self) -> FmtList<Self>where
&'a Self: for<'a> IntoIterator,
fn fmt_list(self) -> FmtList<Self>where
&'a Self: for<'a> IntoIterator,
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
§impl<T> Pipe for Twhere
T: ?Sized,
impl<T> Pipe for Twhere
T: ?Sized,
§fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
§fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
self
and passes that borrow into the pipe function. Read more§fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
self
and passes that borrow into the pipe function. Read more§fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
§fn pipe_borrow_mut<'a, B, R>(
&'a mut self,
func: impl FnOnce(&'a mut B) -> R,
) -> R
fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
§fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
self
, then passes self.as_ref()
into the pipe function.§fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
self
, then passes self.as_mut()
into the pipe
function.§fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
self
, then passes self.deref()
into the pipe function.§impl<T> Tap for T
impl<T> Tap for T
§fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
Borrow<B>
of a value. Read more§fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
BorrowMut<B>
of a value. Read more§fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
AsRef<R>
view of a value. Read more§fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
AsMut<R>
view of a value. Read more§fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
Deref::Target
of a value. Read more§fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
Deref::Target
of a value. Read more§fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
.tap()
only in debug builds, and is erased in release builds.§fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
.tap_mut()
only in debug builds, and is erased in release
builds.§fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
.tap_borrow()
only in debug builds, and is erased in release
builds.§fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
.tap_borrow_mut()
only in debug builds, and is erased in release
builds.§fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
.tap_ref()
only in debug builds, and is erased in release
builds.§fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
.tap_ref_mut()
only in debug builds, and is erased in release
builds.§fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
.tap_deref()
only in debug builds, and is erased in release
builds.