mirror of
https://github.com/bevyengine/bevy
synced 2024-11-30 00:20:20 +00:00
Move all logic to UnsafeWorldCell
(#7381)
# Objective - Implementing logic used by system params and `UnsafeWorldCell` on `&World` is sus since `&World` generally denotes shared read only access to world but this is a lie in the above situations. Move most/all logic that uses `&World` to mean `UnsafeWorldCell` onto `UnsafeWorldCell` - Add a way to take a `&mut World` out of `UnsafeWorldCell` and use this in `WorldCell`'s `Drop` impl instead of a `UnsafeCell` field --- ## Changelog - changed some `UnsafeWorldCell` methods to take `self` instead of `&self`/`&mut self` since there is literally no point to them doing that - `UnsafeWorldCell::world` is now used to get immutable access to the whole world instead of just the metadata which can now be done via `UnsafeWorldCell::world_metadata` - `UnsafeWorldCell::world_mut` now exists and can be used to get a `&mut World` out of `UnsafeWorldCell` - removed `UnsafeWorldCell::storages` since that is probably unsound since storages contains the actual component/resource data not just metadata ## Migration guide N/A none of the breaking changes here make any difference for a 0.9->0.10 transition since `UnsafeWorldCell` did not exist in 0.9
This commit is contained in:
parent
aa4170d9a4
commit
5c680a38a7
5 changed files with 506 additions and 524 deletions
|
@ -446,6 +446,7 @@ unsafe impl<'a, T: Resource> SystemParam for Res<'a, T> {
|
|||
change_tick: u32,
|
||||
) -> Self::Item<'w, 's> {
|
||||
let (ptr, ticks) = world
|
||||
.as_unsafe_world_cell_migration_internal()
|
||||
.get_resource_with_ticks(component_id)
|
||||
.unwrap_or_else(|| {
|
||||
panic!(
|
||||
|
@ -486,6 +487,7 @@ unsafe impl<'a, T: Resource> SystemParam for Option<Res<'a, T>> {
|
|||
change_tick: u32,
|
||||
) -> Self::Item<'w, 's> {
|
||||
world
|
||||
.as_unsafe_world_cell_migration_internal()
|
||||
.get_resource_with_ticks(component_id)
|
||||
.map(|(ptr, ticks)| Res {
|
||||
value: ptr.deref(),
|
||||
|
@ -540,7 +542,7 @@ unsafe impl<'a, T: Resource> SystemParam for ResMut<'a, T> {
|
|||
) -> Self::Item<'w, 's> {
|
||||
let value = world
|
||||
.as_unsafe_world_cell_migration_internal()
|
||||
.get_resource_mut_with_id(component_id)
|
||||
.get_resource_mut_by_id(component_id)
|
||||
.unwrap_or_else(|| {
|
||||
panic!(
|
||||
"Resource requested by {} does not exist: {}",
|
||||
|
@ -549,7 +551,7 @@ unsafe impl<'a, T: Resource> SystemParam for ResMut<'a, T> {
|
|||
)
|
||||
});
|
||||
ResMut {
|
||||
value: value.value,
|
||||
value: value.value.deref_mut::<T>(),
|
||||
ticks: TicksMut {
|
||||
added: value.ticks.added,
|
||||
changed: value.ticks.changed,
|
||||
|
@ -578,9 +580,9 @@ unsafe impl<'a, T: Resource> SystemParam for Option<ResMut<'a, T>> {
|
|||
) -> Self::Item<'w, 's> {
|
||||
world
|
||||
.as_unsafe_world_cell_migration_internal()
|
||||
.get_resource_mut_with_id(component_id)
|
||||
.get_resource_mut_by_id(component_id)
|
||||
.map(|value| ResMut {
|
||||
value: value.value,
|
||||
value: value.value.deref_mut::<T>(),
|
||||
ticks: TicksMut {
|
||||
added: value.ticks.added,
|
||||
changed: value.ticks.changed,
|
||||
|
@ -889,6 +891,7 @@ unsafe impl<'a, T: 'static> SystemParam for NonSend<'a, T> {
|
|||
change_tick: u32,
|
||||
) -> Self::Item<'w, 's> {
|
||||
let (ptr, ticks) = world
|
||||
.as_unsafe_world_cell_migration_internal()
|
||||
.get_non_send_with_ticks(component_id)
|
||||
.unwrap_or_else(|| {
|
||||
panic!(
|
||||
|
@ -927,6 +930,7 @@ unsafe impl<T: 'static> SystemParam for Option<NonSend<'_, T>> {
|
|||
change_tick: u32,
|
||||
) -> Self::Item<'w, 's> {
|
||||
world
|
||||
.as_unsafe_world_cell_migration_internal()
|
||||
.get_non_send_with_ticks(component_id)
|
||||
.map(|(ptr, ticks)| NonSend {
|
||||
value: ptr.deref(),
|
||||
|
@ -979,6 +983,7 @@ unsafe impl<'a, T: 'static> SystemParam for NonSendMut<'a, T> {
|
|||
change_tick: u32,
|
||||
) -> Self::Item<'w, 's> {
|
||||
let (ptr, ticks) = world
|
||||
.as_unsafe_world_cell_migration_internal()
|
||||
.get_non_send_with_ticks(component_id)
|
||||
.unwrap_or_else(|| {
|
||||
panic!(
|
||||
|
@ -1011,6 +1016,7 @@ unsafe impl<'a, T: 'static> SystemParam for Option<NonSendMut<'a, T>> {
|
|||
change_tick: u32,
|
||||
) -> Self::Item<'w, 's> {
|
||||
world
|
||||
.as_unsafe_world_cell_migration_internal()
|
||||
.get_non_send_with_ticks(component_id)
|
||||
.map(|(ptr, ticks)| NonSendMut {
|
||||
value: ptr.assert_unique().deref_mut(),
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
use crate::{
|
||||
archetype::{Archetype, ArchetypeId, Archetypes},
|
||||
bundle::{Bundle, BundleInfo},
|
||||
change_detection::{MutUntyped, TicksMut},
|
||||
component::{
|
||||
Component, ComponentId, ComponentStorage, ComponentTicks, Components, StorageType,
|
||||
},
|
||||
change_detection::MutUntyped,
|
||||
component::{Component, ComponentId, ComponentTicks, Components, StorageType},
|
||||
entity::{Entities, Entity, EntityLocation},
|
||||
removal_detection::RemovedComponentEvents,
|
||||
storage::Storages,
|
||||
|
@ -79,12 +77,14 @@ impl<'w> EntityRef<'w> {
|
|||
|
||||
#[inline]
|
||||
pub fn contains_id(&self, component_id: ComponentId) -> bool {
|
||||
contains_component_with_id(self.world, component_id, self.location)
|
||||
self.as_unsafe_world_cell_readonly()
|
||||
.contains_id(component_id)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn contains_type_id(&self, type_id: TypeId) -> bool {
|
||||
contains_component_with_type(self.world, type_id, self.location)
|
||||
self.as_unsafe_world_cell_readonly()
|
||||
.contains_type_id(type_id)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -209,12 +209,14 @@ impl<'w> EntityMut<'w> {
|
|||
|
||||
#[inline]
|
||||
pub fn contains_id(&self, component_id: ComponentId) -> bool {
|
||||
contains_component_with_id(self.world, component_id, self.location)
|
||||
self.as_unsafe_world_cell_readonly()
|
||||
.contains_id(component_id)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn contains_type_id(&self, type_id: TypeId) -> bool {
|
||||
contains_component_with_type(self.world, type_id, self.location)
|
||||
self.as_unsafe_world_cell_readonly()
|
||||
.contains_type_id(type_id)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -600,19 +602,10 @@ impl<'w> EntityMut<'w> {
|
|||
/// which is only valid while the [`EntityMut`] is alive.
|
||||
#[inline]
|
||||
pub fn get_by_id(&self, component_id: ComponentId) -> Option<Ptr<'_>> {
|
||||
let info = self.world.components().get_info(component_id)?;
|
||||
// SAFETY:
|
||||
// - entity_location is valid
|
||||
// - component_id is valid as checked by the line above
|
||||
// - the storage type is accurate as checked by the fetched ComponentInfo
|
||||
unsafe {
|
||||
self.world.get_component(
|
||||
component_id,
|
||||
info.storage_type(),
|
||||
self.entity,
|
||||
self.location,
|
||||
)
|
||||
}
|
||||
// - `&self` ensures that no mutable references exist to this entity's components.
|
||||
// - `as_unsafe_world_cell_readonly` gives read only permission for all components on this entity
|
||||
unsafe { self.as_unsafe_world_cell_readonly().get_by_id(component_id) }
|
||||
}
|
||||
|
||||
/// Gets a [`MutUntyped`] of the component of the given [`ComponentId`] from the entity.
|
||||
|
@ -625,32 +618,13 @@ impl<'w> EntityMut<'w> {
|
|||
/// which is only valid while the [`EntityMut`] is alive.
|
||||
#[inline]
|
||||
pub fn get_mut_by_id(&mut self, component_id: ComponentId) -> Option<MutUntyped<'_>> {
|
||||
self.world.components().get_info(component_id)?;
|
||||
// SAFETY: entity_location is valid, component_id is valid as checked by the line above
|
||||
unsafe { get_mut_by_id(self.world, self.entity, self.location, component_id) }
|
||||
// SAFETY:
|
||||
// - `&mut self` ensures that no references exist to this entity's components.
|
||||
// - `as_unsafe_world_cell` gives mutable permission for all components on this entity
|
||||
unsafe { self.as_unsafe_world_cell().get_mut_by_id(component_id) }
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn contains_component_with_type(
|
||||
world: &World,
|
||||
type_id: TypeId,
|
||||
location: EntityLocation,
|
||||
) -> bool {
|
||||
if let Some(component_id) = world.components.get_id(type_id) {
|
||||
contains_component_with_id(world, component_id, location)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn contains_component_with_id(
|
||||
world: &World,
|
||||
component_id: ComponentId,
|
||||
location: EntityLocation,
|
||||
) -> bool {
|
||||
world.archetypes[location.archetype_id].contains(component_id)
|
||||
}
|
||||
|
||||
/// Removes a bundle from the given archetype and returns the resulting archetype (or None if the
|
||||
/// removal was invalid). in the event that adding the given bundle does not result in an Archetype
|
||||
/// change. Results are cached in the Archetype Graph to avoid redundant work.
|
||||
|
@ -768,59 +742,6 @@ fn sorted_remove<T: Eq + Ord + Copy>(source: &mut Vec<T>, remove: &[T]) {
|
|||
});
|
||||
}
|
||||
|
||||
// SAFETY: EntityLocation must be valid
|
||||
#[inline]
|
||||
pub(crate) unsafe fn get_mut<T: Component>(
|
||||
world: &mut World,
|
||||
entity: Entity,
|
||||
location: EntityLocation,
|
||||
) -> Option<Mut<'_, T>> {
|
||||
let change_tick = world.change_tick();
|
||||
let last_change_tick = world.last_change_tick();
|
||||
// SAFETY:
|
||||
// - world access is unique
|
||||
// - entity location is valid
|
||||
// - returned component is of type T
|
||||
world
|
||||
.get_component_and_ticks_with_type(
|
||||
TypeId::of::<T>(),
|
||||
T::Storage::STORAGE_TYPE,
|
||||
entity,
|
||||
location,
|
||||
)
|
||||
.map(|(value, ticks)| Mut {
|
||||
// SAFETY:
|
||||
// - world access is unique and ties world lifetime to `Mut` lifetime
|
||||
// - `value` is of type `T`
|
||||
value: value.assert_unique().deref_mut::<T>(),
|
||||
ticks: TicksMut::from_tick_cells(ticks, last_change_tick, change_tick),
|
||||
})
|
||||
}
|
||||
|
||||
// SAFETY: EntityLocation must be valid, component_id must be valid
|
||||
#[inline]
|
||||
pub(crate) unsafe fn get_mut_by_id(
|
||||
world: &mut World,
|
||||
entity: Entity,
|
||||
location: EntityLocation,
|
||||
component_id: ComponentId,
|
||||
) -> Option<MutUntyped<'_>> {
|
||||
let change_tick = world.change_tick();
|
||||
// SAFETY: component_id is valid
|
||||
let info = world.components.get_info_unchecked(component_id);
|
||||
// SAFETY:
|
||||
// - world access is unique
|
||||
// - entity location is valid
|
||||
// - returned component is of type T
|
||||
world
|
||||
.get_component_and_ticks(component_id, info.storage_type(), entity, location)
|
||||
.map(|(value, ticks)| MutUntyped {
|
||||
// SAFETY: world access is unique and ties world lifetime to `MutUntyped` lifetime
|
||||
value: value.assert_unique(),
|
||||
ticks: TicksMut::from_tick_cells(ticks, world.last_change_tick(), change_tick),
|
||||
})
|
||||
}
|
||||
|
||||
/// Moves component data out of storage.
|
||||
///
|
||||
/// This function leaves the underlying memory unchanged, but the component behind
|
||||
|
|
|
@ -12,23 +12,19 @@ use crate::{
|
|||
archetype::{ArchetypeComponentId, ArchetypeId, ArchetypeRow, Archetypes},
|
||||
bundle::{Bundle, BundleInserter, BundleSpawner, Bundles},
|
||||
change_detection::{MutUntyped, TicksMut},
|
||||
component::{
|
||||
Component, ComponentDescriptor, ComponentId, ComponentInfo, ComponentTicks, Components,
|
||||
StorageType, TickCells,
|
||||
},
|
||||
component::{Component, ComponentDescriptor, ComponentId, ComponentInfo, Components},
|
||||
entity::{AllocAtWithoutReplacement, Entities, Entity, EntityLocation},
|
||||
event::{Event, Events},
|
||||
query::{DebugCheckedUnwrap, QueryState, ReadOnlyWorldQuery, WorldQuery},
|
||||
removal_detection::RemovedComponentEvents,
|
||||
schedule::{Schedule, ScheduleLabel, Schedules},
|
||||
storage::{Column, ComponentSparseSet, ResourceData, Storages, TableRow},
|
||||
storage::{ResourceData, Storages},
|
||||
system::Resource,
|
||||
};
|
||||
use bevy_ptr::{OwningPtr, Ptr};
|
||||
use bevy_utils::tracing::warn;
|
||||
use std::{
|
||||
any::TypeId,
|
||||
cell::UnsafeCell,
|
||||
fmt,
|
||||
sync::atomic::{AtomicU32, Ordering},
|
||||
};
|
||||
|
@ -66,7 +62,7 @@ pub struct World {
|
|||
pub(crate) bundles: Bundles,
|
||||
pub(crate) removed_components: RemovedComponentEvents,
|
||||
/// Access cache used by [WorldCell]. Is only accessed in the `Drop` impl of `WorldCell`.
|
||||
pub(crate) archetype_component_access: UnsafeCell<ArchetypeComponentAccess>,
|
||||
pub(crate) archetype_component_access: ArchetypeComponentAccess,
|
||||
pub(crate) change_tick: AtomicU32,
|
||||
pub(crate) last_change_tick: u32,
|
||||
pub(crate) last_check_tick: u32,
|
||||
|
@ -112,19 +108,19 @@ impl World {
|
|||
|
||||
/// Creates a new [`UnsafeWorldCell`] view with complete read+write access.
|
||||
pub fn as_unsafe_world_cell(&mut self) -> UnsafeWorldCell<'_> {
|
||||
UnsafeWorldCell::new(self)
|
||||
UnsafeWorldCell::new_mutable(self)
|
||||
}
|
||||
|
||||
/// Creates a new [`UnsafeWorldCell`] view with only read access to everything.
|
||||
pub fn as_unsafe_world_cell_readonly(&self) -> UnsafeWorldCell<'_> {
|
||||
UnsafeWorldCell::new(self)
|
||||
UnsafeWorldCell::new_readonly(self)
|
||||
}
|
||||
|
||||
/// Creates a new [`UnsafeWorldCell`] with read+write access from a [&World](World).
|
||||
/// This is only a temporary measure until every `&World` that is semantically a [`UnsafeWorldCell`]
|
||||
/// has been replaced.
|
||||
pub(crate) fn as_unsafe_world_cell_migration_internal(&self) -> UnsafeWorldCell<'_> {
|
||||
UnsafeWorldCell::new(self)
|
||||
UnsafeWorldCell::new_readonly(self)
|
||||
}
|
||||
|
||||
/// Retrieves this world's [Entities] collection
|
||||
|
@ -602,9 +598,10 @@ impl World {
|
|||
#[inline]
|
||||
pub fn get_mut<T: Component>(&mut self, entity: Entity) -> Option<Mut<T>> {
|
||||
// SAFETY:
|
||||
// - lifetimes enforce correct usage of returned borrow
|
||||
// - entity location is checked in `get_entity`
|
||||
unsafe { entity_ref::get_mut(self, entity, self.get_entity(entity)?.location()) }
|
||||
// - `as_unsafe_world_cell` is the only thing that is borrowing world
|
||||
// - `as_unsafe_world_cell` provides mutable permission to everything
|
||||
// - `&mut self` ensures no other borrows on world data
|
||||
unsafe { self.as_unsafe_world_cell().get_entity(entity)?.get_mut() }
|
||||
}
|
||||
|
||||
/// Despawns the given `entity`, if it exists. This will also remove all of the entity's
|
||||
|
@ -1005,15 +1002,18 @@ impl World {
|
|||
/// Gets a reference to the resource of the given type if it exists
|
||||
#[inline]
|
||||
pub fn get_resource<R: Resource>(&self) -> Option<&R> {
|
||||
let component_id = self.components.get_resource_id(TypeId::of::<R>())?;
|
||||
// SAFETY: `component_id` was obtained from the type ID of `R`.
|
||||
unsafe { self.get_resource_with_id(component_id) }
|
||||
// SAFETY:
|
||||
// - `as_unsafe_world_cell_readonly` gives permission to access everything immutably
|
||||
// - `&self` ensures nothing in world is borrowed immutably
|
||||
unsafe { self.as_unsafe_world_cell_readonly().get_resource() }
|
||||
}
|
||||
|
||||
/// Gets a mutable reference to the resource of the given type if it exists
|
||||
#[inline]
|
||||
pub fn get_resource_mut<R: Resource>(&mut self) -> Option<Mut<'_, R>> {
|
||||
// SAFETY: unique world access
|
||||
// SAFETY:
|
||||
// - `as_unsafe_world_cell` gives permission to access everything mutably
|
||||
// - `&mut self` ensures nothing in world is borrowed
|
||||
unsafe { self.as_unsafe_world_cell().get_resource_mut() }
|
||||
}
|
||||
|
||||
|
@ -1098,9 +1098,10 @@ impl World {
|
|||
/// This function will panic if it isn't called from the same thread that the resource was inserted from.
|
||||
#[inline]
|
||||
pub fn get_non_send_resource<R: 'static>(&self) -> Option<&R> {
|
||||
let component_id = self.components.get_resource_id(TypeId::of::<R>())?;
|
||||
// SAFETY: component id matches type T
|
||||
unsafe { self.get_non_send_with_id(component_id) }
|
||||
// SAFETY:
|
||||
// - `as_unsafe_world_cell_readonly` gives permission to access the entire world immutably
|
||||
// - `&self` ensures that there are no mutable borrows of world data
|
||||
unsafe { self.as_unsafe_world_cell_readonly().get_non_send_resource() }
|
||||
}
|
||||
|
||||
/// Gets a mutable reference to the non-send resource of the given type, if it exists.
|
||||
|
@ -1110,34 +1111,12 @@ impl World {
|
|||
/// This function will panic if it isn't called from the same thread that the resource was inserted from.
|
||||
#[inline]
|
||||
pub fn get_non_send_resource_mut<R: 'static>(&mut self) -> Option<Mut<'_, R>> {
|
||||
// SAFETY: unique world access
|
||||
// SAFETY:
|
||||
// - `as_unsafe_world_cell` gives permission to access the entire world mutably
|
||||
// - `&mut self` ensures that there are no borrows of world data
|
||||
unsafe { self.as_unsafe_world_cell().get_non_send_resource_mut() }
|
||||
}
|
||||
|
||||
// Shorthand helper function for getting the data and change ticks for a resource.
|
||||
#[inline]
|
||||
pub(crate) fn get_resource_with_ticks(
|
||||
&self,
|
||||
component_id: ComponentId,
|
||||
) -> Option<(Ptr<'_>, TickCells<'_>)> {
|
||||
self.storages.resources.get(component_id)?.get_with_ticks()
|
||||
}
|
||||
|
||||
// Shorthand helper function for getting the data and change ticks for a resource.
|
||||
///
|
||||
/// # Panics
|
||||
/// This function will panic if it isn't called from the same thread that the resource was inserted from.
|
||||
#[inline]
|
||||
pub(crate) fn get_non_send_with_ticks(
|
||||
&self,
|
||||
component_id: ComponentId,
|
||||
) -> Option<(Ptr<'_>, TickCells<'_>)> {
|
||||
self.storages
|
||||
.non_send_resources
|
||||
.get(component_id)?
|
||||
.get_with_ticks()
|
||||
}
|
||||
|
||||
// Shorthand helper function for getting the [`ArchetypeComponentId`] for a resource.
|
||||
#[inline]
|
||||
pub(crate) fn get_resource_archetype_component_id(
|
||||
|
@ -1380,36 +1359,6 @@ impl World {
|
|||
}
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
/// `component_id` must be assigned to a component of type `R`
|
||||
#[inline]
|
||||
pub(crate) unsafe fn get_resource_with_id<R: 'static>(
|
||||
&self,
|
||||
component_id: ComponentId,
|
||||
) -> Option<&R> {
|
||||
self.storages
|
||||
.resources
|
||||
.get(component_id)?
|
||||
.get_data()
|
||||
.map(|ptr| ptr.deref())
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
/// `component_id` must be assigned to a component of type `R`
|
||||
#[inline]
|
||||
pub(crate) unsafe fn get_non_send_with_id<R: 'static>(
|
||||
&self,
|
||||
component_id: ComponentId,
|
||||
) -> Option<&R> {
|
||||
Some(
|
||||
self.storages
|
||||
.non_send_resources
|
||||
.get(component_id)?
|
||||
.get_data()?
|
||||
.deref::<R>(),
|
||||
)
|
||||
}
|
||||
|
||||
/// Inserts a new resource with the given `value`. Will replace the value if it already existed.
|
||||
///
|
||||
/// **You should prefer to use the typed API [`World::insert_resource`] where possible and only
|
||||
|
@ -1616,7 +1565,13 @@ impl World {
|
|||
/// use this in cases where the actual types are not known at compile time.**
|
||||
#[inline]
|
||||
pub fn get_resource_by_id(&self, component_id: ComponentId) -> Option<Ptr<'_>> {
|
||||
self.storages.resources.get(component_id)?.get_data()
|
||||
// SAFETY:
|
||||
// - `as_unsafe_world_cell_readonly` gives permission to access the whole world immutably
|
||||
// - `&self` ensures there are no mutable borrows on world data
|
||||
unsafe {
|
||||
self.as_unsafe_world_cell_readonly()
|
||||
.get_resource_by_id(component_id)
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets a pointer to the resource with the id [`ComponentId`] if it exists.
|
||||
|
@ -1627,7 +1582,9 @@ impl World {
|
|||
/// use this in cases where the actual types are not known at compile time.**
|
||||
#[inline]
|
||||
pub fn get_resource_mut_by_id(&mut self, component_id: ComponentId) -> Option<MutUntyped<'_>> {
|
||||
// SAFETY: unique world access
|
||||
// SAFETY:
|
||||
// - `&mut self` ensures that all accessed data is unaliased
|
||||
// - `as_unsafe_world_cell` provides mutable permission to the whole world
|
||||
unsafe {
|
||||
self.as_unsafe_world_cell()
|
||||
.get_resource_mut_by_id(component_id)
|
||||
|
@ -1645,10 +1602,13 @@ impl World {
|
|||
/// This function will panic if it isn't called from the same thread that the resource was inserted from.
|
||||
#[inline]
|
||||
pub fn get_non_send_by_id(&self, component_id: ComponentId) -> Option<Ptr<'_>> {
|
||||
self.storages
|
||||
.non_send_resources
|
||||
.get(component_id)?
|
||||
.get_data()
|
||||
// SAFETY:
|
||||
// - `as_unsafe_world_cell_readonly` gives permission to access the whole world immutably
|
||||
// - `&self` ensures there are no mutable borrows on world data
|
||||
unsafe {
|
||||
self.as_unsafe_world_cell_readonly()
|
||||
.get_non_send_resource_by_id(component_id)
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets a `!Send` resource to the resource with the id [`ComponentId`] if it exists.
|
||||
|
@ -1662,20 +1622,13 @@ impl World {
|
|||
/// This function will panic if it isn't called from the same thread that the resource was inserted from.
|
||||
#[inline]
|
||||
pub fn get_non_send_mut_by_id(&mut self, component_id: ComponentId) -> Option<MutUntyped<'_>> {
|
||||
let change_tick = self.change_tick();
|
||||
let (ptr, ticks) = self.get_non_send_with_ticks(component_id)?;
|
||||
|
||||
let ticks =
|
||||
// SAFETY: This function has exclusive access to the world so nothing aliases `ticks`.
|
||||
// - index is in-bounds because the column is initialized and non-empty
|
||||
// - no other reference to the ticks of the same row can exist at the same time
|
||||
unsafe { TicksMut::from_tick_cells(ticks, self.last_change_tick(), change_tick) };
|
||||
|
||||
Some(MutUntyped {
|
||||
// SAFETY: This function has exclusive access to the world so nothing aliases `ptr`.
|
||||
value: unsafe { ptr.assert_unique() },
|
||||
ticks,
|
||||
})
|
||||
// SAFETY:
|
||||
// - `&mut self` ensures that all accessed data is unaliased
|
||||
// - `as_unsafe_world_cell` provides mutable permission to the whole world
|
||||
unsafe {
|
||||
self.as_unsafe_world_cell()
|
||||
.get_non_send_resource_mut_by_id(component_id)
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes the resource of a given type, if it exists. Otherwise returns [None].
|
||||
|
@ -1715,18 +1668,13 @@ impl World {
|
|||
/// This function will panic if it isn't called from the same thread that the resource was inserted from.
|
||||
#[inline]
|
||||
pub fn get_by_id(&self, entity: Entity, component_id: ComponentId) -> Option<Ptr<'_>> {
|
||||
let info = self.components().get_info(component_id)?;
|
||||
// SAFETY:
|
||||
// - entity_location is valid
|
||||
// - component_id is valid as checked by the line above
|
||||
// - the storage type is accurate as checked by the fetched ComponentInfo
|
||||
// - `&self` ensures that all accessed data is not mutably aliased
|
||||
// - `as_unsafe_world_cell_readonly` provides shared/readonly permission to the whole world
|
||||
unsafe {
|
||||
self.get_component(
|
||||
component_id,
|
||||
info.storage_type(),
|
||||
entity,
|
||||
self.get_entity(entity)?.location(),
|
||||
)
|
||||
self.as_unsafe_world_cell_readonly()
|
||||
.get_entity(entity)?
|
||||
.get_by_id(component_id)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1741,183 +1689,17 @@ impl World {
|
|||
entity: Entity,
|
||||
component_id: ComponentId,
|
||||
) -> Option<MutUntyped<'_>> {
|
||||
self.components().get_info(component_id)?;
|
||||
// SAFETY: entity_location is valid, component_id is valid as checked by the line above
|
||||
// SAFETY:
|
||||
// - `&mut self` ensures that all accessed data is unaliased
|
||||
// - `as_unsafe_world_cell` provides mutable permission to the whole world
|
||||
unsafe {
|
||||
entity_ref::get_mut_by_id(
|
||||
self,
|
||||
entity,
|
||||
self.get_entity(entity)?.location(),
|
||||
component_id,
|
||||
)
|
||||
self.as_unsafe_world_cell()
|
||||
.get_entity(entity)?
|
||||
.get_mut_by_id(component_id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl World {
|
||||
/// Get an untyped pointer to a particular [`Component`](crate::component::Component) and its [`ComponentTicks`] identified by their [`TypeId`]
|
||||
///
|
||||
/// # Safety
|
||||
/// - `storage_type` must accurately reflect where the components for `component_id` are stored.
|
||||
/// - `location` must refer to an archetype that contains `entity`
|
||||
/// - the caller must ensure that no aliasing rules are violated
|
||||
#[inline]
|
||||
pub(crate) unsafe fn get_component_and_ticks_with_type(
|
||||
&self,
|
||||
type_id: TypeId,
|
||||
storage_type: StorageType,
|
||||
entity: Entity,
|
||||
location: EntityLocation,
|
||||
) -> Option<(Ptr<'_>, TickCells<'_>)> {
|
||||
let component_id = self.components.get_id(type_id)?;
|
||||
// SAFETY: component_id is valid, the rest is deferred to caller
|
||||
self.get_component_and_ticks(component_id, storage_type, entity, location)
|
||||
}
|
||||
|
||||
/// Get an untyped pointer to a particular [`Component`](crate::component::Component) and its [`ComponentTicks`]
|
||||
///
|
||||
/// # Safety
|
||||
/// - `location` must refer to an archetype that contains `entity`
|
||||
/// - `component_id` must be valid
|
||||
/// - `storage_type` must accurately reflect where the components for `component_id` are stored.
|
||||
/// - the caller must ensure that no aliasing rules are violated
|
||||
#[inline]
|
||||
pub(crate) unsafe fn get_component_and_ticks(
|
||||
&self,
|
||||
component_id: ComponentId,
|
||||
storage_type: StorageType,
|
||||
entity: Entity,
|
||||
location: EntityLocation,
|
||||
) -> Option<(Ptr<'_>, TickCells<'_>)> {
|
||||
match storage_type {
|
||||
StorageType::Table => {
|
||||
let (components, table_row) = self.fetch_table(location, component_id)?;
|
||||
|
||||
// SAFETY: archetypes only store valid table_rows and caller ensure aliasing rules
|
||||
Some((
|
||||
components.get_data_unchecked(table_row),
|
||||
TickCells {
|
||||
added: components.get_added_ticks_unchecked(table_row),
|
||||
changed: components.get_changed_ticks_unchecked(table_row),
|
||||
},
|
||||
))
|
||||
}
|
||||
StorageType::SparseSet => self.fetch_sparse_set(component_id)?.get_with_ticks(entity),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get an untyped pointer to a particular [`Component`](crate::component::Component) on a particular [`Entity`], identified by the component's type
|
||||
///
|
||||
/// # Safety
|
||||
/// - `location` must refer to an archetype that contains `entity`
|
||||
/// the archetype
|
||||
/// - `storage_type` must accurately reflect where the components for `component_id` are stored.
|
||||
/// - the caller must ensure that no aliasing rules are violated
|
||||
#[inline]
|
||||
pub(crate) unsafe fn get_component_with_type(
|
||||
&self,
|
||||
type_id: TypeId,
|
||||
storage_type: StorageType,
|
||||
entity: Entity,
|
||||
location: EntityLocation,
|
||||
) -> Option<Ptr<'_>> {
|
||||
let component_id = self.components.get_id(type_id)?;
|
||||
// SAFETY: component_id is valid, the rest is deferred to caller
|
||||
self.get_component(component_id, storage_type, entity, location)
|
||||
}
|
||||
|
||||
/// Get an untyped pointer to a particular [`Component`](crate::component::Component) on a particular [`Entity`] in the provided [`World`](crate::world::World).
|
||||
///
|
||||
/// # Safety
|
||||
/// - `location` must refer to an archetype that contains `entity`
|
||||
/// the archetype
|
||||
/// - `component_id` must be valid
|
||||
/// - `storage_type` must accurately reflect where the components for `component_id` are stored.
|
||||
/// - the caller must ensure that no aliasing rules are violated
|
||||
#[inline]
|
||||
pub(crate) unsafe fn get_component(
|
||||
&self,
|
||||
component_id: ComponentId,
|
||||
storage_type: StorageType,
|
||||
entity: Entity,
|
||||
location: EntityLocation,
|
||||
) -> Option<Ptr<'_>> {
|
||||
// SAFETY: component_id exists and is therefore valid
|
||||
match storage_type {
|
||||
StorageType::Table => {
|
||||
let (components, table_row) = self.fetch_table(location, component_id)?;
|
||||
// SAFETY: archetypes only store valid table_rows and caller ensure aliasing rules
|
||||
Some(components.get_data_unchecked(table_row))
|
||||
}
|
||||
StorageType::SparseSet => self.fetch_sparse_set(component_id)?.get(entity),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get an untyped pointer to the [`ComponentTicks`] on a particular [`Entity`], identified by the component's [`TypeId`]
|
||||
///
|
||||
/// # Safety
|
||||
/// - `location` must refer to an archetype that contains `entity`
|
||||
/// the archetype
|
||||
/// - `storage_type` must accurately reflect where the components for `component_id` are stored.
|
||||
/// - the caller must ensure that no aliasing rules are violated
|
||||
#[inline]
|
||||
pub(crate) unsafe fn get_ticks_with_type(
|
||||
&self,
|
||||
type_id: TypeId,
|
||||
storage_type: StorageType,
|
||||
entity: Entity,
|
||||
location: EntityLocation,
|
||||
) -> Option<ComponentTicks> {
|
||||
let component_id = self.components.get_id(type_id)?;
|
||||
// SAFETY: component_id is valid, the rest is deferred to caller
|
||||
self.get_ticks(component_id, storage_type, entity, location)
|
||||
}
|
||||
|
||||
/// Get an untyped pointer to the [`ComponentTicks`] on a particular [`Entity`]
|
||||
///
|
||||
/// # Safety
|
||||
/// - `location` must refer to an archetype that contains `entity`
|
||||
/// the archetype
|
||||
/// - `component_id` must be valid
|
||||
/// - `storage_type` must accurately reflect where the components for `component_id` are stored.
|
||||
/// - the caller must ensure that no aliasing rules are violated
|
||||
#[inline]
|
||||
pub(crate) unsafe fn get_ticks(
|
||||
&self,
|
||||
component_id: ComponentId,
|
||||
storage_type: StorageType,
|
||||
entity: Entity,
|
||||
location: EntityLocation,
|
||||
) -> Option<ComponentTicks> {
|
||||
match storage_type {
|
||||
StorageType::Table => {
|
||||
let (components, table_row) = self.fetch_table(location, component_id)?;
|
||||
// SAFETY: archetypes only store valid table_rows and caller ensure aliasing rules
|
||||
Some(components.get_ticks_unchecked(table_row))
|
||||
}
|
||||
StorageType::SparseSet => self.fetch_sparse_set(component_id)?.get_ticks(entity),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn fetch_table(
|
||||
&self,
|
||||
location: EntityLocation,
|
||||
component_id: ComponentId,
|
||||
) -> Option<(&Column, TableRow)> {
|
||||
let archetype = &self.archetypes[location.archetype_id];
|
||||
let table = &self.storages.tables[archetype.table_id()];
|
||||
let components = table.get_column(component_id)?;
|
||||
let table_row = archetype.entity_table_row(location.archetype_row);
|
||||
Some((components, table_row))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn fetch_sparse_set(&self, component_id: ComponentId) -> Option<&ComponentSparseSet> {
|
||||
self.storages.sparse_sets.get(component_id)
|
||||
}
|
||||
}
|
||||
|
||||
// Schedule-related methods
|
||||
impl World {
|
||||
/// Runs the [`Schedule`] associated with the `label` a single time.
|
||||
|
|
|
@ -1,18 +1,20 @@
|
|||
#![warn(unsafe_op_in_unsafe_fn)]
|
||||
|
||||
use super::{entity_ref, Mut, World};
|
||||
use super::{Mut, World};
|
||||
use crate::{
|
||||
archetype::{Archetype, Archetypes},
|
||||
archetype::{Archetype, ArchetypeComponentId, Archetypes},
|
||||
bundle::Bundles,
|
||||
change_detection::{MutUntyped, TicksMut},
|
||||
component::{ComponentId, ComponentStorage, ComponentTicks, Components},
|
||||
component::{
|
||||
ComponentId, ComponentStorage, ComponentTicks, Components, StorageType, TickCells,
|
||||
},
|
||||
entity::{Entities, Entity, EntityLocation},
|
||||
prelude::Component,
|
||||
storage::Storages,
|
||||
storage::{Column, ComponentSparseSet, TableRow},
|
||||
system::Resource,
|
||||
};
|
||||
use bevy_ptr::Ptr;
|
||||
use std::any::TypeId;
|
||||
use std::{any::TypeId, cell::UnsafeCell, marker::PhantomData, sync::atomic::Ordering};
|
||||
|
||||
/// 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.
|
||||
|
@ -70,75 +72,177 @@ use std::any::TypeId;
|
|||
/// }
|
||||
/// ```
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct UnsafeWorldCell<'w>(&'w World);
|
||||
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<'_> {}
|
||||
|
||||
impl<'w> UnsafeWorldCell<'w> {
|
||||
pub(crate) fn new(world: &'w World) -> Self {
|
||||
UnsafeWorldCell(world)
|
||||
/// Creates a [`UnsafeWorldCell`] that can be used to access everything immutably
|
||||
pub(crate) fn new_readonly(world: &'w World) -> Self {
|
||||
UnsafeWorldCell(world as *const World as *mut World, PhantomData)
|
||||
}
|
||||
|
||||
/// Creates [`UnsafeWorldCell`] that can be used to access everything mutably
|
||||
pub(crate) fn new_mutable(world: &'w mut World) -> Self {
|
||||
Self(world as *mut World, PhantomData)
|
||||
}
|
||||
|
||||
/// This `&mut World` counts as a mutable borrow of every resource and component for the purposes
|
||||
/// of safety invariants that talk about borrows on component/resource data not existing. This is
|
||||
/// true even for methods that do not explicitly call out `&mut World` as problematic.
|
||||
///
|
||||
/// # Safety
|
||||
/// - must have permission to access everything mutably
|
||||
/// - there must be no other borrows on world
|
||||
/// - returned borrow must not be used in any way if the world is accessed
|
||||
/// through other means than the `&mut World` after this call.
|
||||
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 }
|
||||
}
|
||||
|
||||
/// Gets a reference to the [`&World`](crate::world::World) this [`UnsafeWorldCell`] belongs to.
|
||||
/// This can be used to call methods like [`World::contains_resource`] which aren't exposed and but don't perform any accesses.
|
||||
///
|
||||
/// **Note**: You *must not* hand out a `&World` reference to arbitrary safe code when the [`UnsafeWorldCell`] is currently
|
||||
/// being used for mutable accesses.
|
||||
/// This can be used for arbitrary shared/readonly access.
|
||||
///
|
||||
/// # Safety
|
||||
/// - the world must not be used to access any resources or components. You can use it to safely access metadata.
|
||||
/// - 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(self) -> &'w World {
|
||||
self.0
|
||||
// SAFETY:
|
||||
// - 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 }
|
||||
}
|
||||
|
||||
/// 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 unsafe fn world_metadata(self) -> &'w World {
|
||||
// SAFETY: caller ensures that returned reference is not used to violate aliasing rules
|
||||
unsafe { self.unsafe_world() }
|
||||
}
|
||||
|
||||
/// Variant on [`UnsafeWorldCell::world`] solely used for implementing this type's methods.
|
||||
/// It allows having an `&World` even with live mutable borrows of components and resources
|
||||
/// so the returned `&World` should not be handed out to safe code and care should be taken
|
||||
/// when working with it.
|
||||
///
|
||||
/// Deliberately private as the correct way to access data in a [`World`] that may have existing
|
||||
/// mutable borrows of data inside it, is to use [`UnsafeWorldCell`].
|
||||
///
|
||||
/// # Safety
|
||||
/// - must not be used in a way that would conflict with any
|
||||
/// live exclusive borrows on world data
|
||||
unsafe fn unsafe_world(self) -> &'w World {
|
||||
// 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 }
|
||||
}
|
||||
|
||||
/// Retrieves this world's [Entities] collection
|
||||
#[inline]
|
||||
pub fn entities(self) -> &'w Entities {
|
||||
&self.0.entities
|
||||
// SAFETY:
|
||||
// - we only access world metadata
|
||||
&unsafe { self.world_metadata() }.entities
|
||||
}
|
||||
|
||||
/// Retrieves this world's [Archetypes] collection
|
||||
#[inline]
|
||||
pub fn archetypes(self) -> &'w Archetypes {
|
||||
&self.0.archetypes
|
||||
// SAFETY:
|
||||
// - we only access world metadata
|
||||
&unsafe { self.world_metadata() }.archetypes
|
||||
}
|
||||
|
||||
/// Retrieves this world's [Components] collection
|
||||
#[inline]
|
||||
pub fn components(self) -> &'w Components {
|
||||
&self.0.components
|
||||
}
|
||||
|
||||
/// Retrieves this world's [Storages] collection
|
||||
#[inline]
|
||||
pub fn storages(self) -> &'w Storages {
|
||||
&self.0.storages
|
||||
// SAFETY:
|
||||
// - we only access world metadata
|
||||
&unsafe { self.world_metadata() }.components
|
||||
}
|
||||
|
||||
/// Retrieves this world's [Bundles] collection
|
||||
#[inline]
|
||||
pub fn bundles(self) -> &'w Bundles {
|
||||
&self.0.bundles
|
||||
// SAFETY:
|
||||
// - we only access world metadata
|
||||
&unsafe { self.world_metadata() }.bundles
|
||||
}
|
||||
|
||||
/// Reads the current change tick of this world.
|
||||
#[inline]
|
||||
pub fn read_change_tick(self) -> u32 {
|
||||
self.0.read_change_tick()
|
||||
// SAFETY:
|
||||
// - we only access world metadata
|
||||
unsafe { self.world_metadata() }
|
||||
.change_tick
|
||||
.load(Ordering::Acquire)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn last_change_tick(self) -> u32 {
|
||||
self.0.last_change_tick()
|
||||
// SAFETY:
|
||||
// - we only access world metadata
|
||||
unsafe { self.world_metadata() }.last_change_tick
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn increment_change_tick(self) -> u32 {
|
||||
self.0.increment_change_tick()
|
||||
// SAFETY:
|
||||
// - we only access world metadata
|
||||
unsafe { self.world_metadata() }
|
||||
.change_tick
|
||||
.fetch_add(1, Ordering::AcqRel)
|
||||
}
|
||||
|
||||
/// Shorthand helper function for getting the [`ArchetypeComponentId`] for a resource.
|
||||
#[inline]
|
||||
pub(crate) fn get_resource_archetype_component_id(
|
||||
self,
|
||||
component_id: ComponentId,
|
||||
) -> Option<ArchetypeComponentId> {
|
||||
// SAFETY:
|
||||
// - we only access world metadata
|
||||
let resource = unsafe { self.world_metadata() }
|
||||
.storages
|
||||
.resources
|
||||
.get(component_id)?;
|
||||
Some(resource.id())
|
||||
}
|
||||
|
||||
/// Shorthand helper function for getting the [`ArchetypeComponentId`] for a resource.
|
||||
#[inline]
|
||||
pub(crate) fn get_non_send_archetype_component_id(
|
||||
self,
|
||||
component_id: ComponentId,
|
||||
) -> Option<ArchetypeComponentId> {
|
||||
// SAFETY:
|
||||
// - we only access world metadata
|
||||
let resource = unsafe { self.world_metadata() }
|
||||
.storages
|
||||
.non_send_resources
|
||||
.get(component_id)?;
|
||||
Some(resource.id())
|
||||
}
|
||||
|
||||
/// Retrieves an [`UnsafeWorldCellEntityRef`] 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 fn get_entity(self, entity: Entity) -> Option<UnsafeWorldCellEntityRef<'w>> {
|
||||
let location = self.0.entities.get(entity)?;
|
||||
let location = self.entities().get(entity)?;
|
||||
Some(UnsafeWorldCellEntityRef::new(self, entity, location))
|
||||
}
|
||||
|
||||
|
@ -150,7 +254,14 @@ impl<'w> UnsafeWorldCell<'w> {
|
|||
/// - no mutable reference to the resource exists at the same time
|
||||
#[inline]
|
||||
pub unsafe fn get_resource<R: Resource>(self) -> Option<&'w R> {
|
||||
self.0.get_resource::<R>()
|
||||
let component_id = self.components().get_resource_id(TypeId::of::<R>())?;
|
||||
// SAFETY: caller ensures `self` has permission to access the resource
|
||||
// caller also ensure that no mutable reference to the resource exists
|
||||
unsafe {
|
||||
self.get_resource_by_id(component_id)
|
||||
// SAFETY: `component_id` was obtained from the type ID of `R`.
|
||||
.map(|ptr| ptr.deref::<R>())
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets a pointer to the resource with the id [`ComponentId`] if it exists.
|
||||
|
@ -166,7 +277,13 @@ impl<'w> UnsafeWorldCell<'w> {
|
|||
/// - no mutable reference to the resource exists at the same time
|
||||
#[inline]
|
||||
pub unsafe fn get_resource_by_id(self, component_id: ComponentId) -> Option<Ptr<'w>> {
|
||||
self.0.get_resource_by_id(component_id)
|
||||
// SAFETY: caller ensures that `self` has permission to access `R`
|
||||
// caller ensures that no mutable reference exists to `R`
|
||||
unsafe { self.unsafe_world() }
|
||||
.storages
|
||||
.resources
|
||||
.get(component_id)?
|
||||
.get_data()
|
||||
}
|
||||
|
||||
/// Gets a reference to the non-send resource of the given type if it exists
|
||||
|
@ -177,7 +294,14 @@ impl<'w> UnsafeWorldCell<'w> {
|
|||
/// - no mutable reference to the resource exists at the same time
|
||||
#[inline]
|
||||
pub unsafe fn get_non_send_resource<R: 'static>(self) -> Option<&'w R> {
|
||||
self.0.get_non_send_resource()
|
||||
let component_id = self.components().get_resource_id(TypeId::of::<R>())?;
|
||||
// SAFETY: caller ensures that `self` has permission to access `R`
|
||||
// caller ensures that no mutable reference exists to `R`
|
||||
unsafe {
|
||||
self.get_non_send_resource_by_id(component_id)
|
||||
// SAEFTY: `component_id` was obtained from `TypeId::of::<R>()`
|
||||
.map(|ptr| ptr.deref::<R>())
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets a `!Send` resource to the resource with the id [`ComponentId`] if it exists.
|
||||
|
@ -196,7 +320,9 @@ impl<'w> UnsafeWorldCell<'w> {
|
|||
/// - no mutable reference to the resource exists at the same time
|
||||
#[inline]
|
||||
pub unsafe fn get_non_send_resource_by_id(self, component_id: ComponentId) -> Option<Ptr<'w>> {
|
||||
self.0
|
||||
// SAFETY: we only access data on world that the caller has ensured is unaliased and we have
|
||||
// permission to access.
|
||||
unsafe { self.unsafe_world() }
|
||||
.storages
|
||||
.non_send_resources
|
||||
.get(component_id)?
|
||||
|
@ -211,12 +337,15 @@ impl<'w> UnsafeWorldCell<'w> {
|
|||
/// - no other references to the resource exist at the same time
|
||||
#[inline]
|
||||
pub unsafe fn get_resource_mut<R: Resource>(self) -> Option<Mut<'w, R>> {
|
||||
let component_id = self.0.components.get_resource_id(TypeId::of::<R>())?;
|
||||
let component_id = self.components().get_resource_id(TypeId::of::<R>())?;
|
||||
// SAFETY:
|
||||
// - component_id is of type `R`
|
||||
// - caller ensures aliasing rules
|
||||
// - `R` is Send + Sync
|
||||
unsafe { self.get_resource_mut_with_id(component_id) }
|
||||
// - caller ensures `self` has permission to access the resource mutably
|
||||
// - caller ensures no other references to the resource exist
|
||||
unsafe {
|
||||
self.get_resource_mut_by_id(component_id)
|
||||
// `component_id` was gotten from `TypeId::of::<R>()`
|
||||
.map(|ptr| ptr.with_type::<R>())
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets a pointer to the resource with the id [`ComponentId`] if it exists.
|
||||
|
@ -232,10 +361,16 @@ impl<'w> UnsafeWorldCell<'w> {
|
|||
/// - no other references to the resource exist at the same time
|
||||
#[inline]
|
||||
pub unsafe fn get_resource_mut_by_id(
|
||||
&self,
|
||||
self,
|
||||
component_id: ComponentId,
|
||||
) -> Option<MutUntyped<'w>> {
|
||||
let (ptr, ticks) = self.0.get_resource_with_ticks(component_id)?;
|
||||
// SAFETY: we only access data that the caller has ensured is unaliased and `self`
|
||||
// has permission to access.
|
||||
let (ptr, ticks) = unsafe { self.unsafe_world() }
|
||||
.storages
|
||||
.resources
|
||||
.get(component_id)?
|
||||
.get_with_ticks()?;
|
||||
|
||||
// SAFETY:
|
||||
// - index is in-bounds because the column is initialized and non-empty
|
||||
|
@ -259,9 +394,15 @@ impl<'w> UnsafeWorldCell<'w> {
|
|||
/// - no other references to the resource exist at the same time
|
||||
#[inline]
|
||||
pub unsafe fn get_non_send_resource_mut<R: 'static>(self) -> Option<Mut<'w, R>> {
|
||||
let component_id = self.0.components.get_resource_id(TypeId::of::<R>())?;
|
||||
// SAFETY: component_id matches `R`, rest is promised by caller
|
||||
unsafe { self.get_non_send_mut_with_id(component_id) }
|
||||
let component_id = self.components().get_resource_id(TypeId::of::<R>())?;
|
||||
// SAFETY:
|
||||
// - caller ensures that `self` has permission to access the resource
|
||||
// - caller ensures that the resource is unaliased
|
||||
unsafe {
|
||||
self.get_non_send_resource_mut_by_id(component_id)
|
||||
// SAFETY: `component_id` was gotten by `TypeId::of::<R>()`
|
||||
.map(|ptr| ptr.with_type::<R>())
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets a `!Send` resource to the resource with the id [`ComponentId`] if it exists.
|
||||
|
@ -280,11 +421,17 @@ impl<'w> UnsafeWorldCell<'w> {
|
|||
/// - no other references to the resource exist at the same time
|
||||
#[inline]
|
||||
pub unsafe fn get_non_send_resource_mut_by_id(
|
||||
&mut self,
|
||||
self,
|
||||
component_id: ComponentId,
|
||||
) -> Option<MutUntyped<'_>> {
|
||||
) -> Option<MutUntyped<'w>> {
|
||||
let change_tick = self.read_change_tick();
|
||||
let (ptr, ticks) = self.0.get_non_send_with_ticks(component_id)?;
|
||||
// SAFETY: we only access data that the caller has ensured is unaliased and `self`
|
||||
// has permission to access.
|
||||
let (ptr, ticks) = unsafe { self.unsafe_world() }
|
||||
.storages
|
||||
.non_send_resources
|
||||
.get(component_id)?
|
||||
.get_with_ticks()?;
|
||||
|
||||
let ticks =
|
||||
// SAFETY: This function has exclusive access to the world so nothing aliases `ticks`.
|
||||
|
@ -298,59 +445,52 @@ impl<'w> UnsafeWorldCell<'w> {
|
|||
ticks,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'w> UnsafeWorldCell<'w> {
|
||||
// Shorthand helper function for getting the data and change ticks for a resource.
|
||||
///
|
||||
/// # Safety
|
||||
/// It is the callers responsibility to ensure that
|
||||
/// - `component_id` must be assigned to a component of type `R`
|
||||
/// - the [`UnsafeWorldCell`] has permission to access the resource
|
||||
/// - no other mutable references to the resource exist at the same time
|
||||
#[inline]
|
||||
pub(crate) unsafe fn get_resource_mut_with_id<R>(
|
||||
&self,
|
||||
component_id: ComponentId,
|
||||
) -> Option<Mut<'w, R>> {
|
||||
let (ptr, ticks) = self.0.get_resource_with_ticks(component_id)?;
|
||||
|
||||
// SAFETY:
|
||||
// - This caller ensures that nothing aliases `ticks`.
|
||||
// - index is in-bounds because the column is initialized and non-empty
|
||||
let ticks = unsafe {
|
||||
TicksMut::from_tick_cells(ticks, self.last_change_tick(), self.read_change_tick())
|
||||
};
|
||||
|
||||
Some(Mut {
|
||||
// SAFETY: caller ensures aliasing rules, ptr is of type `R`
|
||||
value: unsafe { ptr.assert_unique().deref_mut() },
|
||||
ticks,
|
||||
})
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
/// It is the callers responsibility to ensure that
|
||||
/// - `component_id` must be assigned to a component of type `R`.
|
||||
/// - the [`UnsafeWorldCell`] has permission to access the resource mutably
|
||||
/// - no other references to the resource exist at the same time
|
||||
/// - no mutable references to the resource exist at the same time
|
||||
#[inline]
|
||||
pub(crate) unsafe fn get_non_send_mut_with_id<R: 'static>(
|
||||
&self,
|
||||
pub(crate) unsafe fn get_resource_with_ticks(
|
||||
self,
|
||||
component_id: ComponentId,
|
||||
) -> Option<Mut<'w, R>> {
|
||||
let (ptr, ticks) = self
|
||||
.0
|
||||
) -> Option<(Ptr<'w>, TickCells<'w>)> {
|
||||
// SAFETY:
|
||||
// - caller ensures there is no `&mut World`
|
||||
// - caller ensures there are no mutable borrows of this resource
|
||||
// - caller ensures that we have permission to access this resource
|
||||
unsafe { self.unsafe_world() }
|
||||
.storages
|
||||
.resources
|
||||
.get(component_id)?
|
||||
.get_with_ticks()
|
||||
}
|
||||
|
||||
// Shorthand helper function for getting the data and change ticks for a resource.
|
||||
///
|
||||
/// # 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 mutable references to the resource exist at the same time
|
||||
#[inline]
|
||||
pub(crate) unsafe fn get_non_send_with_ticks(
|
||||
self,
|
||||
component_id: ComponentId,
|
||||
) -> Option<(Ptr<'w>, TickCells<'w>)> {
|
||||
// SAFETY:
|
||||
// - caller ensures there is no `&mut World`
|
||||
// - caller ensures there are no mutable borrows of this resource
|
||||
// - caller ensures that we have permission to access this resource
|
||||
unsafe { self.unsafe_world() }
|
||||
.storages
|
||||
.non_send_resources
|
||||
.get(component_id)?
|
||||
.get_with_ticks()?;
|
||||
Some(Mut {
|
||||
// SAFETY: caller ensures unique access
|
||||
value: unsafe { ptr.assert_unique().deref_mut() },
|
||||
// SAFETY: caller ensures unique access
|
||||
ticks: unsafe {
|
||||
TicksMut::from_tick_cells(ticks, self.last_change_tick(), self.read_change_tick())
|
||||
},
|
||||
})
|
||||
.get_with_ticks()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -388,7 +528,7 @@ impl<'w> UnsafeWorldCellEntityRef<'w> {
|
|||
|
||||
#[inline]
|
||||
pub fn archetype(self) -> &'w Archetype {
|
||||
&self.world.0.archetypes[self.location.archetype_id]
|
||||
&self.world.archetypes()[self.location.archetype_id]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -403,12 +543,16 @@ impl<'w> UnsafeWorldCellEntityRef<'w> {
|
|||
|
||||
#[inline]
|
||||
pub fn contains_id(self, component_id: ComponentId) -> bool {
|
||||
entity_ref::contains_component_with_id(self.world.0, component_id, self.location)
|
||||
self.archetype().contains(component_id)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn contains_type_id(self, type_id: TypeId) -> bool {
|
||||
entity_ref::contains_component_with_type(self.world.0, type_id, self.location)
|
||||
let id = match self.world.components().get_id(type_id) {
|
||||
Some(id) => id,
|
||||
None => return false,
|
||||
};
|
||||
self.contains_id(id)
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
|
@ -417,14 +561,15 @@ impl<'w> UnsafeWorldCellEntityRef<'w> {
|
|||
/// - no other mutable references to the component exist at the same time
|
||||
#[inline]
|
||||
pub unsafe fn get<T: Component>(self) -> Option<&'w T> {
|
||||
let component_id = self.world.components().get_id(TypeId::of::<T>())?;
|
||||
|
||||
// SAFETY:
|
||||
// - entity location is valid
|
||||
// - proper world access is promised by caller
|
||||
unsafe {
|
||||
self.world
|
||||
.0
|
||||
.get_component_with_type(
|
||||
TypeId::of::<T>(),
|
||||
get_component(
|
||||
self.world,
|
||||
component_id,
|
||||
T::Storage::STORAGE_TYPE,
|
||||
self.entity,
|
||||
self.location,
|
||||
|
@ -443,12 +588,15 @@ impl<'w> UnsafeWorldCellEntityRef<'w> {
|
|||
/// - no other mutable references to the component exist at the same time
|
||||
#[inline]
|
||||
pub unsafe fn get_change_ticks<T: Component>(self) -> Option<ComponentTicks> {
|
||||
let component_id = self.world.components().get_id(TypeId::of::<T>())?;
|
||||
|
||||
// SAFETY:
|
||||
// - entity location is valid
|
||||
// - proper world acess is promised by caller
|
||||
unsafe {
|
||||
self.world.0.get_ticks_with_type(
|
||||
TypeId::of::<T>(),
|
||||
get_ticks(
|
||||
self.world,
|
||||
component_id,
|
||||
T::Storage::STORAGE_TYPE,
|
||||
self.entity,
|
||||
self.location,
|
||||
|
@ -478,7 +626,8 @@ impl<'w> UnsafeWorldCellEntityRef<'w> {
|
|||
// - world access is immutable, lifetime tied to `&self`
|
||||
// - the storage type provided is correct for T
|
||||
unsafe {
|
||||
self.world.0.get_ticks(
|
||||
get_ticks(
|
||||
self.world,
|
||||
component_id,
|
||||
info.storage_type(),
|
||||
self.entity,
|
||||
|
@ -509,15 +658,16 @@ impl<'w> UnsafeWorldCellEntityRef<'w> {
|
|||
last_change_tick: u32,
|
||||
change_tick: u32,
|
||||
) -> Option<Mut<'w, T>> {
|
||||
let component_id = self.world.components().get_id(TypeId::of::<T>())?;
|
||||
|
||||
// SAFETY:
|
||||
// - `storage_type` is correct
|
||||
// - `location` is valid
|
||||
// - aliasing rules are ensured by caller
|
||||
unsafe {
|
||||
self.world
|
||||
.0
|
||||
.get_component_and_ticks_with_type(
|
||||
TypeId::of::<T>(),
|
||||
get_component_and_ticks(
|
||||
self.world,
|
||||
component_id,
|
||||
T::Storage::STORAGE_TYPE,
|
||||
self.entity,
|
||||
self.location,
|
||||
|
@ -546,10 +696,11 @@ impl<'w> UnsafeWorldCellEntityRef<'w> {
|
|||
/// - no other mutable references to the component exist at the same time
|
||||
#[inline]
|
||||
pub unsafe fn get_by_id(self, component_id: ComponentId) -> Option<Ptr<'w>> {
|
||||
let info = self.world.0.components.get_info(component_id)?;
|
||||
let info = self.world.components().get_info(component_id)?;
|
||||
// SAFETY: entity_location is valid, component_id is valid as checked by the line above
|
||||
unsafe {
|
||||
self.world.0.get_component(
|
||||
get_component(
|
||||
self.world,
|
||||
component_id,
|
||||
info.storage_type(),
|
||||
self.entity,
|
||||
|
@ -570,12 +721,11 @@ impl<'w> UnsafeWorldCellEntityRef<'w> {
|
|||
/// - no other references to the component exist at the same time
|
||||
#[inline]
|
||||
pub unsafe fn get_mut_by_id(self, component_id: ComponentId) -> Option<MutUntyped<'w>> {
|
||||
let info = self.world.0.components.get_info(component_id)?;
|
||||
let info = self.world.components().get_info(component_id)?;
|
||||
// SAFETY: entity_location is valid, component_id is valid as checked by the line above
|
||||
unsafe {
|
||||
self.world
|
||||
.0
|
||||
.get_component_and_ticks(
|
||||
get_component_and_ticks(
|
||||
self.world,
|
||||
component_id,
|
||||
info.storage_type(),
|
||||
self.entity,
|
||||
|
@ -593,3 +743,126 @@ impl<'w> UnsafeWorldCellEntityRef<'w> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'w> UnsafeWorldCell<'w> {
|
||||
#[inline]
|
||||
/// # Safety:
|
||||
/// - the returned `Column` is only used in ways that this [`UnsafeWorldCell`] has permission for.
|
||||
/// - the returned `Column` is only used in ways that would not conflict with any existing
|
||||
/// borrows of world data.
|
||||
unsafe fn fetch_table(
|
||||
self,
|
||||
location: EntityLocation,
|
||||
component_id: ComponentId,
|
||||
) -> Option<(&'w Column, TableRow)> {
|
||||
let archetype = &self.archetypes()[location.archetype_id];
|
||||
// SAFETY: caller ensures returned data is not misused and we have not created any borrows
|
||||
// of component/resource data
|
||||
let table = &unsafe { self.unsafe_world() }.storages.tables[archetype.table_id()];
|
||||
let components = table.get_column(component_id)?;
|
||||
let table_row = archetype.entity_table_row(location.archetype_row);
|
||||
Some((components, table_row))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// # Safety:
|
||||
/// - the returned `ComponentSparseSet` is only used in ways that this [`UnsafeWorldCell`] has permission for.
|
||||
/// - the returned `ComponentSparseSet` is only used in ways that would not conflict with any existing
|
||||
/// borrows of world data.
|
||||
unsafe fn fetch_sparse_set(self, component_id: ComponentId) -> Option<&'w ComponentSparseSet> {
|
||||
// SAFETY: caller ensures returned data is not misused and we have not created any borrows
|
||||
// of component/resource data
|
||||
unsafe { self.unsafe_world() }
|
||||
.storages
|
||||
.sparse_sets
|
||||
.get(component_id)
|
||||
}
|
||||
}
|
||||
|
||||
/// Get an untyped pointer to a particular [`Component`](crate::component::Component) on a particular [`Entity`] in the provided [`World`](crate::world::World).
|
||||
///
|
||||
/// # Safety
|
||||
/// - `location` must refer to an archetype that contains `entity`
|
||||
/// the archetype
|
||||
/// - `component_id` must be valid
|
||||
/// - `storage_type` must accurately reflect where the components for `component_id` are stored.
|
||||
/// - the caller must ensure that no aliasing rules are violated
|
||||
#[inline]
|
||||
#[allow(unsafe_op_in_unsafe_fn)]
|
||||
unsafe fn get_component(
|
||||
world: UnsafeWorldCell<'_>,
|
||||
component_id: ComponentId,
|
||||
storage_type: StorageType,
|
||||
entity: Entity,
|
||||
location: EntityLocation,
|
||||
) -> Option<Ptr<'_>> {
|
||||
// SAFETY: component_id exists and is therefore valid
|
||||
match storage_type {
|
||||
StorageType::Table => {
|
||||
let (components, table_row) = world.fetch_table(location, component_id)?;
|
||||
// SAFETY: archetypes only store valid table_rows and caller ensure aliasing rules
|
||||
Some(components.get_data_unchecked(table_row))
|
||||
}
|
||||
StorageType::SparseSet => world.fetch_sparse_set(component_id)?.get(entity),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get an untyped pointer to a particular [`Component`](crate::component::Component) and its [`ComponentTicks`]
|
||||
///
|
||||
/// # Safety
|
||||
/// - `location` must refer to an archetype that contains `entity`
|
||||
/// - `component_id` must be valid
|
||||
/// - `storage_type` must accurately reflect where the components for `component_id` are stored.
|
||||
/// - the caller must ensure that no aliasing rules are violated
|
||||
#[inline]
|
||||
#[allow(unsafe_op_in_unsafe_fn)]
|
||||
unsafe fn get_component_and_ticks(
|
||||
world: UnsafeWorldCell<'_>,
|
||||
component_id: ComponentId,
|
||||
storage_type: StorageType,
|
||||
entity: Entity,
|
||||
location: EntityLocation,
|
||||
) -> Option<(Ptr<'_>, TickCells<'_>)> {
|
||||
match storage_type {
|
||||
StorageType::Table => {
|
||||
let (components, table_row) = world.fetch_table(location, component_id)?;
|
||||
|
||||
// SAFETY: archetypes only store valid table_rows and caller ensure aliasing rules
|
||||
Some((
|
||||
components.get_data_unchecked(table_row),
|
||||
TickCells {
|
||||
added: components.get_added_ticks_unchecked(table_row),
|
||||
changed: components.get_changed_ticks_unchecked(table_row),
|
||||
},
|
||||
))
|
||||
}
|
||||
StorageType::SparseSet => world.fetch_sparse_set(component_id)?.get_with_ticks(entity),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get an untyped pointer to the [`ComponentTicks`] on a particular [`Entity`]
|
||||
///
|
||||
/// # Safety
|
||||
/// - `location` must refer to an archetype that contains `entity`
|
||||
/// the archetype
|
||||
/// - `component_id` must be valid
|
||||
/// - `storage_type` must accurately reflect where the components for `component_id` are stored.
|
||||
/// - the caller must ensure that no aliasing rules are violated
|
||||
#[inline]
|
||||
#[allow(unsafe_op_in_unsafe_fn)]
|
||||
unsafe fn get_ticks(
|
||||
world: UnsafeWorldCell<'_>,
|
||||
component_id: ComponentId,
|
||||
storage_type: StorageType,
|
||||
entity: Entity,
|
||||
location: EntityLocation,
|
||||
) -> Option<ComponentTicks> {
|
||||
match storage_type {
|
||||
StorageType::Table => {
|
||||
let (components, table_row) = world.fetch_table(location, component_id)?;
|
||||
// SAFETY: archetypes only store valid table_rows and caller ensure aliasing rules
|
||||
Some(components.get_ticks_unchecked(table_row))
|
||||
}
|
||||
StorageType::SparseSet => world.fetch_sparse_set(component_id)?.get_ticks(entity),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -80,10 +80,10 @@ impl<'w> Drop for WorldCell<'w> {
|
|||
let mut access = self.access.borrow_mut();
|
||||
|
||||
{
|
||||
// SAFETY: we only swap `archetype_component_access`
|
||||
let world = unsafe { self.world.world() };
|
||||
// SAFETY: the WorldCell has exclusive world access
|
||||
let world_cached_access = unsafe { &mut *world.archetype_component_access.get() };
|
||||
// SAFETY: `WorldCell` does not hand out `UnsafeWorldCell` to anywhere else so this is the only
|
||||
// `UnsafeWorldCell` and we have exclusive access to it.
|
||||
let world = unsafe { self.world.world_mut() };
|
||||
let world_cached_access = &mut world.archetype_component_access;
|
||||
|
||||
// give world ArchetypeComponentAccess back to reuse allocations
|
||||
std::mem::swap(world_cached_access, &mut *access);
|
||||
|
@ -185,7 +185,7 @@ impl<'w> WorldCell<'w> {
|
|||
pub(crate) fn new(world: &'w mut World) -> Self {
|
||||
// this is cheap because ArchetypeComponentAccess::new() is const / allocation free
|
||||
let access = std::mem::replace(
|
||||
world.archetype_component_access.get_mut(),
|
||||
&mut world.archetype_component_access,
|
||||
ArchetypeComponentAccess::new(),
|
||||
);
|
||||
// world's ArchetypeComponentAccess is recycled to cut down on allocations
|
||||
|
@ -199,7 +199,9 @@ impl<'w> WorldCell<'w> {
|
|||
pub fn get_resource<T: Resource>(&self) -> Option<WorldBorrow<'_, T>> {
|
||||
let component_id = self.world.components().get_resource_id(TypeId::of::<T>())?;
|
||||
|
||||
let archetype_component_id = self.world.storages().resources.get(component_id)?.id();
|
||||
let archetype_component_id = self
|
||||
.world
|
||||
.get_resource_archetype_component_id(component_id)?;
|
||||
|
||||
WorldBorrow::try_new(
|
||||
// SAFETY: access is checked by WorldBorrow
|
||||
|
@ -231,7 +233,10 @@ impl<'w> WorldCell<'w> {
|
|||
/// Gets a mutable reference to the resource of the given type
|
||||
pub fn get_resource_mut<T: Resource>(&self) -> Option<WorldBorrowMut<'_, T>> {
|
||||
let component_id = self.world.components().get_resource_id(TypeId::of::<T>())?;
|
||||
let archetype_component_id = self.world.storages().resources.get(component_id)?.id();
|
||||
|
||||
let archetype_component_id = self
|
||||
.world
|
||||
.get_resource_archetype_component_id(component_id)?;
|
||||
WorldBorrowMut::try_new(
|
||||
// SAFETY: access is checked by WorldBorrowMut
|
||||
|| unsafe { self.world.get_resource_mut::<T>() },
|
||||
|
@ -262,12 +267,10 @@ impl<'w> WorldCell<'w> {
|
|||
/// Gets an immutable reference to the non-send resource of the given type, if it exists.
|
||||
pub fn get_non_send_resource<T: 'static>(&self) -> Option<WorldBorrow<'_, T>> {
|
||||
let component_id = self.world.components().get_resource_id(TypeId::of::<T>())?;
|
||||
|
||||
let archetype_component_id = self
|
||||
.world
|
||||
.storages()
|
||||
.non_send_resources
|
||||
.get(component_id)?
|
||||
.id();
|
||||
.get_non_send_archetype_component_id(component_id)?;
|
||||
WorldBorrow::try_new(
|
||||
// SAFETY: access is checked by WorldBorrowMut
|
||||
|| unsafe { self.world.get_non_send_resource::<T>() },
|
||||
|
@ -298,12 +301,10 @@ impl<'w> WorldCell<'w> {
|
|||
/// Gets a mutable reference to the non-send resource of the given type, if it exists.
|
||||
pub fn get_non_send_resource_mut<T: 'static>(&self) -> Option<WorldBorrowMut<'_, T>> {
|
||||
let component_id = self.world.components().get_resource_id(TypeId::of::<T>())?;
|
||||
|
||||
let archetype_component_id = self
|
||||
.world
|
||||
.storages()
|
||||
.non_send_resources
|
||||
.get(component_id)?
|
||||
.id();
|
||||
.get_non_send_archetype_component_id(component_id)?;
|
||||
WorldBorrowMut::try_new(
|
||||
// SAFETY: access is checked by WorldBorrowMut
|
||||
|| unsafe { self.world.get_non_send_resource_mut::<T>() },
|
||||
|
@ -422,11 +423,10 @@ mod tests {
|
|||
let u32_archetype_component_id = world
|
||||
.get_resource_archetype_component_id(u32_component_id)
|
||||
.unwrap();
|
||||
assert_eq!(world.archetype_component_access.get_mut().access.len(), 1);
|
||||
assert_eq!(world.archetype_component_access.access.len(), 1);
|
||||
assert_eq!(
|
||||
world
|
||||
.archetype_component_access
|
||||
.get_mut()
|
||||
.access
|
||||
.get(u32_archetype_component_id),
|
||||
Some(&BASE_ACCESS),
|
||||
|
|
Loading…
Reference in a new issue