Encapsulate cfg(feature = "track_location") in a type. (#17602)
# Objective Eliminate the need to write `cfg(feature = "track_location")` every time one uses an API that may use location tracking. It's verbose, and a little intimidating. And it requires code outside of `bevy_ecs` that wants to use location tracking needs to either unconditionally enable the feature, or include conditional compilation of its own. It would be good for users to be able to log locations when they are available without needing to add feature flags to their own crates. Reduce the number of cases where code compiles with the `track_location` feature enabled, but not with it disabled, or vice versa. It can be hard to remember to test it both ways! Remove the need to store a `None` in `HookContext` when the `track_location` feature is disabled. ## Solution Create an `MaybeLocation<T>` type that contains a `T` if the `track_location` feature is enabled, and is a ZST if it is not. The overall API is similar to `Option`, but whether the value is `Some` or `None` is set at compile time and is the same for all values. Default `T` to `&'static Location<'static>`, since that is the most common case. Remove all `cfg(feature = "track_location")` blocks outside of the implementation of that type, and instead call methods on it. When `track_location` is disabled, `MaybeLocation` is a ZST and all methods are `#[inline]` and empty, so they should be entirely removed by the compiler. But the code will still be visible to the compiler and checked, so if it compiles with the feature disabled then it should also compile with it enabled, and vice versa. ## Open Questions Where should these types live? I put them in `change_detection` because that's where the existing `MaybeLocation` types were, but we now use these outside of change detection. While I believe that the compiler should be able to remove all of these calls, I have not actually tested anything. If we want to take this approach, what testing is required to ensure it doesn't impact performance? ## Migration Guide Methods like `Ref::changed_by()` that return a `&'static Location<'static>` will now be available even when the `track_location` feature is disabled, but they will return a new `MaybeLocation` type. `MaybeLocation` wraps a `&'static Location<'static>` when the feature is enabled, and is a ZST when the feature is disabled. Existing code that needs a `&Location` can call `into_option().unwrap()` to recover it. Many trait impls are forwarded, so if you only need `Display` then no changes will be necessary. If that code was conditionally compiled, you may instead want to use the methods on `MaybeLocation` to remove the need for conditional compilation. Code that constructs a `Ref`, `Mut`, `Res`, or `ResMut` will now need to provide location information unconditionally. If you are creating them from existing Bevy types, you can obtain a `MaybeLocation` from methods like `Table::get_changed_by_slice_for()` or `ComponentSparseSet::get_with_ticks`. Otherwise, you will need to store a `MaybeLocation` next to your data and use methods like `as_ref()` or `as_mut()` to obtain wrapped references.
This commit is contained in:
parent
4ecbe001d5
commit
eee7fd5b3e
@ -9,6 +9,7 @@ use crate::{
|
||||
Archetype, ArchetypeAfterBundleInsert, ArchetypeId, Archetypes, BundleComponentStatus,
|
||||
ComponentStatus, SpawnBundleStatus,
|
||||
},
|
||||
change_detection::MaybeLocation,
|
||||
component::{
|
||||
Component, ComponentId, Components, RequiredComponentConstructor, RequiredComponents,
|
||||
StorageType, Tick,
|
||||
@ -24,8 +25,6 @@ use alloc::{boxed::Box, vec, vec::Vec};
|
||||
use bevy_platform_support::collections::{HashMap, HashSet};
|
||||
use bevy_ptr::{ConstNonNull, OwningPtr};
|
||||
use bevy_utils::TypeIdMap;
|
||||
#[cfg(feature = "track_location")]
|
||||
use core::panic::Location;
|
||||
use core::{any::TypeId, ptr::NonNull};
|
||||
use variadics_please::all_tuples;
|
||||
|
||||
@ -623,7 +622,7 @@ impl BundleInfo {
|
||||
change_tick: Tick,
|
||||
bundle: T,
|
||||
insert_mode: InsertMode,
|
||||
#[cfg(feature = "track_location")] caller: &'static Location<'static>,
|
||||
caller: MaybeLocation,
|
||||
) -> T::Effect {
|
||||
// NOTE: get_components calls this closure on each component in "bundle order".
|
||||
// bundle_info.component_ids are also in "bundle order"
|
||||
@ -638,20 +637,12 @@ impl BundleInfo {
|
||||
// the target table contains the component.
|
||||
let column = table.get_column_mut(component_id).debug_checked_unwrap();
|
||||
match (status, insert_mode) {
|
||||
(ComponentStatus::Added, _) => column.initialize(
|
||||
table_row,
|
||||
component_ptr,
|
||||
change_tick,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
),
|
||||
(ComponentStatus::Existing, InsertMode::Replace) => column.replace(
|
||||
table_row,
|
||||
component_ptr,
|
||||
change_tick,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
),
|
||||
(ComponentStatus::Added, _) => {
|
||||
column.initialize(table_row, component_ptr, change_tick, caller);
|
||||
}
|
||||
(ComponentStatus::Existing, InsertMode::Replace) => {
|
||||
column.replace(table_row, component_ptr, change_tick, caller);
|
||||
}
|
||||
(ComponentStatus::Existing, InsertMode::Keep) => {
|
||||
if let Some(drop_fn) = table.get_drop_for(component_id) {
|
||||
drop_fn(component_ptr);
|
||||
@ -664,13 +655,7 @@ impl BundleInfo {
|
||||
// SAFETY: If component_id is in self.component_ids, BundleInfo::new ensures that
|
||||
// a sparse set exists for the component.
|
||||
unsafe { sparse_sets.get_mut(component_id).debug_checked_unwrap() };
|
||||
sparse_set.insert(
|
||||
entity,
|
||||
component_ptr,
|
||||
change_tick,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
sparse_set.insert(entity, component_ptr, change_tick, caller);
|
||||
}
|
||||
}
|
||||
bundle_component += 1;
|
||||
@ -683,7 +668,6 @@ impl BundleInfo {
|
||||
change_tick,
|
||||
table_row,
|
||||
entity,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
}
|
||||
@ -712,7 +696,7 @@ impl BundleInfo {
|
||||
component_id: ComponentId,
|
||||
storage_type: StorageType,
|
||||
component_ptr: OwningPtr,
|
||||
#[cfg(feature = "track_location")] caller: &'static Location<'static>,
|
||||
caller: MaybeLocation,
|
||||
) {
|
||||
{
|
||||
match storage_type {
|
||||
@ -721,26 +705,14 @@ impl BundleInfo {
|
||||
// SAFETY: If component_id is in required_components, BundleInfo::new requires that
|
||||
// the target table contains the component.
|
||||
unsafe { table.get_column_mut(component_id).debug_checked_unwrap() };
|
||||
column.initialize(
|
||||
table_row,
|
||||
component_ptr,
|
||||
change_tick,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
column.initialize(table_row, component_ptr, change_tick, caller);
|
||||
}
|
||||
StorageType::SparseSet => {
|
||||
let sparse_set =
|
||||
// SAFETY: If component_id is in required_components, BundleInfo::new requires that
|
||||
// a sparse set exists for the component.
|
||||
unsafe { sparse_sets.get_mut(component_id).debug_checked_unwrap() };
|
||||
sparse_set.insert(
|
||||
entity,
|
||||
component_ptr,
|
||||
change_tick,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
sparse_set.insert(entity, component_ptr, change_tick, caller);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1127,7 +1099,7 @@ impl<'w> BundleInserter<'w> {
|
||||
location: EntityLocation,
|
||||
bundle: T,
|
||||
insert_mode: InsertMode,
|
||||
#[cfg(feature = "track_location")] caller: &'static Location<'static>,
|
||||
caller: MaybeLocation,
|
||||
) -> (EntityLocation, T::Effect) {
|
||||
let bundle_info = self.bundle_info.as_ref();
|
||||
let archetype_after_insert = self.archetype_after_insert.as_ref();
|
||||
@ -1145,7 +1117,6 @@ impl<'w> BundleInserter<'w> {
|
||||
ON_REPLACE,
|
||||
entity,
|
||||
archetype_after_insert.iter_existing(),
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
}
|
||||
@ -1153,7 +1124,6 @@ impl<'w> BundleInserter<'w> {
|
||||
archetype,
|
||||
entity,
|
||||
archetype_after_insert.iter_existing(),
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
}
|
||||
@ -1183,7 +1153,6 @@ impl<'w> BundleInserter<'w> {
|
||||
self.change_tick,
|
||||
bundle,
|
||||
insert_mode,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
|
||||
@ -1225,7 +1194,6 @@ impl<'w> BundleInserter<'w> {
|
||||
self.change_tick,
|
||||
bundle,
|
||||
insert_mode,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
|
||||
@ -1308,7 +1276,6 @@ impl<'w> BundleInserter<'w> {
|
||||
self.change_tick,
|
||||
bundle,
|
||||
insert_mode,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
|
||||
@ -1327,7 +1294,6 @@ impl<'w> BundleInserter<'w> {
|
||||
new_archetype,
|
||||
entity,
|
||||
archetype_after_insert.iter_added(),
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
if new_archetype.has_add_observer() {
|
||||
@ -1335,7 +1301,6 @@ impl<'w> BundleInserter<'w> {
|
||||
ON_ADD,
|
||||
entity,
|
||||
archetype_after_insert.iter_added(),
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
}
|
||||
@ -1346,7 +1311,6 @@ impl<'w> BundleInserter<'w> {
|
||||
new_archetype,
|
||||
entity,
|
||||
archetype_after_insert.iter_inserted(),
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
if new_archetype.has_insert_observer() {
|
||||
@ -1354,7 +1318,6 @@ impl<'w> BundleInserter<'w> {
|
||||
ON_INSERT,
|
||||
entity,
|
||||
archetype_after_insert.iter_inserted(),
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
}
|
||||
@ -1366,7 +1329,6 @@ impl<'w> BundleInserter<'w> {
|
||||
new_archetype,
|
||||
entity,
|
||||
archetype_after_insert.iter_added(),
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
if new_archetype.has_insert_observer() {
|
||||
@ -1374,7 +1336,6 @@ impl<'w> BundleInserter<'w> {
|
||||
ON_INSERT,
|
||||
entity,
|
||||
archetype_after_insert.iter_added(),
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
}
|
||||
@ -1456,7 +1417,7 @@ impl<'w> BundleSpawner<'w> {
|
||||
&mut self,
|
||||
entity: Entity,
|
||||
bundle: T,
|
||||
#[cfg(feature = "track_location")] caller: &'static Location<'static>,
|
||||
caller: MaybeLocation,
|
||||
) -> (EntityLocation, T::Effect) {
|
||||
// SAFETY: We do not make any structural changes to the archetype graph through self.world so these pointers always remain valid
|
||||
let bundle_info = self.bundle_info.as_ref();
|
||||
@ -1481,7 +1442,6 @@ impl<'w> BundleSpawner<'w> {
|
||||
self.change_tick,
|
||||
bundle,
|
||||
InsertMode::Replace,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
entities.set(entity.index(), location);
|
||||
@ -1499,7 +1459,6 @@ impl<'w> BundleSpawner<'w> {
|
||||
archetype,
|
||||
entity,
|
||||
bundle_info.iter_contributed_components(),
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
if archetype.has_add_observer() {
|
||||
@ -1507,7 +1466,6 @@ impl<'w> BundleSpawner<'w> {
|
||||
ON_ADD,
|
||||
entity,
|
||||
bundle_info.iter_contributed_components(),
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
}
|
||||
@ -1515,7 +1473,6 @@ impl<'w> BundleSpawner<'w> {
|
||||
archetype,
|
||||
entity,
|
||||
bundle_info.iter_contributed_components(),
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
if archetype.has_insert_observer() {
|
||||
@ -1523,7 +1480,6 @@ impl<'w> BundleSpawner<'w> {
|
||||
ON_INSERT,
|
||||
entity,
|
||||
bundle_info.iter_contributed_components(),
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
}
|
||||
@ -1538,18 +1494,11 @@ impl<'w> BundleSpawner<'w> {
|
||||
pub unsafe fn spawn<T: Bundle>(
|
||||
&mut self,
|
||||
bundle: T,
|
||||
#[cfg(feature = "track_location")] caller: &'static Location<'static>,
|
||||
caller: MaybeLocation,
|
||||
) -> (Entity, T::Effect) {
|
||||
let entity = self.entities().alloc();
|
||||
// SAFETY: entity is allocated (but non-existent), `T` matches this BundleInfo's type
|
||||
let (_, after_effect) = unsafe {
|
||||
self.spawn_non_existent(
|
||||
entity,
|
||||
bundle,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
)
|
||||
};
|
||||
let (_, after_effect) = unsafe { self.spawn_non_existent(entity, bundle, caller) };
|
||||
(entity, after_effect)
|
||||
}
|
||||
|
||||
|
||||
@ -7,14 +7,13 @@ use crate::{
|
||||
};
|
||||
use alloc::borrow::ToOwned;
|
||||
use bevy_ptr::{Ptr, UnsafeCellDeref};
|
||||
#[cfg(feature = "bevy_reflect")]
|
||||
use bevy_reflect::Reflect;
|
||||
use core::{
|
||||
marker::PhantomData,
|
||||
mem,
|
||||
ops::{Deref, DerefMut},
|
||||
};
|
||||
#[cfg(feature = "track_location")]
|
||||
use {
|
||||
bevy_ptr::ThinSlicePtr,
|
||||
core::{cell::UnsafeCell, panic::Location},
|
||||
panic::Location,
|
||||
};
|
||||
|
||||
/// The (arbitrarily chosen) minimum number of world tick increments between `check_tick` scans.
|
||||
@ -73,8 +72,7 @@ pub trait DetectChanges {
|
||||
fn last_changed(&self) -> Tick;
|
||||
|
||||
/// The location that last caused this to change.
|
||||
#[cfg(feature = "track_location")]
|
||||
fn changed_by(&self) -> &'static Location<'static>;
|
||||
fn changed_by(&self) -> MaybeLocation;
|
||||
}
|
||||
|
||||
/// Types that implement reliable change detection.
|
||||
@ -343,9 +341,8 @@ macro_rules! change_detection_impl {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[cfg(feature = "track_location")]
|
||||
fn changed_by(&self) -> &'static Location<'static> {
|
||||
self.changed_by
|
||||
fn changed_by(&self) -> MaybeLocation {
|
||||
self.changed_by.copied()
|
||||
}
|
||||
}
|
||||
|
||||
@ -376,20 +373,14 @@ macro_rules! change_detection_mut_impl {
|
||||
#[track_caller]
|
||||
fn set_changed(&mut self) {
|
||||
*self.ticks.changed = self.ticks.this_run;
|
||||
#[cfg(feature = "track_location")]
|
||||
{
|
||||
*self.changed_by = Location::caller();
|
||||
}
|
||||
self.changed_by.assign(MaybeLocation::caller());
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[track_caller]
|
||||
fn set_last_changed(&mut self, last_changed: Tick) {
|
||||
*self.ticks.changed = last_changed;
|
||||
#[cfg(feature = "track_location")]
|
||||
{
|
||||
*self.changed_by = Location::caller();
|
||||
}
|
||||
self.changed_by.assign(MaybeLocation::caller());
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -403,10 +394,7 @@ macro_rules! change_detection_mut_impl {
|
||||
#[track_caller]
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
self.set_changed();
|
||||
#[cfg(feature = "track_location")]
|
||||
{
|
||||
*self.changed_by = Location::caller();
|
||||
}
|
||||
self.changed_by.assign(MaybeLocation::caller());
|
||||
self.value
|
||||
}
|
||||
}
|
||||
@ -444,8 +432,7 @@ macro_rules! impl_methods {
|
||||
last_run: self.ticks.last_run,
|
||||
this_run: self.ticks.this_run,
|
||||
},
|
||||
#[cfg(feature = "track_location")]
|
||||
changed_by: self.changed_by,
|
||||
changed_by: self.changed_by.as_deref_mut(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -475,7 +462,6 @@ macro_rules! impl_methods {
|
||||
Mut {
|
||||
value: f(self.value),
|
||||
ticks: self.ticks,
|
||||
#[cfg(feature = "track_location")]
|
||||
changed_by: self.changed_by,
|
||||
}
|
||||
}
|
||||
@ -489,7 +475,6 @@ macro_rules! impl_methods {
|
||||
value.map(|value| Mut {
|
||||
value,
|
||||
ticks: self.ticks,
|
||||
#[cfg(feature = "track_location")]
|
||||
changed_by: self.changed_by,
|
||||
})
|
||||
}
|
||||
@ -503,7 +488,6 @@ macro_rules! impl_methods {
|
||||
value.map(|value| Mut {
|
||||
value,
|
||||
ticks: self.ticks,
|
||||
#[cfg(feature = "track_location")]
|
||||
changed_by: self.changed_by,
|
||||
})
|
||||
}
|
||||
@ -614,8 +598,7 @@ impl<'w> From<TicksMut<'w>> for Ticks<'w> {
|
||||
pub struct Res<'w, T: ?Sized + Resource> {
|
||||
pub(crate) value: &'w T,
|
||||
pub(crate) ticks: Ticks<'w>,
|
||||
#[cfg(feature = "track_location")]
|
||||
pub(crate) changed_by: &'static Location<'static>,
|
||||
pub(crate) changed_by: MaybeLocation<&'w &'static Location<'static>>,
|
||||
}
|
||||
|
||||
impl<'w, T: Resource> Res<'w, T> {
|
||||
@ -631,7 +614,6 @@ impl<'w, T: Resource> Res<'w, T> {
|
||||
Self {
|
||||
value: this.value,
|
||||
ticks: this.ticks.clone(),
|
||||
#[cfg(feature = "track_location")]
|
||||
changed_by: this.changed_by,
|
||||
}
|
||||
}
|
||||
@ -649,8 +631,7 @@ impl<'w, T: Resource> From<ResMut<'w, T>> for Res<'w, T> {
|
||||
Self {
|
||||
value: res.value,
|
||||
ticks: res.ticks.into(),
|
||||
#[cfg(feature = "track_location")]
|
||||
changed_by: res.changed_by,
|
||||
changed_by: res.changed_by.map(|changed_by| &*changed_by),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -662,7 +643,6 @@ impl<'w, T: Resource> From<Res<'w, T>> for Ref<'w, T> {
|
||||
Self {
|
||||
value: res.value,
|
||||
ticks: res.ticks,
|
||||
#[cfg(feature = "track_location")]
|
||||
changed_by: res.changed_by,
|
||||
}
|
||||
}
|
||||
@ -695,8 +675,7 @@ impl_debug!(Res<'w, T>, Resource);
|
||||
pub struct ResMut<'w, T: ?Sized + Resource> {
|
||||
pub(crate) value: &'w mut T,
|
||||
pub(crate) ticks: TicksMut<'w>,
|
||||
#[cfg(feature = "track_location")]
|
||||
pub(crate) changed_by: &'w mut &'static Location<'static>,
|
||||
pub(crate) changed_by: MaybeLocation<&'w mut &'static Location<'static>>,
|
||||
}
|
||||
|
||||
impl<'w, 'a, T: Resource> IntoIterator for &'a ResMut<'w, T>
|
||||
@ -736,7 +715,6 @@ impl<'w, T: Resource> From<ResMut<'w, T>> for Mut<'w, T> {
|
||||
Mut {
|
||||
value: other.value,
|
||||
ticks: other.ticks,
|
||||
#[cfg(feature = "track_location")]
|
||||
changed_by: other.changed_by,
|
||||
}
|
||||
}
|
||||
@ -756,8 +734,7 @@ impl<'w, T: Resource> From<ResMut<'w, T>> for Mut<'w, T> {
|
||||
pub struct NonSendMut<'w, T: ?Sized + 'static> {
|
||||
pub(crate) value: &'w mut T,
|
||||
pub(crate) ticks: TicksMut<'w>,
|
||||
#[cfg(feature = "track_location")]
|
||||
pub(crate) changed_by: &'w mut &'static Location<'static>,
|
||||
pub(crate) changed_by: MaybeLocation<&'w mut &'static Location<'static>>,
|
||||
}
|
||||
|
||||
change_detection_impl!(NonSendMut<'w, T>, T,);
|
||||
@ -772,7 +749,6 @@ impl<'w, T: 'static> From<NonSendMut<'w, T>> for Mut<'w, T> {
|
||||
Mut {
|
||||
value: other.value,
|
||||
ticks: other.ticks,
|
||||
#[cfg(feature = "track_location")]
|
||||
changed_by: other.changed_by,
|
||||
}
|
||||
}
|
||||
@ -805,8 +781,7 @@ impl<'w, T: 'static> From<NonSendMut<'w, T>> for Mut<'w, T> {
|
||||
pub struct Ref<'w, T: ?Sized> {
|
||||
pub(crate) value: &'w T,
|
||||
pub(crate) ticks: Ticks<'w>,
|
||||
#[cfg(feature = "track_location")]
|
||||
pub(crate) changed_by: &'static Location<'static>,
|
||||
pub(crate) changed_by: MaybeLocation<&'w &'static Location<'static>>,
|
||||
}
|
||||
|
||||
impl<'w, T: ?Sized> Ref<'w, T> {
|
||||
@ -823,7 +798,6 @@ impl<'w, T: ?Sized> Ref<'w, T> {
|
||||
Ref {
|
||||
value: f(self.value),
|
||||
ticks: self.ticks,
|
||||
#[cfg(feature = "track_location")]
|
||||
changed_by: self.changed_by,
|
||||
}
|
||||
}
|
||||
@ -845,7 +819,7 @@ impl<'w, T: ?Sized> Ref<'w, T> {
|
||||
changed: &'w Tick,
|
||||
last_run: Tick,
|
||||
this_run: Tick,
|
||||
#[cfg(feature = "track_location")] caller: &'static Location<'static>,
|
||||
caller: MaybeLocation<&'w &'static Location<'static>>,
|
||||
) -> Ref<'w, T> {
|
||||
Ref {
|
||||
value,
|
||||
@ -855,7 +829,6 @@ impl<'w, T: ?Sized> Ref<'w, T> {
|
||||
last_run,
|
||||
this_run,
|
||||
},
|
||||
#[cfg(feature = "track_location")]
|
||||
changed_by: caller,
|
||||
}
|
||||
}
|
||||
@ -938,8 +911,7 @@ impl_debug!(Ref<'w, T>,);
|
||||
pub struct Mut<'w, T: ?Sized> {
|
||||
pub(crate) value: &'w mut T,
|
||||
pub(crate) ticks: TicksMut<'w>,
|
||||
#[cfg(feature = "track_location")]
|
||||
pub(crate) changed_by: &'w mut &'static Location<'static>,
|
||||
pub(crate) changed_by: MaybeLocation<&'w mut &'static Location<'static>>,
|
||||
}
|
||||
|
||||
impl<'w, T: ?Sized> Mut<'w, T> {
|
||||
@ -964,7 +936,7 @@ impl<'w, T: ?Sized> Mut<'w, T> {
|
||||
last_changed: &'w mut Tick,
|
||||
last_run: Tick,
|
||||
this_run: Tick,
|
||||
#[cfg(feature = "track_location")] caller: &'w mut &'static Location<'static>,
|
||||
caller: MaybeLocation<&'w mut &'static Location<'static>>,
|
||||
) -> Self {
|
||||
Self {
|
||||
value,
|
||||
@ -974,7 +946,6 @@ impl<'w, T: ?Sized> Mut<'w, T> {
|
||||
last_run,
|
||||
this_run,
|
||||
},
|
||||
#[cfg(feature = "track_location")]
|
||||
changed_by: caller,
|
||||
}
|
||||
}
|
||||
@ -985,8 +956,7 @@ impl<'w, T: ?Sized> From<Mut<'w, T>> for Ref<'w, T> {
|
||||
Self {
|
||||
value: mut_ref.value,
|
||||
ticks: mut_ref.ticks.into(),
|
||||
#[cfg(feature = "track_location")]
|
||||
changed_by: mut_ref.changed_by,
|
||||
changed_by: mut_ref.changed_by.map(|changed_by| &*changed_by),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1032,8 +1002,7 @@ impl_debug!(Mut<'w, T>,);
|
||||
pub struct MutUntyped<'w> {
|
||||
pub(crate) value: PtrMut<'w>,
|
||||
pub(crate) ticks: TicksMut<'w>,
|
||||
#[cfg(feature = "track_location")]
|
||||
pub(crate) changed_by: &'w mut &'static Location<'static>,
|
||||
pub(crate) changed_by: MaybeLocation<&'w mut &'static Location<'static>>,
|
||||
}
|
||||
|
||||
impl<'w> MutUntyped<'w> {
|
||||
@ -1058,8 +1027,7 @@ impl<'w> MutUntyped<'w> {
|
||||
last_run: self.ticks.last_run,
|
||||
this_run: self.ticks.this_run,
|
||||
},
|
||||
#[cfg(feature = "track_location")]
|
||||
changed_by: self.changed_by,
|
||||
changed_by: self.changed_by.as_deref_mut(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -1110,7 +1078,6 @@ impl<'w> MutUntyped<'w> {
|
||||
Mut {
|
||||
value: f(self.value),
|
||||
ticks: self.ticks,
|
||||
#[cfg(feature = "track_location")]
|
||||
changed_by: self.changed_by,
|
||||
}
|
||||
}
|
||||
@ -1125,7 +1092,6 @@ impl<'w> MutUntyped<'w> {
|
||||
value: unsafe { self.value.deref_mut() },
|
||||
ticks: self.ticks,
|
||||
// SAFETY: `caller` is `Aligned`.
|
||||
#[cfg(feature = "track_location")]
|
||||
changed_by: self.changed_by,
|
||||
}
|
||||
}
|
||||
@ -1152,9 +1118,8 @@ impl<'w> DetectChanges for MutUntyped<'w> {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[cfg(feature = "track_location")]
|
||||
fn changed_by(&self) -> &'static Location<'static> {
|
||||
self.changed_by
|
||||
fn changed_by(&self) -> MaybeLocation {
|
||||
self.changed_by.copied()
|
||||
}
|
||||
}
|
||||
|
||||
@ -1165,20 +1130,14 @@ impl<'w> DetectChangesMut for MutUntyped<'w> {
|
||||
#[track_caller]
|
||||
fn set_changed(&mut self) {
|
||||
*self.ticks.changed = self.ticks.this_run;
|
||||
#[cfg(feature = "track_location")]
|
||||
{
|
||||
*self.changed_by = Location::caller();
|
||||
}
|
||||
self.changed_by.assign(MaybeLocation::caller());
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[track_caller]
|
||||
fn set_last_changed(&mut self, last_changed: Tick) {
|
||||
*self.ticks.changed = last_changed;
|
||||
#[cfg(feature = "track_location")]
|
||||
{
|
||||
*self.changed_by = Location::caller();
|
||||
}
|
||||
self.changed_by.assign(MaybeLocation::caller());
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -1201,62 +1160,294 @@ impl<'w, T> From<Mut<'w, T>> for MutUntyped<'w> {
|
||||
MutUntyped {
|
||||
value: value.value.into(),
|
||||
ticks: value.ticks,
|
||||
#[cfg(feature = "track_location")]
|
||||
changed_by: value.changed_by,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A type alias to [`&'static Location<'static>`](std::panic::Location) when the `track_location` feature is
|
||||
/// enabled, and the unit type `()` when it is not.
|
||||
/// A value that contains a `T` if the `track_location` feature is enabled,
|
||||
/// and is a ZST if it is not.
|
||||
///
|
||||
/// This is primarily used in places where `#[cfg(...)]` attributes are not allowed, such as
|
||||
/// function return types. Because unit is a zero-sized type, it is the equivalent of not using a
|
||||
/// `Location` at all.
|
||||
/// The overall API is similar to [`Option`], but whether the value is `Some` or `None` is set at compile
|
||||
/// time and is the same for all values.
|
||||
///
|
||||
/// Please use this type sparingly: prefer normal `#[cfg(...)]` attributes when possible.
|
||||
#[cfg(feature = "track_location")]
|
||||
pub(crate) type MaybeLocation = &'static Location<'static>;
|
||||
/// If the `track_location` feature is disabled, then all functions on this type that return
|
||||
/// an `MaybeLocation` will have an empty body and should be removed by the optimizer.
|
||||
///
|
||||
/// This allows code to be written that will be checked by the compiler even when the feature is disabled,
|
||||
/// but that will be entirely removed during compilation.
|
||||
#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
|
||||
#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||
pub struct MaybeLocation<T: ?Sized = &'static Location<'static>> {
|
||||
#[cfg_attr(feature = "bevy_reflect", reflect(ignore))]
|
||||
marker: PhantomData<T>,
|
||||
#[cfg(feature = "track_location")]
|
||||
value: T,
|
||||
}
|
||||
|
||||
/// A type alias to [`&'static Location<'static>`](std::panic::Location) when the `track_location` feature is
|
||||
/// enabled, and the unit type `()` when it is not.
|
||||
///
|
||||
/// This is primarily used in places where `#[cfg(...)]` attributes are not allowed, such as
|
||||
/// function return types. Because unit is a zero-sized type, it is the equivalent of not using a
|
||||
/// `Location` at all.
|
||||
///
|
||||
/// Please use this type sparingly: prefer normal `#[cfg(...)]` attributes when possible.
|
||||
#[cfg(not(feature = "track_location"))]
|
||||
pub(crate) type MaybeLocation = ();
|
||||
impl<T: core::fmt::Display> core::fmt::Display for MaybeLocation<T> {
|
||||
fn fmt(&self, _f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
#[cfg(feature = "track_location")]
|
||||
{
|
||||
self.value.fmt(_f)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// A type alias to `&UnsafeCell<&'static Location<'static>>` when the `track_location`
|
||||
/// feature is enabled, and the unit type `()` when it is not.
|
||||
///
|
||||
/// See [`MaybeLocation`] for further information.
|
||||
#[cfg(feature = "track_location")]
|
||||
pub(crate) type MaybeUnsafeCellLocation<'a> = &'a UnsafeCell<&'static Location<'static>>;
|
||||
impl<T> MaybeLocation<T> {
|
||||
/// Constructs a new `MaybeLocation` that wraps the given value.
|
||||
///
|
||||
/// This may only accept `Copy` types,
|
||||
/// since it needs to drop the value if the `track_location` feature is disabled,
|
||||
/// and non-`Copy` types cannot be dropped in `const` context.
|
||||
/// Use [`new_with`][Self::new_with] if you need to construct a non-`Copy` value.
|
||||
///
|
||||
/// # See also
|
||||
/// - [`new_with`][Self::new_with] to initialize using a closure.
|
||||
/// - [`new_with_flattened`][Self::new_with_flattened] to initialize using a closure that returns an `Option<MaybeLocation<T>>`.
|
||||
#[inline]
|
||||
pub const fn new(_value: T) -> Self
|
||||
where
|
||||
T: Copy,
|
||||
{
|
||||
Self {
|
||||
#[cfg(feature = "track_location")]
|
||||
value: _value,
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// A type alias to `&UnsafeCell<&'static Location<'static>>` when the `track_location`
|
||||
/// feature is enabled, and the unit type `()` when it is not.
|
||||
///
|
||||
/// See [`MaybeLocation`] for further information.
|
||||
#[cfg(not(feature = "track_location"))]
|
||||
pub(crate) type MaybeUnsafeCellLocation<'a> = ();
|
||||
/// Constructs a new `MaybeLocation` that wraps the result of the given closure.
|
||||
///
|
||||
/// # See also
|
||||
/// - [`new`][Self::new] to initialize using a value.
|
||||
/// - [`new_with_flattened`][Self::new_with_flattened] to initialize using a closure that returns an `Option<MaybeLocation<T>>`.
|
||||
#[inline]
|
||||
pub fn new_with(_f: impl FnOnce() -> T) -> Self {
|
||||
Self {
|
||||
#[cfg(feature = "track_location")]
|
||||
value: _f(),
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// A type alias to `ThinSlicePtr<'w, UnsafeCell<&'static Location<'static>>>` when the
|
||||
/// `track_location` feature is enabled, and the unit type `()` when it is not.
|
||||
///
|
||||
/// See [`MaybeLocation`] for further information.
|
||||
#[cfg(feature = "track_location")]
|
||||
pub(crate) type MaybeThinSlicePtrLocation<'w> =
|
||||
ThinSlicePtr<'w, UnsafeCell<&'static Location<'static>>>;
|
||||
/// Maps an `MaybeLocation<T> `to `MaybeLocation<U>` by applying a function to a contained value.
|
||||
#[inline]
|
||||
pub fn map<U>(self, _f: impl FnOnce(T) -> U) -> MaybeLocation<U> {
|
||||
MaybeLocation {
|
||||
#[cfg(feature = "track_location")]
|
||||
value: _f(self.value),
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// A type alias to `ThinSlicePtr<'w, UnsafeCell<&'static Location<'static>>>` when the
|
||||
/// `track_location` feature is enabled, and the unit type `()` when it is not.
|
||||
///
|
||||
/// See [`MaybeLocation`] for further information.
|
||||
#[cfg(not(feature = "track_location"))]
|
||||
pub(crate) type MaybeThinSlicePtrLocation<'w> = ();
|
||||
/// Converts a pair of `MaybeLocation` values to an `MaybeLocation` of a tuple.
|
||||
#[inline]
|
||||
pub fn zip<U>(self, _other: MaybeLocation<U>) -> MaybeLocation<(T, U)> {
|
||||
MaybeLocation {
|
||||
#[cfg(feature = "track_location")]
|
||||
value: (self.value, _other.value),
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the contained value or a default.
|
||||
/// If the `track_location` feature is enabled, this always returns the contained value.
|
||||
/// If it is disabled, this always returns `T::Default()`.
|
||||
#[inline]
|
||||
pub fn unwrap_or_default(self) -> T
|
||||
where
|
||||
T: Default,
|
||||
{
|
||||
self.into_option().unwrap_or_default()
|
||||
}
|
||||
|
||||
/// Converts an `MaybeLocation` to an [`Option`] to allow run-time branching.
|
||||
/// If the `track_location` feature is enabled, this always returns `Some`.
|
||||
/// If it is disabled, this always returns `None`.
|
||||
#[inline]
|
||||
pub fn into_option(self) -> Option<T> {
|
||||
#[cfg(feature = "track_location")]
|
||||
{
|
||||
Some(self.value)
|
||||
}
|
||||
#[cfg(not(feature = "track_location"))]
|
||||
{
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> MaybeLocation<Option<T>> {
|
||||
/// Constructs a new `MaybeLocation` that wraps the result of the given closure.
|
||||
/// If the closure returns `Some`, it unwraps the inner value.
|
||||
///
|
||||
/// # See also
|
||||
/// - [`new`][Self::new] to initialize using a value.
|
||||
/// - [`new_with`][Self::new_with] to initialize using a closure.
|
||||
#[inline]
|
||||
pub fn new_with_flattened(_f: impl FnOnce() -> Option<MaybeLocation<T>>) -> Self {
|
||||
Self {
|
||||
#[cfg(feature = "track_location")]
|
||||
value: _f().map(|value| value.value),
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Transposes a `MaybeLocation` of an [`Option`] into an [`Option`] of a `MaybeLocation`.
|
||||
///
|
||||
/// This can be useful if you want to use the `?` operator to exit early
|
||||
/// if the `track_location` feature is enabled but the value is not found.
|
||||
///
|
||||
/// If the `track_location` feature is enabled,
|
||||
/// this returns `Some` if the inner value is `Some`
|
||||
/// and `None` if the inner value is `None`.
|
||||
///
|
||||
/// If it is disabled, this always returns `Some`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use bevy_ecs::{change_detection::MaybeLocation, world::World};
|
||||
/// # use core::panic::Location;
|
||||
/// #
|
||||
/// # fn test() -> Option<()> {
|
||||
/// let mut world = World::new();
|
||||
/// let entity = world.spawn(()).id();
|
||||
/// let location: MaybeLocation<Option<&'static Location<'static>>> =
|
||||
/// world.entities().entity_get_spawned_or_despawned_by(entity);
|
||||
/// let location: MaybeLocation<&'static Location<'static>> = location.transpose()?;
|
||||
/// # Some(())
|
||||
/// # }
|
||||
/// # test();
|
||||
/// ```
|
||||
///
|
||||
/// # See also
|
||||
///
|
||||
/// - [`into_option`][Self::into_option] to convert to an `Option<Option<T>>`.
|
||||
/// When used with [`Option::flatten`], this will have a similar effect,
|
||||
/// but will return `None` when the `track_location` feature is disabled.
|
||||
#[inline]
|
||||
pub fn transpose(self) -> Option<MaybeLocation<T>> {
|
||||
#[cfg(feature = "track_location")]
|
||||
{
|
||||
self.value.map(|value| MaybeLocation {
|
||||
value,
|
||||
marker: PhantomData,
|
||||
})
|
||||
}
|
||||
#[cfg(not(feature = "track_location"))]
|
||||
{
|
||||
Some(MaybeLocation {
|
||||
marker: PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> MaybeLocation<&T> {
|
||||
/// Maps an `MaybeLocation<&T>` to an `MaybeLocation<T>` by copying the contents.
|
||||
#[inline]
|
||||
pub const fn copied(&self) -> MaybeLocation<T>
|
||||
where
|
||||
T: Copy,
|
||||
{
|
||||
MaybeLocation {
|
||||
#[cfg(feature = "track_location")]
|
||||
value: *self.value,
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> MaybeLocation<&mut T> {
|
||||
/// Maps an `MaybeLocation<&mut T>` to an `MaybeLocation<T>` by copying the contents.
|
||||
#[inline]
|
||||
pub const fn copied(&self) -> MaybeLocation<T>
|
||||
where
|
||||
T: Copy,
|
||||
{
|
||||
MaybeLocation {
|
||||
#[cfg(feature = "track_location")]
|
||||
value: *self.value,
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Assigns the contents of an `MaybeLocation<T>` to an `MaybeLocation<&mut T>`.
|
||||
#[inline]
|
||||
pub fn assign(&mut self, _value: MaybeLocation<T>) {
|
||||
#[cfg(feature = "track_location")]
|
||||
{
|
||||
*self.value = _value.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> MaybeLocation<T> {
|
||||
/// Converts from `&MaybeLocation<T>` to `MaybeLocation<&T>`.
|
||||
#[inline]
|
||||
pub const fn as_ref(&self) -> MaybeLocation<&T> {
|
||||
MaybeLocation {
|
||||
#[cfg(feature = "track_location")]
|
||||
value: &self.value,
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts from `&mut MaybeLocation<T>` to `MaybeLocation<&mut T>`.
|
||||
#[inline]
|
||||
pub const fn as_mut(&mut self) -> MaybeLocation<&mut T> {
|
||||
MaybeLocation {
|
||||
#[cfg(feature = "track_location")]
|
||||
value: &mut self.value,
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts from `&MaybeLocation<T>` to `MaybeLocation<&T::Target>`.
|
||||
#[inline]
|
||||
pub fn as_deref(&self) -> MaybeLocation<&T::Target>
|
||||
where
|
||||
T: Deref,
|
||||
{
|
||||
MaybeLocation {
|
||||
#[cfg(feature = "track_location")]
|
||||
value: &*self.value,
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts from `&mut MaybeLocation<T>` to `MaybeLocation<&mut T::Target>`.
|
||||
#[inline]
|
||||
pub fn as_deref_mut(&mut self) -> MaybeLocation<&mut T::Target>
|
||||
where
|
||||
T: DerefMut,
|
||||
{
|
||||
MaybeLocation {
|
||||
#[cfg(feature = "track_location")]
|
||||
value: &mut *self.value,
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MaybeLocation {
|
||||
/// Returns the source location of the caller of this function. If that function's caller is
|
||||
/// annotated then its call location will be returned, and so on up the stack to the first call
|
||||
/// within a non-tracked function body.
|
||||
#[inline]
|
||||
#[track_caller]
|
||||
pub fn caller() -> Self {
|
||||
// Note that this cannot use `new_with`, since `FnOnce` invocations cannot be annotated with `#[track_caller]`.
|
||||
MaybeLocation {
|
||||
#[cfg(feature = "track_location")]
|
||||
value: Location::caller(),
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
@ -1264,12 +1455,11 @@ mod tests {
|
||||
use bevy_ptr::PtrMut;
|
||||
use bevy_reflect::{FromType, ReflectFromPtr};
|
||||
use core::ops::{Deref, DerefMut};
|
||||
#[cfg(feature = "track_location")]
|
||||
use core::panic::Location;
|
||||
|
||||
use crate::{
|
||||
change_detection::{
|
||||
Mut, NonSendMut, Ref, ResMut, TicksMut, CHECK_TICK_THRESHOLD, MAX_CHANGE_AGE,
|
||||
MaybeLocation, Mut, NonSendMut, Ref, ResMut, TicksMut, CHECK_TICK_THRESHOLD,
|
||||
MAX_CHANGE_AGE,
|
||||
},
|
||||
component::{Component, ComponentTicks, Tick},
|
||||
system::{IntoSystem, Single, System},
|
||||
@ -1395,14 +1585,12 @@ mod tests {
|
||||
this_run: Tick::new(4),
|
||||
};
|
||||
let mut res = R {};
|
||||
#[cfg(feature = "track_location")]
|
||||
let mut caller = Location::caller();
|
||||
let mut caller = MaybeLocation::caller();
|
||||
|
||||
let res_mut = ResMut {
|
||||
value: &mut res,
|
||||
ticks,
|
||||
#[cfg(feature = "track_location")]
|
||||
changed_by: &mut caller,
|
||||
changed_by: caller.as_mut(),
|
||||
};
|
||||
|
||||
let into_mut: Mut<R> = res_mut.into();
|
||||
@ -1419,8 +1607,7 @@ mod tests {
|
||||
changed: Tick::new(3),
|
||||
};
|
||||
let mut res = R {};
|
||||
#[cfg(feature = "track_location")]
|
||||
let mut caller = Location::caller();
|
||||
let mut caller = MaybeLocation::caller();
|
||||
|
||||
let val = Mut::new(
|
||||
&mut res,
|
||||
@ -1428,8 +1615,7 @@ mod tests {
|
||||
&mut component_ticks.changed,
|
||||
Tick::new(2), // last_run
|
||||
Tick::new(4), // this_run
|
||||
#[cfg(feature = "track_location")]
|
||||
&mut caller,
|
||||
caller.as_mut(),
|
||||
);
|
||||
|
||||
assert!(!val.is_added());
|
||||
@ -1449,14 +1635,12 @@ mod tests {
|
||||
this_run: Tick::new(4),
|
||||
};
|
||||
let mut res = R {};
|
||||
#[cfg(feature = "track_location")]
|
||||
let mut caller = Location::caller();
|
||||
let mut caller = MaybeLocation::caller();
|
||||
|
||||
let non_send_mut = NonSendMut {
|
||||
value: &mut res,
|
||||
ticks,
|
||||
#[cfg(feature = "track_location")]
|
||||
changed_by: &mut caller,
|
||||
changed_by: caller.as_mut(),
|
||||
};
|
||||
|
||||
let into_mut: Mut<R> = non_send_mut.into();
|
||||
@ -1485,14 +1669,12 @@ mod tests {
|
||||
};
|
||||
|
||||
let mut outer = Outer(0);
|
||||
#[cfg(feature = "track_location")]
|
||||
let mut caller = Location::caller();
|
||||
let mut caller = MaybeLocation::caller();
|
||||
|
||||
let ptr = Mut {
|
||||
value: &mut outer,
|
||||
ticks,
|
||||
#[cfg(feature = "track_location")]
|
||||
changed_by: &mut caller,
|
||||
changed_by: caller.as_mut(),
|
||||
};
|
||||
assert!(!ptr.is_changed());
|
||||
|
||||
@ -1575,14 +1757,12 @@ mod tests {
|
||||
};
|
||||
|
||||
let mut value: i32 = 5;
|
||||
#[cfg(feature = "track_location")]
|
||||
let mut caller = Location::caller();
|
||||
let mut caller = MaybeLocation::caller();
|
||||
|
||||
let value = MutUntyped {
|
||||
value: PtrMut::from(&mut value),
|
||||
ticks,
|
||||
#[cfg(feature = "track_location")]
|
||||
changed_by: &mut caller,
|
||||
changed_by: caller.as_mut(),
|
||||
};
|
||||
|
||||
let reflect_from_ptr = <ReflectFromPtr as FromType<i32>>::from_type();
|
||||
@ -1613,14 +1793,12 @@ mod tests {
|
||||
this_run: Tick::new(4),
|
||||
};
|
||||
let mut c = C {};
|
||||
#[cfg(feature = "track_location")]
|
||||
let mut caller = Location::caller();
|
||||
let mut caller = MaybeLocation::caller();
|
||||
|
||||
let mut_typed = Mut {
|
||||
value: &mut c,
|
||||
ticks,
|
||||
#[cfg(feature = "track_location")]
|
||||
changed_by: &mut caller,
|
||||
changed_by: caller.as_mut(),
|
||||
};
|
||||
|
||||
let into_mut: MutUntyped = mut_typed.into();
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
use crate::{
|
||||
archetype::ArchetypeFlags,
|
||||
bundle::BundleInfo,
|
||||
change_detection::MAX_CHANGE_AGE,
|
||||
change_detection::{MaybeLocation, MAX_CHANGE_AGE},
|
||||
entity::{ComponentCloneCtx, Entity},
|
||||
query::DebugCheckedUnwrap,
|
||||
resource::Resource,
|
||||
@ -28,7 +28,6 @@ use core::{
|
||||
fmt::Debug,
|
||||
marker::PhantomData,
|
||||
mem::needs_drop,
|
||||
panic::Location,
|
||||
};
|
||||
use disqualified::ShortName;
|
||||
use thiserror::Error;
|
||||
@ -544,7 +543,7 @@ pub struct HookContext {
|
||||
/// The [`ComponentId`] this hook was invoked for.
|
||||
pub component_id: ComponentId,
|
||||
/// The caller location is `Some` if the `track_caller` feature is enabled.
|
||||
pub caller: Option<&'static Location<'static>>,
|
||||
pub caller: MaybeLocation,
|
||||
}
|
||||
|
||||
/// [`World`]-mutating functions that run as part of lifecycle events of a [`Component`].
|
||||
@ -1936,17 +1935,9 @@ pub enum RequiredComponentsError {
|
||||
}
|
||||
|
||||
/// A Required Component constructor. See [`Component`] for details.
|
||||
#[cfg(feature = "track_location")]
|
||||
#[derive(Clone)]
|
||||
pub struct RequiredComponentConstructor(
|
||||
pub Arc<dyn Fn(&mut Table, &mut SparseSets, Tick, TableRow, Entity, &'static Location<'static>)>,
|
||||
);
|
||||
|
||||
/// A Required Component constructor. See [`Component`] for details.
|
||||
#[cfg(not(feature = "track_location"))]
|
||||
#[derive(Clone)]
|
||||
pub struct RequiredComponentConstructor(
|
||||
pub Arc<dyn Fn(&mut Table, &mut SparseSets, Tick, TableRow, Entity)>,
|
||||
pub Arc<dyn Fn(&mut Table, &mut SparseSets, Tick, TableRow, Entity, MaybeLocation)>,
|
||||
);
|
||||
|
||||
impl RequiredComponentConstructor {
|
||||
@ -1966,17 +1957,9 @@ impl RequiredComponentConstructor {
|
||||
change_tick: Tick,
|
||||
table_row: TableRow,
|
||||
entity: Entity,
|
||||
#[cfg(feature = "track_location")] caller: &'static Location<'static>,
|
||||
caller: MaybeLocation,
|
||||
) {
|
||||
(self.0)(
|
||||
table,
|
||||
sparse_sets,
|
||||
change_tick,
|
||||
table_row,
|
||||
entity,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
(self.0)(table, sparse_sets, change_tick, table_row, entity, caller);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2080,20 +2063,15 @@ impl RequiredComponents {
|
||||
#[cfg(feature = "portable-atomic")]
|
||||
use alloc::boxed::Box;
|
||||
|
||||
#[cfg(feature = "track_location")]
|
||||
type Constructor = dyn for<'a, 'b> Fn(
|
||||
&'a mut Table,
|
||||
&'b mut SparseSets,
|
||||
Tick,
|
||||
TableRow,
|
||||
Entity,
|
||||
&'static Location<'static>,
|
||||
MaybeLocation,
|
||||
);
|
||||
|
||||
#[cfg(not(feature = "track_location"))]
|
||||
type Constructor =
|
||||
dyn for<'a, 'b> Fn(&'a mut Table, &'b mut SparseSets, Tick, TableRow, Entity);
|
||||
|
||||
#[cfg(feature = "portable-atomic")]
|
||||
type Intermediate<T> = Box<T>;
|
||||
|
||||
@ -2101,12 +2079,7 @@ impl RequiredComponents {
|
||||
type Intermediate<T> = Arc<T>;
|
||||
|
||||
let boxed: Intermediate<Constructor> = Intermediate::new(
|
||||
move |table,
|
||||
sparse_sets,
|
||||
change_tick,
|
||||
table_row,
|
||||
entity,
|
||||
#[cfg(feature = "track_location")] caller| {
|
||||
move |table, sparse_sets, change_tick, table_row, entity, caller| {
|
||||
OwningPtr::make(constructor(), |ptr| {
|
||||
// SAFETY: This will only be called in the context of `BundleInfo::write_components`, which will
|
||||
// pass in a valid table_row and entity requiring a C constructor
|
||||
@ -2122,7 +2095,6 @@ impl RequiredComponents {
|
||||
component_id,
|
||||
C::STORAGE_TYPE,
|
||||
ptr,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
}
|
||||
|
||||
@ -72,6 +72,7 @@ pub use unique_slice::*;
|
||||
|
||||
use crate::{
|
||||
archetype::{ArchetypeId, ArchetypeRow},
|
||||
change_detection::MaybeLocation,
|
||||
identifier::{
|
||||
error::IdentifierError,
|
||||
kinds::IdKind,
|
||||
@ -82,12 +83,9 @@ use crate::{
|
||||
};
|
||||
use alloc::vec::Vec;
|
||||
use bevy_platform_support::sync::atomic::Ordering;
|
||||
use core::{fmt, hash::Hash, mem, num::NonZero};
|
||||
use core::{fmt, hash::Hash, mem, num::NonZero, panic::Location};
|
||||
use log::warn;
|
||||
|
||||
#[cfg(feature = "track_location")]
|
||||
use core::panic::Location;
|
||||
|
||||
#[cfg(feature = "serialize")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
@ -984,24 +982,25 @@ impl Entities {
|
||||
|
||||
/// Sets the source code location from which this entity has last been spawned
|
||||
/// or despawned.
|
||||
#[cfg(feature = "track_location")]
|
||||
#[inline]
|
||||
pub(crate) fn set_spawned_or_despawned_by(&mut self, index: u32, caller: &'static Location) {
|
||||
pub(crate) fn set_spawned_or_despawned_by(&mut self, index: u32, caller: MaybeLocation) {
|
||||
caller.map(|caller| {
|
||||
let meta = self
|
||||
.meta
|
||||
.get_mut(index as usize)
|
||||
.expect("Entity index invalid");
|
||||
meta.spawned_or_despawned_by = Some(caller);
|
||||
meta.spawned_or_despawned_by = MaybeLocation::new(Some(caller));
|
||||
});
|
||||
}
|
||||
|
||||
/// Returns the source code location from which this entity has last been spawned
|
||||
/// or despawned. Returns `None` if its index has been reused by another entity
|
||||
/// or if this entity has never existed.
|
||||
#[cfg(feature = "track_location")]
|
||||
pub fn entity_get_spawned_or_despawned_by(
|
||||
&self,
|
||||
entity: Entity,
|
||||
) -> Option<&'static Location<'static>> {
|
||||
) -> MaybeLocation<Option<&'static Location<'static>>> {
|
||||
MaybeLocation::new_with_flattened(|| {
|
||||
self.meta
|
||||
.get(entity.index() as usize)
|
||||
.filter(|meta|
|
||||
@ -1009,7 +1008,9 @@ impl Entities {
|
||||
(meta.generation == entity.generation)
|
||||
|| (meta.location.archetype_id == ArchetypeId::INVALID)
|
||||
&& (meta.generation == IdentifierMask::inc_masked_high_by(entity.generation, 1)))
|
||||
.and_then(|meta| meta.spawned_or_despawned_by)
|
||||
.map(|meta| meta.spawned_or_despawned_by)
|
||||
})
|
||||
.map(Option::flatten)
|
||||
}
|
||||
|
||||
/// Constructs a message explaining why an entity does not exists, if known.
|
||||
@ -1018,7 +1019,6 @@ impl Entities {
|
||||
_entity: Entity,
|
||||
) -> EntityDoesNotExistDetails {
|
||||
EntityDoesNotExistDetails {
|
||||
#[cfg(feature = "track_location")]
|
||||
location: self.entity_get_spawned_or_despawned_by(_entity),
|
||||
}
|
||||
}
|
||||
@ -1028,26 +1028,22 @@ impl Entities {
|
||||
/// regarding an entity that did not exist.
|
||||
#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||
pub struct EntityDoesNotExistDetails {
|
||||
#[cfg(feature = "track_location")]
|
||||
location: Option<&'static Location<'static>>,
|
||||
location: MaybeLocation<Option<&'static Location<'static>>>,
|
||||
}
|
||||
|
||||
impl fmt::Display for EntityDoesNotExistDetails {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
#[cfg(feature = "track_location")]
|
||||
if let Some(location) = self.location {
|
||||
write!(f, "was despawned by {location}")
|
||||
} else {
|
||||
write!(
|
||||
match self.location.into_option() {
|
||||
Some(Some(location)) => write!(f, "was despawned by {location}"),
|
||||
Some(None) => write!(
|
||||
f,
|
||||
"does not exist (index has been reused or was never spawned)"
|
||||
)
|
||||
}
|
||||
#[cfg(not(feature = "track_location"))]
|
||||
write!(
|
||||
),
|
||||
None => write!(
|
||||
f,
|
||||
"does not exist (enable `track_location` feature for more details)"
|
||||
)
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1058,8 +1054,7 @@ struct EntityMeta {
|
||||
/// The current location of the [`Entity`]
|
||||
pub location: EntityLocation,
|
||||
/// Location of the last spawn or despawn of this entity
|
||||
#[cfg(feature = "track_location")]
|
||||
spawned_or_despawned_by: Option<&'static Location<'static>>,
|
||||
spawned_or_despawned_by: MaybeLocation<Option<&'static Location<'static>>>,
|
||||
}
|
||||
|
||||
impl EntityMeta {
|
||||
@ -1067,8 +1062,7 @@ impl EntityMeta {
|
||||
const EMPTY: EntityMeta = EntityMeta {
|
||||
generation: NonZero::<u32>::MIN,
|
||||
location: EntityLocation::INVALID,
|
||||
#[cfg(feature = "track_location")]
|
||||
spawned_or_despawned_by: None,
|
||||
spawned_or_despawned_by: MaybeLocation::new(None),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -1,10 +1,9 @@
|
||||
use crate::change_detection::MaybeLocation;
|
||||
use crate::component::ComponentId;
|
||||
use crate::world::World;
|
||||
use crate::{component::Component, traversal::Traversal};
|
||||
#[cfg(feature = "bevy_reflect")]
|
||||
use bevy_reflect::Reflect;
|
||||
#[cfg(feature = "track_location")]
|
||||
use core::panic::Location;
|
||||
use core::{
|
||||
cmp::Ordering,
|
||||
fmt,
|
||||
@ -105,8 +104,7 @@ pub struct EventId<E: Event> {
|
||||
// This value corresponds to the order in which each event was added to the world.
|
||||
pub id: usize,
|
||||
/// The source code location that triggered this event.
|
||||
#[cfg(feature = "track_location")]
|
||||
pub caller: &'static Location<'static>,
|
||||
pub caller: MaybeLocation,
|
||||
#[cfg_attr(feature = "bevy_reflect", reflect(ignore))]
|
||||
pub(super) _marker: PhantomData<E>,
|
||||
}
|
||||
|
||||
@ -1,10 +1,9 @@
|
||||
use alloc::vec::Vec;
|
||||
use bevy_ecs::{
|
||||
change_detection::MaybeLocation,
|
||||
event::{Event, EventCursor, EventId, EventInstance},
|
||||
resource::Resource,
|
||||
};
|
||||
#[cfg(feature = "track_location")]
|
||||
use core::panic::Location;
|
||||
use core::{
|
||||
marker::PhantomData,
|
||||
ops::{Deref, DerefMut},
|
||||
@ -123,21 +122,12 @@ impl<E: Event> Events<E> {
|
||||
/// This method returns the [ID](`EventId`) of the sent `event`.
|
||||
#[track_caller]
|
||||
pub fn send(&mut self, event: E) -> EventId<E> {
|
||||
self.send_with_caller(
|
||||
event,
|
||||
#[cfg(feature = "track_location")]
|
||||
Location::caller(),
|
||||
)
|
||||
self.send_with_caller(event, MaybeLocation::caller())
|
||||
}
|
||||
|
||||
pub(crate) fn send_with_caller(
|
||||
&mut self,
|
||||
event: E,
|
||||
#[cfg(feature = "track_location")] caller: &'static Location<'static>,
|
||||
) -> EventId<E> {
|
||||
pub(crate) fn send_with_caller(&mut self, event: E, caller: MaybeLocation) -> EventId<E> {
|
||||
let event_id = EventId {
|
||||
id: self.event_count,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
_marker: PhantomData,
|
||||
};
|
||||
@ -307,8 +297,7 @@ impl<E: Event> Extend<E> for Events<E> {
|
||||
let events = iter.into_iter().map(|event| {
|
||||
let event_id = EventId {
|
||||
id: event_count,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller: Location::caller(),
|
||||
caller: MaybeLocation::caller(),
|
||||
_marker: PhantomData,
|
||||
};
|
||||
event_count += 1;
|
||||
@ -378,8 +367,7 @@ impl<E: Event> Iterator for SendBatchIds<E> {
|
||||
|
||||
let result = Some(EventId {
|
||||
id: self.last_count,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller: Location::caller(),
|
||||
caller: MaybeLocation::caller(),
|
||||
_marker: PhantomData,
|
||||
});
|
||||
|
||||
|
||||
@ -8,6 +8,7 @@ pub use runner::*;
|
||||
|
||||
use crate::{
|
||||
archetype::ArchetypeFlags,
|
||||
change_detection::MaybeLocation,
|
||||
component::ComponentId,
|
||||
entity::hash_map::EntityHashMap,
|
||||
prelude::*,
|
||||
@ -24,9 +25,6 @@ use core::{
|
||||
};
|
||||
use smallvec::SmallVec;
|
||||
|
||||
#[cfg(feature = "track_location")]
|
||||
use core::panic::Location;
|
||||
|
||||
/// Type containing triggered [`Event`] information for a given run of an [`Observer`]. This contains the
|
||||
/// [`Event`] data itself. If it was triggered for a specific [`Entity`], it includes that as well. It also
|
||||
/// contains event propagation information. See [`Trigger::propagate`] for more information.
|
||||
@ -143,8 +141,7 @@ impl<'w, E, B: Bundle> Trigger<'w, E, B> {
|
||||
}
|
||||
|
||||
/// Returns the source code location that triggered this observer.
|
||||
#[cfg(feature = "track_location")]
|
||||
pub fn caller(&self) -> &'static Location<'static> {
|
||||
pub fn caller(&self) -> MaybeLocation {
|
||||
self.trigger.caller
|
||||
}
|
||||
}
|
||||
@ -335,10 +332,8 @@ pub struct ObserverTrigger {
|
||||
components: SmallVec<[ComponentId; 2]>,
|
||||
/// The entity the trigger targeted.
|
||||
pub target: Entity,
|
||||
|
||||
/// The location of the source code that triggered the obserer.
|
||||
#[cfg(feature = "track_location")]
|
||||
pub caller: &'static Location<'static>,
|
||||
pub caller: MaybeLocation,
|
||||
}
|
||||
|
||||
impl ObserverTrigger {
|
||||
@ -415,7 +410,7 @@ impl Observers {
|
||||
components: impl Iterator<Item = ComponentId> + Clone,
|
||||
data: &mut T,
|
||||
propagate: &mut bool,
|
||||
#[cfg(feature = "track_location")] caller: &'static Location<'static>,
|
||||
caller: MaybeLocation,
|
||||
) {
|
||||
// SAFETY: You cannot get a mutable reference to `observers` from `DeferredWorld`
|
||||
let (mut world, observers) = unsafe {
|
||||
@ -440,7 +435,6 @@ impl Observers {
|
||||
event_type,
|
||||
components: components.clone().collect(),
|
||||
target,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
},
|
||||
data.into(),
|
||||
@ -565,28 +559,14 @@ impl World {
|
||||
/// If you need to use the event after triggering it, use [`World::trigger_ref`] instead.
|
||||
#[track_caller]
|
||||
pub fn trigger<E: Event>(&mut self, event: E) {
|
||||
self.trigger_with_caller(
|
||||
event,
|
||||
#[cfg(feature = "track_location")]
|
||||
Location::caller(),
|
||||
);
|
||||
self.trigger_with_caller(event, MaybeLocation::caller());
|
||||
}
|
||||
|
||||
pub(crate) fn trigger_with_caller<E: Event>(
|
||||
&mut self,
|
||||
mut event: E,
|
||||
#[cfg(feature = "track_location")] caller: &'static Location<'static>,
|
||||
) {
|
||||
pub(crate) fn trigger_with_caller<E: Event>(&mut self, mut event: E, caller: MaybeLocation) {
|
||||
let event_id = E::register_component_id(self);
|
||||
// SAFETY: We just registered `event_id` with the type of `event`
|
||||
unsafe {
|
||||
self.trigger_targets_dynamic_ref_with_caller(
|
||||
event_id,
|
||||
&mut event,
|
||||
(),
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
self.trigger_targets_dynamic_ref_with_caller(event_id, &mut event, (), caller);
|
||||
}
|
||||
}
|
||||
|
||||
@ -608,30 +588,19 @@ impl World {
|
||||
/// If you need to use the event after triggering it, use [`World::trigger_targets_ref`] instead.
|
||||
#[track_caller]
|
||||
pub fn trigger_targets<E: Event>(&mut self, event: E, targets: impl TriggerTargets) {
|
||||
self.trigger_targets_with_caller(
|
||||
event,
|
||||
targets,
|
||||
#[cfg(feature = "track_location")]
|
||||
Location::caller(),
|
||||
);
|
||||
self.trigger_targets_with_caller(event, targets, MaybeLocation::caller());
|
||||
}
|
||||
|
||||
pub(crate) fn trigger_targets_with_caller<E: Event>(
|
||||
&mut self,
|
||||
mut event: E,
|
||||
targets: impl TriggerTargets,
|
||||
#[cfg(feature = "track_location")] caller: &'static Location<'static>,
|
||||
caller: MaybeLocation,
|
||||
) {
|
||||
let event_id = E::register_component_id(self);
|
||||
// SAFETY: We just registered `event_id` with the type of `event`
|
||||
unsafe {
|
||||
self.trigger_targets_dynamic_ref_with_caller(
|
||||
event_id,
|
||||
&mut event,
|
||||
targets,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
self.trigger_targets_dynamic_ref_with_caller(event_id, &mut event, targets, caller);
|
||||
}
|
||||
}
|
||||
|
||||
@ -689,8 +658,7 @@ impl World {
|
||||
event_id,
|
||||
event_data,
|
||||
targets,
|
||||
#[cfg(feature = "track_location")]
|
||||
Location::caller(),
|
||||
MaybeLocation::caller(),
|
||||
);
|
||||
}
|
||||
|
||||
@ -702,7 +670,7 @@ impl World {
|
||||
event_id: ComponentId,
|
||||
event_data: &mut E,
|
||||
targets: Targets,
|
||||
#[cfg(feature = "track_location")] caller: &'static Location<'static>,
|
||||
caller: MaybeLocation,
|
||||
) {
|
||||
let mut world = DeferredWorld::from(self);
|
||||
if targets.entities().is_empty() {
|
||||
@ -714,7 +682,6 @@ impl World {
|
||||
targets.components(),
|
||||
event_data,
|
||||
false,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
};
|
||||
@ -728,7 +695,6 @@ impl World {
|
||||
targets.components(),
|
||||
event_data,
|
||||
E::AUTO_PROPAGATE,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
};
|
||||
@ -858,14 +824,13 @@ impl World {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use alloc::{vec, vec::Vec};
|
||||
#[cfg(feature = "track_location")]
|
||||
use core::panic::Location;
|
||||
|
||||
use bevy_platform_support::collections::HashMap;
|
||||
use bevy_ptr::OwningPtr;
|
||||
|
||||
use crate::component::ComponentId;
|
||||
use crate::{
|
||||
change_detection::MaybeLocation,
|
||||
observer::{Observer, ObserverDescriptor, ObserverState, OnReplace},
|
||||
prelude::*,
|
||||
traversal::Traversal,
|
||||
@ -1615,13 +1580,12 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "track_location")]
|
||||
#[track_caller]
|
||||
fn observer_caller_location_event() {
|
||||
#[derive(Event)]
|
||||
struct EventA;
|
||||
|
||||
let caller = Location::caller();
|
||||
let caller = MaybeLocation::caller();
|
||||
let mut world = World::new();
|
||||
world.add_observer(move |trigger: Trigger<EventA>| {
|
||||
assert_eq!(trigger.caller(), caller);
|
||||
@ -1630,13 +1594,12 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "track_location")]
|
||||
#[track_caller]
|
||||
fn observer_caller_location_command_archetype_move() {
|
||||
#[derive(Component)]
|
||||
struct Component;
|
||||
|
||||
let caller = Location::caller();
|
||||
let caller = MaybeLocation::caller();
|
||||
let mut world = World::new();
|
||||
world.add_observer(move |trigger: Trigger<OnAdd, Component>| {
|
||||
assert_eq!(trigger.caller(), caller);
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
archetype::{Archetype, Archetypes},
|
||||
bundle::Bundle,
|
||||
change_detection::{MaybeThinSlicePtrLocation, Ticks, TicksMut},
|
||||
change_detection::{MaybeLocation, Ticks, TicksMut},
|
||||
component::{Component, ComponentId, Components, Mutable, StorageType, Tick},
|
||||
entity::{Entities, Entity, EntityLocation},
|
||||
query::{Access, DebugCheckedUnwrap, FilteredAccess, WorldQuery},
|
||||
@ -12,7 +12,7 @@ use crate::{
|
||||
},
|
||||
};
|
||||
use bevy_ptr::{ThinSlicePtr, UnsafeCellDeref};
|
||||
use core::{cell::UnsafeCell, marker::PhantomData};
|
||||
use core::{cell::UnsafeCell, marker::PhantomData, panic::Location};
|
||||
use smallvec::SmallVec;
|
||||
use variadics_please::all_tuples;
|
||||
|
||||
@ -1251,7 +1251,7 @@ pub struct RefFetch<'w, T: Component> {
|
||||
ThinSlicePtr<'w, UnsafeCell<T>>,
|
||||
ThinSlicePtr<'w, UnsafeCell<Tick>>,
|
||||
ThinSlicePtr<'w, UnsafeCell<Tick>>,
|
||||
MaybeThinSlicePtrLocation<'w>,
|
||||
MaybeLocation<ThinSlicePtr<'w, UnsafeCell<&'static Location<'static>>>>,
|
||||
)>,
|
||||
// T::STORAGE_TYPE = StorageType::SparseSet
|
||||
// Can be `None` when the component has never been inserted
|
||||
@ -1337,10 +1337,9 @@ unsafe impl<'__w, T: Component> WorldQuery for Ref<'__w, T> {
|
||||
column.get_data_slice(table.entity_count()).into(),
|
||||
column.get_added_ticks_slice(table.entity_count()).into(),
|
||||
column.get_changed_ticks_slice(table.entity_count()).into(),
|
||||
#[cfg(feature = "track_location")]
|
||||
column.get_changed_by_slice(table.entity_count()).into(),
|
||||
#[cfg(not(feature = "track_location"))]
|
||||
(),
|
||||
column
|
||||
.get_changed_by_slice(table.entity_count())
|
||||
.map(Into::into),
|
||||
));
|
||||
// SAFETY: set_table is only called when T::STORAGE_TYPE = StorageType::Table
|
||||
unsafe { fetch.components.set_table(table_data) };
|
||||
@ -1392,7 +1391,7 @@ unsafe impl<'__w, T: Component> QueryData for Ref<'__w, T> {
|
||||
fetch.components.extract(
|
||||
|table| {
|
||||
// SAFETY: set_table was previously called
|
||||
let (table_components, added_ticks, changed_ticks, _callers) =
|
||||
let (table_components, added_ticks, changed_ticks, callers) =
|
||||
unsafe { table.debug_checked_unwrap() };
|
||||
|
||||
// SAFETY: The caller ensures `table_row` is in range.
|
||||
@ -1402,8 +1401,7 @@ unsafe impl<'__w, T: Component> QueryData for Ref<'__w, T> {
|
||||
// SAFETY: The caller ensures `table_row` is in range.
|
||||
let changed = unsafe { changed_ticks.get(table_row.as_usize()) };
|
||||
// SAFETY: The caller ensures `table_row` is in range.
|
||||
#[cfg(feature = "track_location")]
|
||||
let caller = unsafe { _callers.get(table_row.as_usize()) };
|
||||
let caller = callers.map(|callers| unsafe { callers.get(table_row.as_usize()) });
|
||||
|
||||
Ref {
|
||||
value: component.deref(),
|
||||
@ -1413,13 +1411,12 @@ unsafe impl<'__w, T: Component> QueryData for Ref<'__w, T> {
|
||||
this_run: fetch.this_run,
|
||||
last_run: fetch.last_run,
|
||||
},
|
||||
#[cfg(feature = "track_location")]
|
||||
changed_by: caller.deref(),
|
||||
changed_by: caller.map(|caller| caller.deref()),
|
||||
}
|
||||
},
|
||||
|sparse_set| {
|
||||
// SAFETY: The caller ensures `entity` is in range and has the component.
|
||||
let (component, ticks, _caller) = unsafe {
|
||||
let (component, ticks, caller) = unsafe {
|
||||
sparse_set
|
||||
.debug_checked_unwrap()
|
||||
.get_with_ticks(entity)
|
||||
@ -1429,8 +1426,7 @@ unsafe impl<'__w, T: Component> QueryData for Ref<'__w, T> {
|
||||
Ref {
|
||||
value: component.deref(),
|
||||
ticks: Ticks::from_tick_cells(ticks, fetch.last_run, fetch.this_run),
|
||||
#[cfg(feature = "track_location")]
|
||||
changed_by: _caller.deref(),
|
||||
changed_by: caller.map(|caller| caller.deref()),
|
||||
}
|
||||
},
|
||||
)
|
||||
@ -1449,7 +1445,7 @@ pub struct WriteFetch<'w, T: Component> {
|
||||
ThinSlicePtr<'w, UnsafeCell<T>>,
|
||||
ThinSlicePtr<'w, UnsafeCell<Tick>>,
|
||||
ThinSlicePtr<'w, UnsafeCell<Tick>>,
|
||||
MaybeThinSlicePtrLocation<'w>,
|
||||
MaybeLocation<ThinSlicePtr<'w, UnsafeCell<&'static Location<'static>>>>,
|
||||
)>,
|
||||
// T::STORAGE_TYPE = StorageType::SparseSet
|
||||
// Can be `None` when the component has never been inserted
|
||||
@ -1535,10 +1531,9 @@ unsafe impl<'__w, T: Component> WorldQuery for &'__w mut T {
|
||||
column.get_data_slice(table.entity_count()).into(),
|
||||
column.get_added_ticks_slice(table.entity_count()).into(),
|
||||
column.get_changed_ticks_slice(table.entity_count()).into(),
|
||||
#[cfg(feature = "track_location")]
|
||||
column.get_changed_by_slice(table.entity_count()).into(),
|
||||
#[cfg(not(feature = "track_location"))]
|
||||
(),
|
||||
column
|
||||
.get_changed_by_slice(table.entity_count())
|
||||
.map(Into::into),
|
||||
));
|
||||
// SAFETY: set_table is only called when T::STORAGE_TYPE = StorageType::Table
|
||||
unsafe { fetch.components.set_table(table_data) };
|
||||
@ -1590,7 +1585,7 @@ unsafe impl<'__w, T: Component<Mutability = Mutable>> QueryData for &'__w mut T
|
||||
fetch.components.extract(
|
||||
|table| {
|
||||
// SAFETY: set_table was previously called
|
||||
let (table_components, added_ticks, changed_ticks, _callers) =
|
||||
let (table_components, added_ticks, changed_ticks, callers) =
|
||||
unsafe { table.debug_checked_unwrap() };
|
||||
|
||||
// SAFETY: The caller ensures `table_row` is in range.
|
||||
@ -1600,8 +1595,7 @@ unsafe impl<'__w, T: Component<Mutability = Mutable>> QueryData for &'__w mut T
|
||||
// SAFETY: The caller ensures `table_row` is in range.
|
||||
let changed = unsafe { changed_ticks.get(table_row.as_usize()) };
|
||||
// SAFETY: The caller ensures `table_row` is in range.
|
||||
#[cfg(feature = "track_location")]
|
||||
let caller = unsafe { _callers.get(table_row.as_usize()) };
|
||||
let caller = callers.map(|callers| unsafe { callers.get(table_row.as_usize()) });
|
||||
|
||||
Mut {
|
||||
value: component.deref_mut(),
|
||||
@ -1611,13 +1605,12 @@ unsafe impl<'__w, T: Component<Mutability = Mutable>> QueryData for &'__w mut T
|
||||
this_run: fetch.this_run,
|
||||
last_run: fetch.last_run,
|
||||
},
|
||||
#[cfg(feature = "track_location")]
|
||||
changed_by: caller.deref_mut(),
|
||||
changed_by: caller.map(|caller| caller.deref_mut()),
|
||||
}
|
||||
},
|
||||
|sparse_set| {
|
||||
// SAFETY: The caller ensures `entity` is in range and has the component.
|
||||
let (component, ticks, _caller) = unsafe {
|
||||
let (component, ticks, caller) = unsafe {
|
||||
sparse_set
|
||||
.debug_checked_unwrap()
|
||||
.get_with_ticks(entity)
|
||||
@ -1627,8 +1620,7 @@ unsafe impl<'__w, T: Component<Mutability = Mutable>> QueryData for &'__w mut T
|
||||
Mut {
|
||||
value: component.assert_unique().deref_mut(),
|
||||
ticks: TicksMut::from_tick_cells(ticks, fetch.last_run, fetch.this_run),
|
||||
#[cfg(feature = "track_location")]
|
||||
changed_by: _caller.deref_mut(),
|
||||
changed_by: caller.map(|caller| caller.deref_mut()),
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
@ -1,14 +1,12 @@
|
||||
use crate::{
|
||||
archetype::ArchetypeComponentId,
|
||||
change_detection::{MaybeLocation, MaybeUnsafeCellLocation, MutUntyped, TicksMut},
|
||||
change_detection::{MaybeLocation, MutUntyped, TicksMut},
|
||||
component::{ComponentId, ComponentTicks, Components, Tick, TickCells},
|
||||
storage::{blob_vec::BlobVec, SparseSet},
|
||||
};
|
||||
use alloc::string::String;
|
||||
use bevy_ptr::{OwningPtr, Ptr, UnsafeCellDeref};
|
||||
#[cfg(feature = "track_location")]
|
||||
use core::panic::Location;
|
||||
use core::{cell::UnsafeCell, mem::ManuallyDrop};
|
||||
use core::{cell::UnsafeCell, mem::ManuallyDrop, panic::Location};
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use std::thread::ThreadId;
|
||||
@ -30,8 +28,7 @@ pub struct ResourceData<const SEND: bool> {
|
||||
id: ArchetypeComponentId,
|
||||
#[cfg(feature = "std")]
|
||||
origin_thread_id: Option<ThreadId>,
|
||||
#[cfg(feature = "track_location")]
|
||||
changed_by: UnsafeCell<&'static Location<'static>>,
|
||||
changed_by: MaybeLocation<UnsafeCell<&'static Location<'static>>>,
|
||||
}
|
||||
|
||||
impl<const SEND: bool> Drop for ResourceData<SEND> {
|
||||
@ -136,7 +133,11 @@ impl<const SEND: bool> ResourceData<SEND> {
|
||||
#[inline]
|
||||
pub(crate) fn get_with_ticks(
|
||||
&self,
|
||||
) -> Option<(Ptr<'_>, TickCells<'_>, MaybeUnsafeCellLocation<'_>)> {
|
||||
) -> Option<(
|
||||
Ptr<'_>,
|
||||
TickCells<'_>,
|
||||
MaybeLocation<&UnsafeCell<&'static Location<'static>>>,
|
||||
)> {
|
||||
self.is_present().then(|| {
|
||||
self.validate_access();
|
||||
(
|
||||
@ -146,10 +147,7 @@ impl<const SEND: bool> ResourceData<SEND> {
|
||||
added: &self.added_ticks,
|
||||
changed: &self.changed_ticks,
|
||||
},
|
||||
#[cfg(feature = "track_location")]
|
||||
&self.changed_by,
|
||||
#[cfg(not(feature = "track_location"))]
|
||||
(),
|
||||
self.changed_by.as_ref(),
|
||||
)
|
||||
})
|
||||
}
|
||||
@ -160,15 +158,14 @@ impl<const SEND: bool> ResourceData<SEND> {
|
||||
/// If `SEND` is false, this will panic if a value is present and is not accessed from the
|
||||
/// original thread it was inserted in.
|
||||
pub(crate) fn get_mut(&mut self, last_run: Tick, this_run: Tick) -> Option<MutUntyped<'_>> {
|
||||
let (ptr, ticks, _caller) = self.get_with_ticks()?;
|
||||
let (ptr, ticks, caller) = self.get_with_ticks()?;
|
||||
Some(MutUntyped {
|
||||
// SAFETY: We have exclusive access to the underlying storage.
|
||||
value: unsafe { ptr.assert_unique() },
|
||||
// SAFETY: We have exclusive access to the underlying storage.
|
||||
ticks: unsafe { TicksMut::from_tick_cells(ticks, last_run, this_run) },
|
||||
#[cfg(feature = "track_location")]
|
||||
// SAFETY: We have exclusive access to the underlying storage.
|
||||
changed_by: unsafe { _caller.deref_mut() },
|
||||
changed_by: unsafe { caller.map(|caller| caller.deref_mut()) },
|
||||
})
|
||||
}
|
||||
|
||||
@ -186,7 +183,7 @@ impl<const SEND: bool> ResourceData<SEND> {
|
||||
&mut self,
|
||||
value: OwningPtr<'_>,
|
||||
change_tick: Tick,
|
||||
#[cfg(feature = "track_location")] caller: &'static Location,
|
||||
caller: MaybeLocation,
|
||||
) {
|
||||
if self.is_present() {
|
||||
self.validate_access();
|
||||
@ -205,10 +202,11 @@ impl<const SEND: bool> ResourceData<SEND> {
|
||||
*self.added_ticks.deref_mut() = change_tick;
|
||||
}
|
||||
*self.changed_ticks.deref_mut() = change_tick;
|
||||
#[cfg(feature = "track_location")]
|
||||
{
|
||||
*self.changed_by.deref_mut() = caller;
|
||||
}
|
||||
|
||||
self.changed_by
|
||||
.as_ref()
|
||||
.map(|changed_by| changed_by.deref_mut())
|
||||
.assign(caller);
|
||||
}
|
||||
|
||||
/// Inserts a value into the resource with a pre-existing change tick. If a
|
||||
@ -225,7 +223,7 @@ impl<const SEND: bool> ResourceData<SEND> {
|
||||
&mut self,
|
||||
value: OwningPtr<'_>,
|
||||
change_ticks: ComponentTicks,
|
||||
#[cfg(feature = "track_location")] caller: &'static Location,
|
||||
caller: MaybeLocation,
|
||||
) {
|
||||
if self.is_present() {
|
||||
self.validate_access();
|
||||
@ -244,10 +242,10 @@ impl<const SEND: bool> ResourceData<SEND> {
|
||||
}
|
||||
*self.added_ticks.deref_mut() = change_ticks.added;
|
||||
*self.changed_ticks.deref_mut() = change_ticks.changed;
|
||||
#[cfg(feature = "track_location")]
|
||||
{
|
||||
*self.changed_by.deref_mut() = caller;
|
||||
}
|
||||
self.changed_by
|
||||
.as_ref()
|
||||
.map(|changed_by| changed_by.deref_mut())
|
||||
.assign(caller);
|
||||
}
|
||||
|
||||
/// Removes a value from the resource, if present.
|
||||
@ -267,11 +265,11 @@ impl<const SEND: bool> ResourceData<SEND> {
|
||||
// SAFETY: We've already validated that the row is present.
|
||||
let res = unsafe { self.data.swap_remove_and_forget_unchecked(Self::ROW) };
|
||||
|
||||
let caller = self
|
||||
.changed_by
|
||||
.as_ref()
|
||||
// SAFETY: This function is being called through an exclusive mutable reference to Self
|
||||
#[cfg(feature = "track_location")]
|
||||
let caller = unsafe { *self.changed_by.deref_mut() };
|
||||
#[cfg(not(feature = "track_location"))]
|
||||
let caller = ();
|
||||
.map(|changed_by| unsafe { *changed_by.deref_mut() });
|
||||
|
||||
// SAFETY: This function is being called through an exclusive mutable reference to Self, which
|
||||
// makes it sound to read these ticks.
|
||||
@ -392,8 +390,7 @@ impl<const SEND: bool> Resources<SEND> {
|
||||
id: f(),
|
||||
#[cfg(feature = "std")]
|
||||
origin_thread_id: None,
|
||||
#[cfg(feature = "track_location")]
|
||||
changed_by: UnsafeCell::new(Location::caller())
|
||||
changed_by: MaybeLocation::caller().map(UnsafeCell::new),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -1,14 +1,12 @@
|
||||
use crate::{
|
||||
change_detection::MaybeUnsafeCellLocation,
|
||||
change_detection::MaybeLocation,
|
||||
component::{ComponentId, ComponentInfo, ComponentTicks, Tick, TickCells},
|
||||
entity::Entity,
|
||||
storage::{Column, TableRow},
|
||||
};
|
||||
use alloc::{boxed::Box, vec::Vec};
|
||||
use bevy_ptr::{OwningPtr, Ptr};
|
||||
#[cfg(feature = "track_location")]
|
||||
use core::panic::Location;
|
||||
use core::{cell::UnsafeCell, hash::Hash, marker::PhantomData};
|
||||
use core::{cell::UnsafeCell, hash::Hash, marker::PhantomData, panic::Location};
|
||||
use nonmax::NonMaxUsize;
|
||||
|
||||
type EntityIndex = u32;
|
||||
@ -170,26 +168,16 @@ impl ComponentSparseSet {
|
||||
entity: Entity,
|
||||
value: OwningPtr<'_>,
|
||||
change_tick: Tick,
|
||||
#[cfg(feature = "track_location")] caller: &'static Location<'static>,
|
||||
caller: MaybeLocation,
|
||||
) {
|
||||
if let Some(&dense_index) = self.sparse.get(entity.index()) {
|
||||
#[cfg(debug_assertions)]
|
||||
assert_eq!(entity, self.entities[dense_index.as_usize()]);
|
||||
self.dense.replace(
|
||||
dense_index,
|
||||
value,
|
||||
change_tick,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
self.dense.replace(dense_index, value, change_tick, caller);
|
||||
} else {
|
||||
let dense_index = self.dense.len();
|
||||
self.dense.push(
|
||||
value,
|
||||
ComponentTicks::new(change_tick),
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
self.dense
|
||||
.push(value, ComponentTicks::new(change_tick), caller);
|
||||
self.sparse
|
||||
.insert(entity.index(), TableRow::from_usize(dense_index));
|
||||
#[cfg(debug_assertions)]
|
||||
@ -238,7 +226,11 @@ impl ComponentSparseSet {
|
||||
pub fn get_with_ticks(
|
||||
&self,
|
||||
entity: Entity,
|
||||
) -> Option<(Ptr<'_>, TickCells<'_>, MaybeUnsafeCellLocation<'_>)> {
|
||||
) -> Option<(
|
||||
Ptr<'_>,
|
||||
TickCells<'_>,
|
||||
MaybeLocation<&UnsafeCell<&'static Location<'static>>>,
|
||||
)> {
|
||||
let dense_index = *self.sparse.get(entity.index())?;
|
||||
#[cfg(debug_assertions)]
|
||||
assert_eq!(entity, self.entities[dense_index.as_usize()]);
|
||||
@ -250,10 +242,7 @@ impl ComponentSparseSet {
|
||||
added: self.dense.get_added_tick_unchecked(dense_index),
|
||||
changed: self.dense.get_changed_tick_unchecked(dense_index),
|
||||
},
|
||||
#[cfg(feature = "track_location")]
|
||||
self.dense.get_changed_by_unchecked(dense_index),
|
||||
#[cfg(not(feature = "track_location"))]
|
||||
(),
|
||||
))
|
||||
}
|
||||
}
|
||||
@ -298,16 +287,17 @@ impl ComponentSparseSet {
|
||||
///
|
||||
/// Returns `None` if `entity` does not have a component in the sparse set.
|
||||
#[inline]
|
||||
#[cfg(feature = "track_location")]
|
||||
pub fn get_changed_by(
|
||||
&self,
|
||||
entity: Entity,
|
||||
) -> Option<&UnsafeCell<&'static Location<'static>>> {
|
||||
) -> MaybeLocation<Option<&UnsafeCell<&'static Location<'static>>>> {
|
||||
MaybeLocation::new_with_flattened(|| {
|
||||
let dense_index = *self.sparse.get(entity.index())?;
|
||||
#[cfg(debug_assertions)]
|
||||
assert_eq!(entity, self.entities[dense_index.as_usize()]);
|
||||
// SAFETY: if the sparse index points to something in the dense vec, it exists
|
||||
unsafe { Some(self.dense.get_changed_by_unchecked(dense_index)) }
|
||||
})
|
||||
}
|
||||
|
||||
/// Removes the `entity` from this sparse set and returns a pointer to the associated value (if
|
||||
|
||||
@ -1,10 +1,12 @@
|
||||
use super::*;
|
||||
use crate::{
|
||||
change_detection::MaybeLocation,
|
||||
component::TickCells,
|
||||
storage::{blob_array::BlobArray, thin_array_ptr::ThinArrayPtr},
|
||||
};
|
||||
use alloc::vec::Vec;
|
||||
use bevy_ptr::PtrMut;
|
||||
use core::panic::Location;
|
||||
|
||||
/// Very similar to a normal [`Column`], but with the capacities and lengths cut out for performance reasons.
|
||||
///
|
||||
@ -17,8 +19,7 @@ pub struct ThinColumn {
|
||||
pub(super) data: BlobArray,
|
||||
pub(super) added_ticks: ThinArrayPtr<UnsafeCell<Tick>>,
|
||||
pub(super) changed_ticks: ThinArrayPtr<UnsafeCell<Tick>>,
|
||||
#[cfg(feature = "track_location")]
|
||||
pub(super) changed_by: ThinArrayPtr<UnsafeCell<&'static Location<'static>>>,
|
||||
pub(super) changed_by: MaybeLocation<ThinArrayPtr<UnsafeCell<&'static Location<'static>>>>,
|
||||
}
|
||||
|
||||
impl ThinColumn {
|
||||
@ -31,8 +32,7 @@ impl ThinColumn {
|
||||
},
|
||||
added_ticks: ThinArrayPtr::with_capacity(capacity),
|
||||
changed_ticks: ThinArrayPtr::with_capacity(capacity),
|
||||
#[cfg(feature = "track_location")]
|
||||
changed_by: ThinArrayPtr::with_capacity(capacity),
|
||||
changed_by: MaybeLocation::new_with(|| ThinArrayPtr::with_capacity(capacity)),
|
||||
}
|
||||
}
|
||||
|
||||
@ -54,9 +54,9 @@ impl ThinColumn {
|
||||
.swap_remove_unchecked_nonoverlapping(row.as_usize(), last_element_index);
|
||||
self.changed_ticks
|
||||
.swap_remove_unchecked_nonoverlapping(row.as_usize(), last_element_index);
|
||||
#[cfg(feature = "track_location")]
|
||||
self.changed_by
|
||||
.swap_remove_unchecked_nonoverlapping(row.as_usize(), last_element_index);
|
||||
self.changed_by.as_mut().map(|changed_by| {
|
||||
changed_by.swap_remove_unchecked_nonoverlapping(row.as_usize(), last_element_index);
|
||||
});
|
||||
}
|
||||
|
||||
/// Swap-remove and drop the removed element.
|
||||
@ -76,9 +76,9 @@ impl ThinColumn {
|
||||
.swap_remove_and_drop_unchecked(row.as_usize(), last_element_index);
|
||||
self.changed_ticks
|
||||
.swap_remove_and_drop_unchecked(row.as_usize(), last_element_index);
|
||||
#[cfg(feature = "track_location")]
|
||||
self.changed_by
|
||||
.swap_remove_and_drop_unchecked(row.as_usize(), last_element_index);
|
||||
self.changed_by.as_mut().map(|changed_by| {
|
||||
changed_by.swap_remove_and_drop_unchecked(row.as_usize(), last_element_index);
|
||||
});
|
||||
}
|
||||
|
||||
/// Swap-remove and forget the removed element.
|
||||
@ -99,9 +99,9 @@ impl ThinColumn {
|
||||
.swap_remove_unchecked(row.as_usize(), last_element_index);
|
||||
self.changed_ticks
|
||||
.swap_remove_unchecked(row.as_usize(), last_element_index);
|
||||
#[cfg(feature = "track_location")]
|
||||
self.changed_by
|
||||
.swap_remove_unchecked(row.as_usize(), last_element_index);
|
||||
.as_mut()
|
||||
.map(|changed_by| changed_by.swap_remove_unchecked(row.as_usize(), last_element_index));
|
||||
}
|
||||
|
||||
/// Call [`realloc`](std::alloc::realloc) to expand / shrink the memory allocation for this [`ThinColumn`]
|
||||
@ -117,8 +117,9 @@ impl ThinColumn {
|
||||
self.data.realloc(current_capacity, new_capacity);
|
||||
self.added_ticks.realloc(current_capacity, new_capacity);
|
||||
self.changed_ticks.realloc(current_capacity, new_capacity);
|
||||
#[cfg(feature = "track_location")]
|
||||
self.changed_by.realloc(current_capacity, new_capacity);
|
||||
self.changed_by
|
||||
.as_mut()
|
||||
.map(|changed_by| changed_by.realloc(current_capacity, new_capacity));
|
||||
}
|
||||
|
||||
/// Call [`alloc`](std::alloc::alloc) to allocate memory for this [`ThinColumn`]
|
||||
@ -127,8 +128,9 @@ impl ThinColumn {
|
||||
self.data.alloc(new_capacity);
|
||||
self.added_ticks.alloc(new_capacity);
|
||||
self.changed_ticks.alloc(new_capacity);
|
||||
#[cfg(feature = "track_location")]
|
||||
self.changed_by.alloc(new_capacity);
|
||||
self.changed_by
|
||||
.as_mut()
|
||||
.map(|changed_by| changed_by.alloc(new_capacity));
|
||||
}
|
||||
|
||||
/// Writes component data to the column at the given row.
|
||||
@ -144,7 +146,7 @@ impl ThinColumn {
|
||||
row: TableRow,
|
||||
data: OwningPtr<'_>,
|
||||
tick: Tick,
|
||||
#[cfg(feature = "track_location")] caller: &'static Location<'static>,
|
||||
caller: MaybeLocation,
|
||||
) {
|
||||
self.data.initialize_unchecked(row.as_usize(), data);
|
||||
*self.added_ticks.get_unchecked_mut(row.as_usize()).get_mut() = tick;
|
||||
@ -152,10 +154,10 @@ impl ThinColumn {
|
||||
.changed_ticks
|
||||
.get_unchecked_mut(row.as_usize())
|
||||
.get_mut() = tick;
|
||||
#[cfg(feature = "track_location")]
|
||||
{
|
||||
*self.changed_by.get_unchecked_mut(row.as_usize()).get_mut() = caller;
|
||||
}
|
||||
self.changed_by
|
||||
.as_mut()
|
||||
.map(|changed_by| changed_by.get_unchecked_mut(row.as_usize()).get_mut())
|
||||
.assign(caller);
|
||||
}
|
||||
|
||||
/// Writes component data to the column at given row. Assumes the slot is initialized, drops the previous value.
|
||||
@ -169,17 +171,17 @@ impl ThinColumn {
|
||||
row: TableRow,
|
||||
data: OwningPtr<'_>,
|
||||
change_tick: Tick,
|
||||
#[cfg(feature = "track_location")] caller: &'static Location<'static>,
|
||||
caller: MaybeLocation,
|
||||
) {
|
||||
self.data.replace_unchecked(row.as_usize(), data);
|
||||
*self
|
||||
.changed_ticks
|
||||
.get_unchecked_mut(row.as_usize())
|
||||
.get_mut() = change_tick;
|
||||
#[cfg(feature = "track_location")]
|
||||
{
|
||||
*self.changed_by.get_unchecked_mut(row.as_usize()).get_mut() = caller;
|
||||
}
|
||||
self.changed_by
|
||||
.as_mut()
|
||||
.map(|changed_by| changed_by.get_unchecked_mut(row.as_usize()).get_mut())
|
||||
.assign(caller);
|
||||
}
|
||||
|
||||
/// Removes the element from `other` at `src_row` and inserts it
|
||||
@ -218,13 +220,13 @@ impl ThinColumn {
|
||||
.swap_remove_unchecked(src_row.as_usize(), other_last_element_index);
|
||||
self.changed_ticks
|
||||
.initialize_unchecked(dst_row.as_usize(), changed_tick);
|
||||
#[cfg(feature = "track_location")]
|
||||
let changed_by = other
|
||||
.changed_by
|
||||
self.changed_by.as_mut().zip(other.changed_by.as_mut()).map(
|
||||
|(self_changed_by, other_changed_by)| {
|
||||
let changed_by = other_changed_by
|
||||
.swap_remove_unchecked(src_row.as_usize(), other_last_element_index);
|
||||
#[cfg(feature = "track_location")]
|
||||
self.changed_by
|
||||
.initialize_unchecked(dst_row.as_usize(), changed_by);
|
||||
self_changed_by.initialize_unchecked(dst_row.as_usize(), changed_by);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// Call [`Tick::check_tick`] on all of the ticks stored in this column.
|
||||
@ -258,8 +260,9 @@ impl ThinColumn {
|
||||
self.added_ticks.clear_elements(len);
|
||||
self.changed_ticks.clear_elements(len);
|
||||
self.data.clear(len);
|
||||
#[cfg(feature = "track_location")]
|
||||
self.changed_by.clear_elements(len);
|
||||
self.changed_by
|
||||
.as_mut()
|
||||
.map(|changed_by| changed_by.clear_elements(len));
|
||||
}
|
||||
|
||||
/// Because this method needs parameters, it can't be the implementation of the `Drop` trait.
|
||||
@ -273,8 +276,9 @@ impl ThinColumn {
|
||||
self.added_ticks.drop(cap, len);
|
||||
self.changed_ticks.drop(cap, len);
|
||||
self.data.drop(cap, len);
|
||||
#[cfg(feature = "track_location")]
|
||||
self.changed_by.drop(cap, len);
|
||||
self.changed_by
|
||||
.as_mut()
|
||||
.map(|changed_by| changed_by.drop(cap, len));
|
||||
}
|
||||
|
||||
/// Drops the last component in this column.
|
||||
@ -285,8 +289,9 @@ impl ThinColumn {
|
||||
pub(crate) unsafe fn drop_last_component(&mut self, last_element_index: usize) {
|
||||
core::ptr::drop_in_place(self.added_ticks.get_unchecked_raw(last_element_index));
|
||||
core::ptr::drop_in_place(self.changed_ticks.get_unchecked_raw(last_element_index));
|
||||
#[cfg(feature = "track_location")]
|
||||
core::ptr::drop_in_place(self.changed_by.get_unchecked_raw(last_element_index));
|
||||
self.changed_by.as_mut().map(|changed_by| {
|
||||
core::ptr::drop_in_place(changed_by.get_unchecked_raw(last_element_index));
|
||||
});
|
||||
self.data.drop_last_element(last_element_index);
|
||||
}
|
||||
|
||||
@ -319,12 +324,13 @@ impl ThinColumn {
|
||||
///
|
||||
/// # Safety
|
||||
/// - `len` must match the actual length of this column (number of elements stored)
|
||||
#[cfg(feature = "track_location")]
|
||||
pub unsafe fn get_changed_by_slice(
|
||||
&self,
|
||||
len: usize,
|
||||
) -> &[UnsafeCell<&'static Location<'static>>] {
|
||||
self.changed_by.as_slice(len)
|
||||
) -> MaybeLocation<&[UnsafeCell<&'static Location<'static>>]> {
|
||||
self.changed_by
|
||||
.as_ref()
|
||||
.map(|changed_by| changed_by.as_slice(len))
|
||||
}
|
||||
}
|
||||
|
||||
@ -343,8 +349,7 @@ pub struct Column {
|
||||
pub(super) data: BlobVec,
|
||||
pub(super) added_ticks: Vec<UnsafeCell<Tick>>,
|
||||
pub(super) changed_ticks: Vec<UnsafeCell<Tick>>,
|
||||
#[cfg(feature = "track_location")]
|
||||
changed_by: Vec<UnsafeCell<&'static Location<'static>>>,
|
||||
changed_by: MaybeLocation<Vec<UnsafeCell<&'static Location<'static>>>>,
|
||||
}
|
||||
|
||||
impl Column {
|
||||
@ -356,8 +361,7 @@ impl Column {
|
||||
data: unsafe { BlobVec::new(component_info.layout(), component_info.drop(), capacity) },
|
||||
added_ticks: Vec::with_capacity(capacity),
|
||||
changed_ticks: Vec::with_capacity(capacity),
|
||||
#[cfg(feature = "track_location")]
|
||||
changed_by: Vec::with_capacity(capacity),
|
||||
changed_by: MaybeLocation::new_with(|| Vec::with_capacity(capacity)),
|
||||
}
|
||||
}
|
||||
|
||||
@ -378,7 +382,7 @@ impl Column {
|
||||
row: TableRow,
|
||||
data: OwningPtr<'_>,
|
||||
change_tick: Tick,
|
||||
#[cfg(feature = "track_location")] caller: &'static Location<'static>,
|
||||
caller: MaybeLocation,
|
||||
) {
|
||||
debug_assert!(row.as_usize() < self.len());
|
||||
self.data.replace_unchecked(row.as_usize(), data);
|
||||
@ -386,10 +390,10 @@ impl Column {
|
||||
.changed_ticks
|
||||
.get_unchecked_mut(row.as_usize())
|
||||
.get_mut() = change_tick;
|
||||
#[cfg(feature = "track_location")]
|
||||
{
|
||||
*self.changed_by.get_unchecked_mut(row.as_usize()).get_mut() = caller;
|
||||
}
|
||||
self.changed_by
|
||||
.as_mut()
|
||||
.map(|changed_by| changed_by.get_unchecked_mut(row.as_usize()).get_mut())
|
||||
.assign(caller);
|
||||
}
|
||||
|
||||
/// Gets the current number of elements stored in the column.
|
||||
@ -418,8 +422,9 @@ impl Column {
|
||||
self.data.swap_remove_and_drop_unchecked(row.as_usize());
|
||||
self.added_ticks.swap_remove(row.as_usize());
|
||||
self.changed_ticks.swap_remove(row.as_usize());
|
||||
#[cfg(feature = "track_location")]
|
||||
self.changed_by.swap_remove(row.as_usize());
|
||||
self.changed_by
|
||||
.as_mut()
|
||||
.map(|changed_by| changed_by.swap_remove(row.as_usize()));
|
||||
}
|
||||
|
||||
/// Removes an element from the [`Column`] and returns it and its change detection ticks.
|
||||
@ -442,10 +447,10 @@ impl Column {
|
||||
let data = self.data.swap_remove_and_forget_unchecked(row.as_usize());
|
||||
let added = self.added_ticks.swap_remove(row.as_usize()).into_inner();
|
||||
let changed = self.changed_ticks.swap_remove(row.as_usize()).into_inner();
|
||||
#[cfg(feature = "track_location")]
|
||||
let caller = self.changed_by.swap_remove(row.as_usize()).into_inner();
|
||||
#[cfg(not(feature = "track_location"))]
|
||||
let caller = ();
|
||||
let caller = self
|
||||
.changed_by
|
||||
.as_mut()
|
||||
.map(|changed_by| changed_by.swap_remove(row.as_usize()).into_inner());
|
||||
(data, ComponentTicks { added, changed }, caller)
|
||||
}
|
||||
|
||||
@ -457,13 +462,15 @@ impl Column {
|
||||
&mut self,
|
||||
ptr: OwningPtr<'_>,
|
||||
ticks: ComponentTicks,
|
||||
#[cfg(feature = "track_location")] caller: &'static Location<'static>,
|
||||
caller: MaybeLocation,
|
||||
) {
|
||||
self.data.push(ptr);
|
||||
self.added_ticks.push(UnsafeCell::new(ticks.added));
|
||||
self.changed_ticks.push(UnsafeCell::new(ticks.changed));
|
||||
#[cfg(feature = "track_location")]
|
||||
self.changed_by.push(UnsafeCell::new(caller));
|
||||
self.changed_by
|
||||
.as_mut()
|
||||
.zip(caller)
|
||||
.map(|(changed_by, caller)| changed_by.push(UnsafeCell::new(caller)));
|
||||
}
|
||||
|
||||
/// Fetches the data pointer to the first element of the [`Column`].
|
||||
@ -644,8 +651,7 @@ impl Column {
|
||||
self.data.clear();
|
||||
self.added_ticks.clear();
|
||||
self.changed_ticks.clear();
|
||||
#[cfg(feature = "track_location")]
|
||||
self.changed_by.clear();
|
||||
self.changed_by.as_mut().map(Vec::clear);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -666,9 +672,13 @@ impl Column {
|
||||
/// Users of this API must ensure that accesses to each individual element
|
||||
/// adhere to the safety invariants of [`UnsafeCell`].
|
||||
#[inline]
|
||||
#[cfg(feature = "track_location")]
|
||||
pub fn get_changed_by(&self, row: TableRow) -> Option<&UnsafeCell<&'static Location<'static>>> {
|
||||
self.changed_by.get(row.as_usize())
|
||||
pub fn get_changed_by(
|
||||
&self,
|
||||
row: TableRow,
|
||||
) -> MaybeLocation<Option<&UnsafeCell<&'static Location<'static>>>> {
|
||||
self.changed_by
|
||||
.as_ref()
|
||||
.map(|changed_by| changed_by.get(row.as_usize()))
|
||||
}
|
||||
|
||||
/// Fetches the calling location that last changed the value at `row`.
|
||||
@ -678,12 +688,13 @@ impl Column {
|
||||
/// # Safety
|
||||
/// `row` must be within the range `[0, self.len())`.
|
||||
#[inline]
|
||||
#[cfg(feature = "track_location")]
|
||||
pub unsafe fn get_changed_by_unchecked(
|
||||
&self,
|
||||
row: TableRow,
|
||||
) -> &UnsafeCell<&'static Location<'static>> {
|
||||
debug_assert!(row.as_usize() < self.changed_by.len());
|
||||
self.changed_by.get_unchecked(row.as_usize())
|
||||
) -> MaybeLocation<&UnsafeCell<&'static Location<'static>>> {
|
||||
self.changed_by.as_ref().map(|changed_by| {
|
||||
debug_assert!(row.as_usize() < changed_by.len());
|
||||
changed_by.get_unchecked(row.as_usize())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,13 +9,12 @@ use alloc::{boxed::Box, vec, vec::Vec};
|
||||
use bevy_platform_support::collections::HashMap;
|
||||
use bevy_ptr::{OwningPtr, Ptr, UnsafeCellDeref};
|
||||
pub use column::*;
|
||||
#[cfg(feature = "track_location")]
|
||||
use core::panic::Location;
|
||||
use core::{
|
||||
alloc::Layout,
|
||||
cell::UnsafeCell,
|
||||
num::NonZeroUsize,
|
||||
ops::{Index, IndexMut},
|
||||
panic::Location,
|
||||
};
|
||||
mod column;
|
||||
|
||||
@ -390,14 +389,15 @@ impl Table {
|
||||
}
|
||||
|
||||
/// Fetches the calling locations that last changed the each component
|
||||
#[cfg(feature = "track_location")]
|
||||
pub fn get_changed_by_slice_for(
|
||||
&self,
|
||||
component_id: ComponentId,
|
||||
) -> Option<&[UnsafeCell<&'static Location<'static>>]> {
|
||||
) -> MaybeLocation<Option<&[UnsafeCell<&'static Location<'static>>]>> {
|
||||
MaybeLocation::new_with_flattened(|| {
|
||||
self.get_column(component_id)
|
||||
// SAFETY: `self.len()` is guaranteed to be the len of the locations array
|
||||
.map(|col| unsafe { col.get_changed_by_slice(self.entity_count()) })
|
||||
})
|
||||
}
|
||||
|
||||
/// Get the specific [`change tick`](Tick) of the component matching `component_id` in `row`.
|
||||
@ -433,20 +433,22 @@ impl Table {
|
||||
}
|
||||
|
||||
/// Get the specific calling location that changed the component matching `component_id` in `row`
|
||||
#[cfg(feature = "track_location")]
|
||||
pub fn get_changed_by(
|
||||
&self,
|
||||
component_id: ComponentId,
|
||||
row: TableRow,
|
||||
) -> Option<&UnsafeCell<&'static Location<'static>>> {
|
||||
) -> MaybeLocation<Option<&UnsafeCell<&'static Location<'static>>>> {
|
||||
MaybeLocation::new_with_flattened(|| {
|
||||
(row.as_usize() < self.entity_count()).then_some(
|
||||
// SAFETY: `row.as_usize()` < `len`
|
||||
unsafe {
|
||||
self.get_column(component_id)?
|
||||
.changed_by
|
||||
.get_unchecked(row.as_usize())
|
||||
.as_ref()
|
||||
.map(|changed_by| changed_by.get_unchecked(row.as_usize()))
|
||||
},
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
/// Get the [`ComponentTicks`] of the component matching `component_id` in `row`.
|
||||
@ -571,9 +573,12 @@ impl Table {
|
||||
.initialize_unchecked(len, UnsafeCell::new(Tick::new(0)));
|
||||
col.changed_ticks
|
||||
.initialize_unchecked(len, UnsafeCell::new(Tick::new(0)));
|
||||
#[cfg(feature = "track_location")]
|
||||
col.changed_by
|
||||
.initialize_unchecked(len, UnsafeCell::new(Location::caller()));
|
||||
.as_mut()
|
||||
.zip(MaybeLocation::caller())
|
||||
.map(|(changed_by, caller)| {
|
||||
changed_by.initialize_unchecked(len, UnsafeCell::new(caller));
|
||||
});
|
||||
}
|
||||
TableRow::from_usize(len)
|
||||
}
|
||||
@ -816,6 +821,7 @@ impl Drop for Table {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{
|
||||
change_detection::MaybeLocation,
|
||||
component::{Component, Components, Tick},
|
||||
entity::Entity,
|
||||
ptr::OwningPtr,
|
||||
@ -823,9 +829,6 @@ mod tests {
|
||||
};
|
||||
use alloc::vec::Vec;
|
||||
|
||||
#[cfg(feature = "track_location")]
|
||||
use core::panic::Location;
|
||||
|
||||
#[derive(Component)]
|
||||
struct W<T>(T);
|
||||
|
||||
@ -860,8 +863,7 @@ mod tests {
|
||||
row,
|
||||
value_ptr,
|
||||
Tick::new(0),
|
||||
#[cfg(feature = "track_location")]
|
||||
Location::caller(),
|
||||
MaybeLocation::caller(),
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
@ -4,11 +4,9 @@
|
||||
//! It also contains functions that return closures for use with
|
||||
//! [`Commands`](crate::system::Commands).
|
||||
|
||||
#[cfg(feature = "track_location")]
|
||||
use core::panic::Location;
|
||||
|
||||
use crate::{
|
||||
bundle::{Bundle, InsertMode, NoBundleEffect},
|
||||
change_detection::MaybeLocation,
|
||||
entity::Entity,
|
||||
event::{Event, Events},
|
||||
observer::TriggerTargets,
|
||||
@ -113,15 +111,9 @@ where
|
||||
I: IntoIterator + Send + Sync + 'static,
|
||||
I::Item: Bundle<Effect: NoBundleEffect>,
|
||||
{
|
||||
#[cfg(feature = "track_location")]
|
||||
let caller = Location::caller();
|
||||
let caller = MaybeLocation::caller();
|
||||
move |world: &mut World| {
|
||||
SpawnBatchIter::new(
|
||||
world,
|
||||
bundles_iter.into_iter(),
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
SpawnBatchIter::new(world, bundles_iter.into_iter(), caller);
|
||||
}
|
||||
}
|
||||
|
||||
@ -137,15 +129,9 @@ where
|
||||
I: IntoIterator<Item = (Entity, B)> + Send + Sync + 'static,
|
||||
B: Bundle<Effect: NoBundleEffect>,
|
||||
{
|
||||
#[cfg(feature = "track_location")]
|
||||
let caller = Location::caller();
|
||||
let caller = MaybeLocation::caller();
|
||||
move |world: &mut World| -> Result {
|
||||
world.try_insert_batch_with_caller(
|
||||
batch,
|
||||
insert_mode,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
)?;
|
||||
world.try_insert_batch_with_caller(batch, insert_mode, caller)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@ -162,14 +148,9 @@ pub fn init_resource<R: Resource + FromWorld>() -> impl Command {
|
||||
/// A [`Command`] that inserts a [`Resource`] into the world.
|
||||
#[track_caller]
|
||||
pub fn insert_resource<R: Resource>(resource: R) -> impl Command {
|
||||
#[cfg(feature = "track_location")]
|
||||
let caller = Location::caller();
|
||||
let caller = MaybeLocation::caller();
|
||||
move |world: &mut World| {
|
||||
world.insert_resource_with_caller(
|
||||
resource,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
world.insert_resource_with_caller(resource, caller);
|
||||
}
|
||||
}
|
||||
|
||||
@ -267,14 +248,9 @@ pub fn run_schedule(label: impl ScheduleLabel) -> impl Command<Result> {
|
||||
/// A [`Command`] that sends a global [`Trigger`](crate::observer::Trigger) without any targets.
|
||||
#[track_caller]
|
||||
pub fn trigger(event: impl Event) -> impl Command {
|
||||
#[cfg(feature = "track_location")]
|
||||
let caller = Location::caller();
|
||||
let caller = MaybeLocation::caller();
|
||||
move |world: &mut World| {
|
||||
world.trigger_with_caller(
|
||||
event,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
world.trigger_with_caller(event, caller);
|
||||
}
|
||||
}
|
||||
|
||||
@ -283,29 +259,18 @@ pub fn trigger_targets(
|
||||
event: impl Event,
|
||||
targets: impl TriggerTargets + Send + Sync + 'static,
|
||||
) -> impl Command {
|
||||
#[cfg(feature = "track_location")]
|
||||
let caller = Location::caller();
|
||||
let caller = MaybeLocation::caller();
|
||||
move |world: &mut World| {
|
||||
world.trigger_targets_with_caller(
|
||||
event,
|
||||
targets,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
world.trigger_targets_with_caller(event, targets, caller);
|
||||
}
|
||||
}
|
||||
|
||||
/// A [`Command`] that sends an arbitrary [`Event`].
|
||||
#[track_caller]
|
||||
pub fn send_event<E: Event>(event: E) -> impl Command {
|
||||
#[cfg(feature = "track_location")]
|
||||
let caller = Location::caller();
|
||||
let caller = MaybeLocation::caller();
|
||||
move |world: &mut World| {
|
||||
let mut events = world.resource_mut::<Events<E>>();
|
||||
events.send_with_caller(
|
||||
event,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
events.send_with_caller(event, caller);
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,11 +7,9 @@
|
||||
use alloc::vec::Vec;
|
||||
use log::info;
|
||||
|
||||
#[cfg(feature = "track_location")]
|
||||
use core::panic::Location;
|
||||
|
||||
use crate::{
|
||||
bundle::{Bundle, InsertMode},
|
||||
change_detection::MaybeLocation,
|
||||
component::{Component, ComponentId, ComponentInfo},
|
||||
entity::{Entity, EntityClonerBuilder},
|
||||
event::Event,
|
||||
@ -155,15 +153,9 @@ where
|
||||
/// replacing any that were already present.
|
||||
#[track_caller]
|
||||
pub fn insert(bundle: impl Bundle) -> impl EntityCommand {
|
||||
#[cfg(feature = "track_location")]
|
||||
let caller = Location::caller();
|
||||
let caller = MaybeLocation::caller();
|
||||
move |mut entity: EntityWorldMut| {
|
||||
entity.insert_with_caller(
|
||||
bundle,
|
||||
InsertMode::Replace,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
entity.insert_with_caller(bundle, InsertMode::Replace, caller);
|
||||
}
|
||||
}
|
||||
|
||||
@ -171,34 +163,22 @@ pub fn insert(bundle: impl Bundle) -> impl EntityCommand {
|
||||
/// except for any that were already present.
|
||||
#[track_caller]
|
||||
pub fn insert_if_new(bundle: impl Bundle) -> impl EntityCommand {
|
||||
#[cfg(feature = "track_location")]
|
||||
let caller = Location::caller();
|
||||
let caller = MaybeLocation::caller();
|
||||
move |mut entity: EntityWorldMut| {
|
||||
entity.insert_with_caller(
|
||||
bundle,
|
||||
InsertMode::Keep,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
entity.insert_with_caller(bundle, InsertMode::Keep, caller);
|
||||
}
|
||||
}
|
||||
|
||||
/// An [`EntityCommand`] that adds a dynamic component to an entity.
|
||||
#[track_caller]
|
||||
pub fn insert_by_id<T: Send + 'static>(component_id: ComponentId, value: T) -> impl EntityCommand {
|
||||
#[cfg(feature = "track_location")]
|
||||
let caller = Location::caller();
|
||||
let caller = MaybeLocation::caller();
|
||||
move |mut entity: EntityWorldMut| {
|
||||
// SAFETY:
|
||||
// - `component_id` safety is ensured by the caller
|
||||
// - `ptr` is valid within the `make` block
|
||||
OwningPtr::make(value, |ptr| unsafe {
|
||||
entity.insert_by_id_with_caller(
|
||||
component_id,
|
||||
ptr,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
entity.insert_by_id_with_caller(component_id, ptr, caller);
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -207,29 +187,19 @@ pub fn insert_by_id<T: Send + 'static>(component_id: ComponentId, value: T) -> i
|
||||
/// the component's [`FromWorld`] implementation.
|
||||
#[track_caller]
|
||||
pub fn insert_from_world<T: Component + FromWorld>(mode: InsertMode) -> impl EntityCommand {
|
||||
#[cfg(feature = "track_location")]
|
||||
let caller = Location::caller();
|
||||
let caller = MaybeLocation::caller();
|
||||
move |mut entity: EntityWorldMut| {
|
||||
let value = entity.world_scope(|world| T::from_world(world));
|
||||
entity.insert_with_caller(
|
||||
value,
|
||||
mode,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
entity.insert_with_caller(value, mode, caller);
|
||||
}
|
||||
}
|
||||
|
||||
/// An [`EntityCommand`] that removes the components in a [`Bundle`] from an entity.
|
||||
#[track_caller]
|
||||
pub fn remove<T: Bundle>() -> impl EntityCommand {
|
||||
#[cfg(feature = "track_location")]
|
||||
let caller = Location::caller();
|
||||
let caller = MaybeLocation::caller();
|
||||
move |mut entity: EntityWorldMut| {
|
||||
entity.remove_with_caller::<T>(
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
entity.remove_with_caller::<T>(caller);
|
||||
}
|
||||
}
|
||||
|
||||
@ -237,40 +207,27 @@ pub fn remove<T: Bundle>() -> impl EntityCommand {
|
||||
/// as well as the required components for each component removed.
|
||||
#[track_caller]
|
||||
pub fn remove_with_requires<T: Bundle>() -> impl EntityCommand {
|
||||
#[cfg(feature = "track_location")]
|
||||
let caller = Location::caller();
|
||||
let caller = MaybeLocation::caller();
|
||||
move |mut entity: EntityWorldMut| {
|
||||
entity.remove_with_requires_with_caller::<T>(
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
entity.remove_with_requires_with_caller::<T>(caller);
|
||||
}
|
||||
}
|
||||
|
||||
/// An [`EntityCommand`] that removes a dynamic component from an entity.
|
||||
#[track_caller]
|
||||
pub fn remove_by_id(component_id: ComponentId) -> impl EntityCommand {
|
||||
#[cfg(feature = "track_location")]
|
||||
let caller = Location::caller();
|
||||
let caller = MaybeLocation::caller();
|
||||
move |mut entity: EntityWorldMut| {
|
||||
entity.remove_by_id_with_caller(
|
||||
component_id,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
entity.remove_by_id_with_caller(component_id, caller);
|
||||
}
|
||||
}
|
||||
|
||||
/// An [`EntityCommand`] that removes all components from an entity.
|
||||
#[track_caller]
|
||||
pub fn clear() -> impl EntityCommand {
|
||||
#[cfg(feature = "track_location")]
|
||||
let caller = Location::caller();
|
||||
let caller = MaybeLocation::caller();
|
||||
move |mut entity: EntityWorldMut| {
|
||||
entity.clear_with_caller(
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
entity.clear_with_caller(caller);
|
||||
}
|
||||
}
|
||||
|
||||
@ -278,13 +235,9 @@ pub fn clear() -> impl EntityCommand {
|
||||
/// except for those in the given [`Bundle`].
|
||||
#[track_caller]
|
||||
pub fn retain<T: Bundle>() -> impl EntityCommand {
|
||||
#[cfg(feature = "track_location")]
|
||||
let caller = Location::caller();
|
||||
let caller = MaybeLocation::caller();
|
||||
move |mut entity: EntityWorldMut| {
|
||||
entity.retain_with_caller::<T>(
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
entity.retain_with_caller::<T>(caller);
|
||||
}
|
||||
}
|
||||
|
||||
@ -296,13 +249,9 @@ pub fn retain<T: Bundle>() -> impl EntityCommand {
|
||||
/// to despawn descendants. This results in "recursive despawn" behavior.
|
||||
#[track_caller]
|
||||
pub fn despawn() -> impl EntityCommand {
|
||||
#[cfg(feature = "track_location")]
|
||||
let caller = Location::caller();
|
||||
let caller = MaybeLocation::caller();
|
||||
move |entity: EntityWorldMut| {
|
||||
entity.despawn_with_caller(
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
entity.despawn_with_caller(caller);
|
||||
}
|
||||
}
|
||||
|
||||
@ -312,14 +261,9 @@ pub fn despawn() -> impl EntityCommand {
|
||||
pub fn observe<E: Event, B: Bundle, M>(
|
||||
observer: impl IntoObserverSystem<E, B, M>,
|
||||
) -> impl EntityCommand {
|
||||
#[cfg(feature = "track_location")]
|
||||
let caller = Location::caller();
|
||||
let caller = MaybeLocation::caller();
|
||||
move |mut entity: EntityWorldMut| {
|
||||
entity.observe_with_caller(
|
||||
observer,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
entity.observe_with_caller(observer, caller);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -13,13 +13,12 @@ pub use parallel_scope::*;
|
||||
|
||||
use alloc::boxed::Box;
|
||||
use core::marker::PhantomData;
|
||||
use core::panic::Location;
|
||||
use log::error;
|
||||
|
||||
use crate::{
|
||||
self as bevy_ecs,
|
||||
bundle::{Bundle, InsertMode, NoBundleEffect},
|
||||
change_detection::Mut,
|
||||
change_detection::{MaybeLocation, Mut},
|
||||
component::{Component, ComponentId, Mutable},
|
||||
entity::{Entities, Entity, EntityClonerBuilder},
|
||||
event::Event,
|
||||
@ -683,11 +682,10 @@ impl<'w, 's> Commands<'w, 's> {
|
||||
I: IntoIterator<Item = (Entity, B)> + Send + Sync + 'static,
|
||||
B: Bundle<Effect: NoBundleEffect>,
|
||||
{
|
||||
let caller = Location::caller();
|
||||
let caller = MaybeLocation::caller();
|
||||
self.queue(move |world: &mut World| {
|
||||
if let Err(invalid_entities) = world.insert_or_spawn_batch_with_caller(
|
||||
bundles_iter,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
) {
|
||||
error!(
|
||||
|
||||
@ -2,7 +2,7 @@ pub use crate::change_detection::{NonSendMut, Res, ResMut};
|
||||
use crate::{
|
||||
archetype::{Archetype, Archetypes},
|
||||
bundle::Bundles,
|
||||
change_detection::{Ticks, TicksMut},
|
||||
change_detection::{MaybeLocation, Ticks, TicksMut},
|
||||
component::{ComponentId, ComponentTicks, Components, Tick},
|
||||
entity::Entities,
|
||||
query::{
|
||||
@ -21,13 +21,12 @@ use alloc::{borrow::ToOwned, boxed::Box, vec::Vec};
|
||||
pub use bevy_ecs_macros::SystemParam;
|
||||
use bevy_ptr::UnsafeCellDeref;
|
||||
use bevy_utils::synccell::SyncCell;
|
||||
#[cfg(feature = "track_location")]
|
||||
use core::panic::Location;
|
||||
use core::{
|
||||
any::Any,
|
||||
fmt::Debug,
|
||||
marker::PhantomData,
|
||||
ops::{Deref, DerefMut},
|
||||
panic::Location,
|
||||
};
|
||||
use disqualified::ShortName;
|
||||
|
||||
@ -857,7 +856,7 @@ unsafe impl<'a, T: Resource> SystemParam for Res<'a, T> {
|
||||
world: UnsafeWorldCell<'w>,
|
||||
change_tick: Tick,
|
||||
) -> Self::Item<'w, 's> {
|
||||
let (ptr, ticks, _caller) =
|
||||
let (ptr, ticks, caller) =
|
||||
world
|
||||
.get_resource_with_ticks(component_id)
|
||||
.unwrap_or_else(|| {
|
||||
@ -875,8 +874,7 @@ unsafe impl<'a, T: Resource> SystemParam for Res<'a, T> {
|
||||
last_run: system_meta.last_run,
|
||||
this_run: change_tick,
|
||||
},
|
||||
#[cfg(feature = "track_location")]
|
||||
changed_by: _caller.deref(),
|
||||
changed_by: caller.map(|caller| caller.deref()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -902,7 +900,7 @@ unsafe impl<'a, T: Resource> SystemParam for Option<Res<'a, T>> {
|
||||
) -> Self::Item<'w, 's> {
|
||||
world
|
||||
.get_resource_with_ticks(component_id)
|
||||
.map(|(ptr, ticks, _caller)| Res {
|
||||
.map(|(ptr, ticks, caller)| Res {
|
||||
value: ptr.deref(),
|
||||
ticks: Ticks {
|
||||
added: ticks.added.deref(),
|
||||
@ -910,8 +908,7 @@ unsafe impl<'a, T: Resource> SystemParam for Option<Res<'a, T>> {
|
||||
last_run: system_meta.last_run,
|
||||
this_run: change_tick,
|
||||
},
|
||||
#[cfg(feature = "track_location")]
|
||||
changed_by: _caller.deref(),
|
||||
changed_by: caller.map(|caller| caller.deref()),
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -988,7 +985,6 @@ unsafe impl<'a, T: Resource> SystemParam for ResMut<'a, T> {
|
||||
last_run: system_meta.last_run,
|
||||
this_run: change_tick,
|
||||
},
|
||||
#[cfg(feature = "track_location")]
|
||||
changed_by: value.changed_by,
|
||||
}
|
||||
}
|
||||
@ -1020,7 +1016,6 @@ unsafe impl<'a, T: Resource> SystemParam for Option<ResMut<'a, T>> {
|
||||
last_run: system_meta.last_run,
|
||||
this_run: change_tick,
|
||||
},
|
||||
#[cfg(feature = "track_location")]
|
||||
changed_by: value.changed_by,
|
||||
})
|
||||
}
|
||||
@ -1435,8 +1430,7 @@ pub struct NonSend<'w, T: 'static> {
|
||||
ticks: ComponentTicks,
|
||||
last_run: Tick,
|
||||
this_run: Tick,
|
||||
#[cfg(feature = "track_location")]
|
||||
changed_by: &'static Location<'static>,
|
||||
changed_by: MaybeLocation<&'w &'static Location<'static>>,
|
||||
}
|
||||
|
||||
// SAFETY: Only reads a single World non-send resource
|
||||
@ -1463,9 +1457,8 @@ impl<'w, T: 'static> NonSend<'w, T> {
|
||||
}
|
||||
|
||||
/// The location that last caused this to change.
|
||||
#[cfg(feature = "track_location")]
|
||||
pub fn changed_by(&self) -> &'static Location<'static> {
|
||||
self.changed_by
|
||||
pub fn changed_by(&self) -> MaybeLocation {
|
||||
self.changed_by.copied()
|
||||
}
|
||||
}
|
||||
|
||||
@ -1486,8 +1479,7 @@ impl<'a, T> From<NonSendMut<'a, T>> for NonSend<'a, T> {
|
||||
},
|
||||
this_run: nsm.ticks.this_run,
|
||||
last_run: nsm.ticks.last_run,
|
||||
#[cfg(feature = "track_location")]
|
||||
changed_by: nsm.changed_by,
|
||||
changed_by: nsm.changed_by.map(|changed_by| &*changed_by),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1546,7 +1538,7 @@ unsafe impl<'a, T: 'static> SystemParam for NonSend<'a, T> {
|
||||
world: UnsafeWorldCell<'w>,
|
||||
change_tick: Tick,
|
||||
) -> Self::Item<'w, 's> {
|
||||
let (ptr, ticks, _caller) =
|
||||
let (ptr, ticks, caller) =
|
||||
world
|
||||
.get_non_send_with_ticks(component_id)
|
||||
.unwrap_or_else(|| {
|
||||
@ -1562,8 +1554,7 @@ unsafe impl<'a, T: 'static> SystemParam for NonSend<'a, T> {
|
||||
ticks: ticks.read(),
|
||||
last_run: system_meta.last_run,
|
||||
this_run: change_tick,
|
||||
#[cfg(feature = "track_location")]
|
||||
changed_by: _caller.deref(),
|
||||
changed_by: caller.map(|caller| caller.deref()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1589,13 +1580,12 @@ unsafe impl<T: 'static> SystemParam for Option<NonSend<'_, T>> {
|
||||
) -> Self::Item<'w, 's> {
|
||||
world
|
||||
.get_non_send_with_ticks(component_id)
|
||||
.map(|(ptr, ticks, _caller)| NonSend {
|
||||
.map(|(ptr, ticks, caller)| NonSend {
|
||||
value: ptr.deref(),
|
||||
ticks: ticks.read(),
|
||||
last_run: system_meta.last_run,
|
||||
this_run: change_tick,
|
||||
#[cfg(feature = "track_location")]
|
||||
changed_by: _caller.deref(),
|
||||
changed_by: caller.map(|caller| caller.deref()),
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -1657,7 +1647,7 @@ unsafe impl<'a, T: 'static> SystemParam for NonSendMut<'a, T> {
|
||||
world: UnsafeWorldCell<'w>,
|
||||
change_tick: Tick,
|
||||
) -> Self::Item<'w, 's> {
|
||||
let (ptr, ticks, _caller) =
|
||||
let (ptr, ticks, caller) =
|
||||
world
|
||||
.get_non_send_with_ticks(component_id)
|
||||
.unwrap_or_else(|| {
|
||||
@ -1670,8 +1660,7 @@ unsafe impl<'a, T: 'static> SystemParam for NonSendMut<'a, T> {
|
||||
NonSendMut {
|
||||
value: ptr.assert_unique().deref_mut(),
|
||||
ticks: TicksMut::from_tick_cells(ticks, system_meta.last_run, change_tick),
|
||||
#[cfg(feature = "track_location")]
|
||||
changed_by: _caller.deref_mut(),
|
||||
changed_by: caller.map(|caller| caller.deref_mut()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1694,11 +1683,10 @@ unsafe impl<'a, T: 'static> SystemParam for Option<NonSendMut<'a, T>> {
|
||||
) -> Self::Item<'w, 's> {
|
||||
world
|
||||
.get_non_send_with_ticks(component_id)
|
||||
.map(|(ptr, ticks, _caller)| NonSendMut {
|
||||
.map(|(ptr, ticks, caller)| NonSendMut {
|
||||
value: ptr.assert_unique().deref_mut(),
|
||||
ticks: TicksMut::from_tick_cells(ticks, system_meta.last_run, change_tick),
|
||||
#[cfg(feature = "track_location")]
|
||||
changed_by: _caller.deref_mut(),
|
||||
changed_by: caller.map(|caller| caller.deref_mut()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,10 +1,8 @@
|
||||
use core::ops::Deref;
|
||||
#[cfg(feature = "track_location")]
|
||||
use core::panic::Location;
|
||||
|
||||
use crate::{
|
||||
archetype::Archetype,
|
||||
change_detection::MutUntyped,
|
||||
change_detection::{MaybeLocation, MutUntyped},
|
||||
component::{ComponentId, HookContext, Mutable},
|
||||
entity::Entity,
|
||||
event::{Event, EventId, Events, SendBatchIds},
|
||||
@ -132,16 +130,14 @@ impl<'w> DeferredWorld<'w> {
|
||||
archetype,
|
||||
entity,
|
||||
[component_id].into_iter(),
|
||||
#[cfg(feature = "track_location")]
|
||||
Location::caller(),
|
||||
MaybeLocation::caller(),
|
||||
);
|
||||
if archetype.has_replace_observer() {
|
||||
self.trigger_observers(
|
||||
ON_REPLACE,
|
||||
entity,
|
||||
[component_id].into_iter(),
|
||||
#[cfg(feature = "track_location")]
|
||||
Location::caller(),
|
||||
MaybeLocation::caller(),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -173,16 +169,14 @@ impl<'w> DeferredWorld<'w> {
|
||||
archetype,
|
||||
entity,
|
||||
[component_id].into_iter(),
|
||||
#[cfg(feature = "track_location")]
|
||||
Location::caller(),
|
||||
MaybeLocation::caller(),
|
||||
);
|
||||
if archetype.has_insert_observer() {
|
||||
self.trigger_observers(
|
||||
ON_INSERT,
|
||||
entity,
|
||||
[component_id].into_iter(),
|
||||
#[cfg(feature = "track_location")]
|
||||
Location::caller(),
|
||||
MaybeLocation::caller(),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -519,7 +513,7 @@ impl<'w> DeferredWorld<'w> {
|
||||
archetype: &Archetype,
|
||||
entity: Entity,
|
||||
targets: impl Iterator<Item = ComponentId>,
|
||||
#[cfg(feature = "track_location")] caller: &'static Location<'static>,
|
||||
caller: MaybeLocation,
|
||||
) {
|
||||
if archetype.has_add_hook() {
|
||||
for component_id in targets {
|
||||
@ -531,10 +525,7 @@ impl<'w> DeferredWorld<'w> {
|
||||
HookContext {
|
||||
entity,
|
||||
component_id,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller: Some(caller),
|
||||
#[cfg(not(feature = "track_location"))]
|
||||
caller: None,
|
||||
caller,
|
||||
},
|
||||
);
|
||||
}
|
||||
@ -552,7 +543,7 @@ impl<'w> DeferredWorld<'w> {
|
||||
archetype: &Archetype,
|
||||
entity: Entity,
|
||||
targets: impl Iterator<Item = ComponentId>,
|
||||
#[cfg(feature = "track_location")] caller: &'static Location<'static>,
|
||||
caller: MaybeLocation,
|
||||
) {
|
||||
if archetype.has_insert_hook() {
|
||||
for component_id in targets {
|
||||
@ -564,10 +555,7 @@ impl<'w> DeferredWorld<'w> {
|
||||
HookContext {
|
||||
entity,
|
||||
component_id,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller: Some(caller),
|
||||
#[cfg(not(feature = "track_location"))]
|
||||
caller: None,
|
||||
caller,
|
||||
},
|
||||
);
|
||||
}
|
||||
@ -585,7 +573,7 @@ impl<'w> DeferredWorld<'w> {
|
||||
archetype: &Archetype,
|
||||
entity: Entity,
|
||||
targets: impl Iterator<Item = ComponentId>,
|
||||
#[cfg(feature = "track_location")] caller: &'static Location<'static>,
|
||||
caller: MaybeLocation,
|
||||
) {
|
||||
if archetype.has_replace_hook() {
|
||||
for component_id in targets {
|
||||
@ -597,10 +585,7 @@ impl<'w> DeferredWorld<'w> {
|
||||
HookContext {
|
||||
entity,
|
||||
component_id,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller: Some(caller),
|
||||
#[cfg(not(feature = "track_location"))]
|
||||
caller: None,
|
||||
caller,
|
||||
},
|
||||
);
|
||||
}
|
||||
@ -618,7 +603,7 @@ impl<'w> DeferredWorld<'w> {
|
||||
archetype: &Archetype,
|
||||
entity: Entity,
|
||||
targets: impl Iterator<Item = ComponentId>,
|
||||
#[cfg(feature = "track_location")] caller: &'static Location<'static>,
|
||||
caller: MaybeLocation,
|
||||
) {
|
||||
if archetype.has_remove_hook() {
|
||||
for component_id in targets {
|
||||
@ -630,10 +615,7 @@ impl<'w> DeferredWorld<'w> {
|
||||
HookContext {
|
||||
entity,
|
||||
component_id,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller: Some(caller),
|
||||
#[cfg(not(feature = "track_location"))]
|
||||
caller: None,
|
||||
caller,
|
||||
},
|
||||
);
|
||||
}
|
||||
@ -651,7 +633,7 @@ impl<'w> DeferredWorld<'w> {
|
||||
archetype: &Archetype,
|
||||
entity: Entity,
|
||||
targets: impl Iterator<Item = ComponentId>,
|
||||
#[cfg(feature = "track_location")] caller: &'static Location<'static>,
|
||||
caller: MaybeLocation,
|
||||
) {
|
||||
if archetype.has_despawn_hook() {
|
||||
for component_id in targets {
|
||||
@ -663,10 +645,7 @@ impl<'w> DeferredWorld<'w> {
|
||||
HookContext {
|
||||
entity,
|
||||
component_id,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller: Some(caller),
|
||||
#[cfg(not(feature = "track_location"))]
|
||||
caller: None,
|
||||
caller,
|
||||
},
|
||||
);
|
||||
}
|
||||
@ -684,7 +663,7 @@ impl<'w> DeferredWorld<'w> {
|
||||
event: ComponentId,
|
||||
target: Entity,
|
||||
components: impl Iterator<Item = ComponentId> + Clone,
|
||||
#[cfg(feature = "track_location")] caller: &'static Location<'static>,
|
||||
caller: MaybeLocation,
|
||||
) {
|
||||
Observers::invoke::<_>(
|
||||
self.reborrow(),
|
||||
@ -693,7 +672,6 @@ impl<'w> DeferredWorld<'w> {
|
||||
components,
|
||||
&mut (),
|
||||
&mut false,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
}
|
||||
@ -710,7 +688,7 @@ impl<'w> DeferredWorld<'w> {
|
||||
components: &[ComponentId],
|
||||
data: &mut E,
|
||||
mut propagate: bool,
|
||||
#[cfg(feature = "track_location")] caller: &'static Location<'static>,
|
||||
caller: MaybeLocation,
|
||||
) where
|
||||
T: Traversal<E>,
|
||||
{
|
||||
@ -722,7 +700,6 @@ impl<'w> DeferredWorld<'w> {
|
||||
components.iter().copied(),
|
||||
data,
|
||||
&mut propagate,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
if !propagate {
|
||||
|
||||
@ -4,7 +4,7 @@ use crate::{
|
||||
Bundle, BundleEffect, BundleFromComponents, BundleId, BundleInfo, BundleInserter,
|
||||
DynamicBundle, InsertMode,
|
||||
},
|
||||
change_detection::MutUntyped,
|
||||
change_detection::{MaybeLocation, MutUntyped},
|
||||
component::{Component, ComponentId, ComponentTicks, Components, Mutable, StorageType},
|
||||
entity::{
|
||||
Entities, Entity, EntityBorrow, EntityCloner, EntityClonerBuilder, EntityLocation,
|
||||
@ -25,8 +25,6 @@ use crate::{
|
||||
use alloc::vec::Vec;
|
||||
use bevy_platform_support::collections::{HashMap, HashSet};
|
||||
use bevy_ptr::{OwningPtr, Ptr};
|
||||
#[cfg(feature = "track_location")]
|
||||
use core::panic::Location;
|
||||
use core::{
|
||||
any::TypeId,
|
||||
cmp::Ordering,
|
||||
@ -294,8 +292,7 @@ impl<'w> EntityRef<'w> {
|
||||
}
|
||||
|
||||
/// Returns the source code location from which this entity has been spawned.
|
||||
#[cfg(feature = "track_location")]
|
||||
pub fn spawned_by(&self) -> &'static Location<'static> {
|
||||
pub fn spawned_by(&self) -> MaybeLocation {
|
||||
self.cell.spawned_by()
|
||||
}
|
||||
}
|
||||
@ -885,8 +882,7 @@ impl<'w> EntityMut<'w> {
|
||||
}
|
||||
|
||||
/// Returns the source code location from which this entity has been spawned.
|
||||
#[cfg(feature = "track_location")]
|
||||
pub fn spawned_by(&self) -> &'static Location<'static> {
|
||||
pub fn spawned_by(&self) -> MaybeLocation {
|
||||
self.cell.spawned_by()
|
||||
}
|
||||
}
|
||||
@ -1530,12 +1526,7 @@ impl<'w> EntityWorldMut<'w> {
|
||||
/// If the entity has been despawned while this `EntityWorldMut` is still alive.
|
||||
#[track_caller]
|
||||
pub fn insert<T: Bundle>(&mut self, bundle: T) -> &mut Self {
|
||||
self.insert_with_caller(
|
||||
bundle,
|
||||
InsertMode::Replace,
|
||||
#[cfg(feature = "track_location")]
|
||||
Location::caller(),
|
||||
)
|
||||
self.insert_with_caller(bundle, InsertMode::Replace, MaybeLocation::caller())
|
||||
}
|
||||
|
||||
/// Adds a [`Bundle`] of components to the entity without overwriting.
|
||||
@ -1548,12 +1539,7 @@ impl<'w> EntityWorldMut<'w> {
|
||||
/// If the entity has been despawned while this `EntityWorldMut` is still alive.
|
||||
#[track_caller]
|
||||
pub fn insert_if_new<T: Bundle>(&mut self, bundle: T) -> &mut Self {
|
||||
self.insert_with_caller(
|
||||
bundle,
|
||||
InsertMode::Keep,
|
||||
#[cfg(feature = "track_location")]
|
||||
Location::caller(),
|
||||
)
|
||||
self.insert_with_caller(bundle, InsertMode::Keep, MaybeLocation::caller())
|
||||
}
|
||||
|
||||
/// Split into a new function so we can pass the calling location into the function when using
|
||||
@ -1563,23 +1549,15 @@ impl<'w> EntityWorldMut<'w> {
|
||||
&mut self,
|
||||
bundle: T,
|
||||
mode: InsertMode,
|
||||
#[cfg(feature = "track_location")] caller: &'static Location,
|
||||
caller: MaybeLocation,
|
||||
) -> &mut Self {
|
||||
self.assert_not_despawned();
|
||||
let change_tick = self.world.change_tick();
|
||||
let mut bundle_inserter =
|
||||
BundleInserter::new::<T>(self.world, self.location.archetype_id, change_tick);
|
||||
// SAFETY: location matches current entity. `T` matches `bundle_info`
|
||||
let (location, after_effect) = unsafe {
|
||||
bundle_inserter.insert(
|
||||
self.entity,
|
||||
self.location,
|
||||
bundle,
|
||||
mode,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
)
|
||||
};
|
||||
let (location, after_effect) =
|
||||
unsafe { bundle_inserter.insert(self.entity, self.location, bundle, mode, caller) };
|
||||
self.location = location;
|
||||
self.world.flush();
|
||||
self.update_location();
|
||||
@ -1607,12 +1585,7 @@ impl<'w> EntityWorldMut<'w> {
|
||||
component_id: ComponentId,
|
||||
component: OwningPtr<'_>,
|
||||
) -> &mut Self {
|
||||
self.insert_by_id_with_caller(
|
||||
component_id,
|
||||
component,
|
||||
#[cfg(feature = "track_location")]
|
||||
Location::caller(),
|
||||
)
|
||||
self.insert_by_id_with_caller(component_id, component, MaybeLocation::caller())
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
@ -1622,7 +1595,7 @@ impl<'w> EntityWorldMut<'w> {
|
||||
&mut self,
|
||||
component_id: ComponentId,
|
||||
component: OwningPtr<'_>,
|
||||
#[cfg(feature = "track_location")] caller: &'static Location<'static>,
|
||||
caller: MaybeLocation,
|
||||
) -> &mut Self {
|
||||
self.assert_not_despawned();
|
||||
let change_tick = self.world.change_tick();
|
||||
@ -1646,7 +1619,6 @@ impl<'w> EntityWorldMut<'w> {
|
||||
self.location,
|
||||
Some(component).into_iter(),
|
||||
Some(storage_type).iter().cloned(),
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
self.world.flush();
|
||||
@ -1698,8 +1670,7 @@ impl<'w> EntityWorldMut<'w> {
|
||||
self.location,
|
||||
iter_components,
|
||||
(*storage_types).iter().cloned(),
|
||||
#[cfg(feature = "track_location")]
|
||||
Location::caller(),
|
||||
MaybeLocation::caller(),
|
||||
);
|
||||
*self.world.bundles.get_storages_unchecked(bundle_id) = core::mem::take(&mut storage_types);
|
||||
self.world.flush();
|
||||
@ -1763,8 +1734,7 @@ impl<'w> EntityWorldMut<'w> {
|
||||
old_archetype,
|
||||
entity,
|
||||
bundle_info,
|
||||
#[cfg(feature = "track_location")]
|
||||
Location::caller(),
|
||||
MaybeLocation::caller(),
|
||||
);
|
||||
}
|
||||
|
||||
@ -1906,11 +1876,7 @@ impl<'w> EntityWorldMut<'w> {
|
||||
///
|
||||
/// # Safety
|
||||
/// - A `BundleInfo` with the corresponding `BundleId` must have been initialized.
|
||||
unsafe fn remove_bundle(
|
||||
&mut self,
|
||||
bundle: BundleId,
|
||||
#[cfg(feature = "track_location")] caller: &'static Location<'static>,
|
||||
) -> EntityLocation {
|
||||
unsafe fn remove_bundle(&mut self, bundle: BundleId, caller: MaybeLocation) -> EntityLocation {
|
||||
let entity = self.entity;
|
||||
let world = &mut self.world;
|
||||
let location = self.location;
|
||||
@ -1953,7 +1919,6 @@ impl<'w> EntityWorldMut<'w> {
|
||||
old_archetype,
|
||||
entity,
|
||||
bundle_info,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
}
|
||||
@ -2004,30 +1969,18 @@ impl<'w> EntityWorldMut<'w> {
|
||||
// TODO: BundleRemover?
|
||||
#[track_caller]
|
||||
pub fn remove<T: Bundle>(&mut self) -> &mut Self {
|
||||
self.remove_with_caller::<T>(
|
||||
#[cfg(feature = "track_location")]
|
||||
Location::caller(),
|
||||
)
|
||||
self.remove_with_caller::<T>(MaybeLocation::caller())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn remove_with_caller<T: Bundle>(
|
||||
&mut self,
|
||||
#[cfg(feature = "track_location")] caller: &'static Location<'static>,
|
||||
) -> &mut Self {
|
||||
pub(crate) fn remove_with_caller<T: Bundle>(&mut self, caller: MaybeLocation) -> &mut Self {
|
||||
self.assert_not_despawned();
|
||||
let storages = &mut self.world.storages;
|
||||
let components = &mut self.world.components;
|
||||
let bundle_info = self.world.bundles.register_info::<T>(components, storages);
|
||||
|
||||
// SAFETY: the `BundleInfo` is initialized above
|
||||
self.location = unsafe {
|
||||
self.remove_bundle(
|
||||
bundle_info,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
)
|
||||
};
|
||||
self.location = unsafe { self.remove_bundle(bundle_info, caller) };
|
||||
self.world.flush();
|
||||
self.update_location();
|
||||
self
|
||||
@ -2040,15 +1993,12 @@ impl<'w> EntityWorldMut<'w> {
|
||||
/// If the entity has been despawned while this `EntityWorldMut` is still alive.
|
||||
#[track_caller]
|
||||
pub fn remove_with_requires<T: Bundle>(&mut self) -> &mut Self {
|
||||
self.remove_with_requires_with_caller::<T>(
|
||||
#[cfg(feature = "track_location")]
|
||||
Location::caller(),
|
||||
)
|
||||
self.remove_with_requires_with_caller::<T>(MaybeLocation::caller())
|
||||
}
|
||||
|
||||
pub(crate) fn remove_with_requires_with_caller<T: Bundle>(
|
||||
&mut self,
|
||||
#[cfg(feature = "track_location")] caller: &'static Location<'static>,
|
||||
caller: MaybeLocation,
|
||||
) -> &mut Self {
|
||||
self.assert_not_despawned();
|
||||
let storages = &mut self.world.storages;
|
||||
@ -2058,13 +2008,7 @@ impl<'w> EntityWorldMut<'w> {
|
||||
let bundle_id = bundles.register_contributed_bundle_info::<T>(components, storages);
|
||||
|
||||
// SAFETY: the dynamic `BundleInfo` is initialized above
|
||||
self.location = unsafe {
|
||||
self.remove_bundle(
|
||||
bundle_id,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
)
|
||||
};
|
||||
self.location = unsafe { self.remove_bundle(bundle_id, caller) };
|
||||
self.world.flush();
|
||||
self.update_location();
|
||||
self
|
||||
@ -2079,17 +2023,11 @@ impl<'w> EntityWorldMut<'w> {
|
||||
/// If the entity has been despawned while this `EntityWorldMut` is still alive.
|
||||
#[track_caller]
|
||||
pub fn retain<T: Bundle>(&mut self) -> &mut Self {
|
||||
self.retain_with_caller::<T>(
|
||||
#[cfg(feature = "track_location")]
|
||||
Location::caller(),
|
||||
)
|
||||
self.retain_with_caller::<T>(MaybeLocation::caller())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn retain_with_caller<T: Bundle>(
|
||||
&mut self,
|
||||
#[cfg(feature = "track_location")] caller: &'static Location<'static>,
|
||||
) -> &mut Self {
|
||||
pub(crate) fn retain_with_caller<T: Bundle>(&mut self, caller: MaybeLocation) -> &mut Self {
|
||||
self.assert_not_despawned();
|
||||
let archetypes = &mut self.world.archetypes;
|
||||
let storages = &mut self.world.storages;
|
||||
@ -2112,13 +2050,7 @@ impl<'w> EntityWorldMut<'w> {
|
||||
.init_dynamic_info(&mut self.world.storages, components, to_remove);
|
||||
|
||||
// SAFETY: the `BundleInfo` for the components to remove is initialized above
|
||||
self.location = unsafe {
|
||||
self.remove_bundle(
|
||||
remove_bundle,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
)
|
||||
};
|
||||
self.location = unsafe { self.remove_bundle(remove_bundle, caller) };
|
||||
self.world.flush();
|
||||
self.update_location();
|
||||
self
|
||||
@ -2134,18 +2066,14 @@ impl<'w> EntityWorldMut<'w> {
|
||||
/// entity has been despawned while this `EntityWorldMut` is still alive.
|
||||
#[track_caller]
|
||||
pub fn remove_by_id(&mut self, component_id: ComponentId) -> &mut Self {
|
||||
self.remove_by_id_with_caller(
|
||||
component_id,
|
||||
#[cfg(feature = "track_location")]
|
||||
Location::caller(),
|
||||
)
|
||||
self.remove_by_id_with_caller(component_id, MaybeLocation::caller())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn remove_by_id_with_caller(
|
||||
&mut self,
|
||||
component_id: ComponentId,
|
||||
#[cfg(feature = "track_location")] caller: &'static Location<'static>,
|
||||
caller: MaybeLocation,
|
||||
) -> &mut Self {
|
||||
self.assert_not_despawned();
|
||||
let components = &mut self.world.components;
|
||||
@ -2157,13 +2085,7 @@ impl<'w> EntityWorldMut<'w> {
|
||||
);
|
||||
|
||||
// SAFETY: the `BundleInfo` for this `component_id` is initialized above
|
||||
self.location = unsafe {
|
||||
self.remove_bundle(
|
||||
bundle_id,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
)
|
||||
};
|
||||
self.location = unsafe { self.remove_bundle(bundle_id, caller) };
|
||||
self.world.flush();
|
||||
self.update_location();
|
||||
self
|
||||
@ -2189,13 +2111,7 @@ impl<'w> EntityWorldMut<'w> {
|
||||
);
|
||||
|
||||
// SAFETY: the `BundleInfo` for this `bundle_id` is initialized above
|
||||
unsafe {
|
||||
self.remove_bundle(
|
||||
bundle_id,
|
||||
#[cfg(feature = "track_location")]
|
||||
Location::caller(),
|
||||
)
|
||||
};
|
||||
unsafe { self.remove_bundle(bundle_id, MaybeLocation::caller()) };
|
||||
|
||||
self.world.flush();
|
||||
self.update_location();
|
||||
@ -2209,17 +2125,11 @@ impl<'w> EntityWorldMut<'w> {
|
||||
/// If the entity has been despawned while this `EntityWorldMut` is still alive.
|
||||
#[track_caller]
|
||||
pub fn clear(&mut self) -> &mut Self {
|
||||
self.clear_with_caller(
|
||||
#[cfg(feature = "track_location")]
|
||||
Location::caller(),
|
||||
)
|
||||
self.clear_with_caller(MaybeLocation::caller())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn clear_with_caller(
|
||||
&mut self,
|
||||
#[cfg(feature = "track_location")] caller: &'static Location<'static>,
|
||||
) -> &mut Self {
|
||||
pub(crate) fn clear_with_caller(&mut self, caller: MaybeLocation) -> &mut Self {
|
||||
self.assert_not_despawned();
|
||||
let component_ids: Vec<ComponentId> = self.archetype().components().collect();
|
||||
let components = &mut self.world.components;
|
||||
@ -2231,13 +2141,7 @@ impl<'w> EntityWorldMut<'w> {
|
||||
);
|
||||
|
||||
// SAFETY: the `BundleInfo` for this `component_id` is initialized above
|
||||
self.location = unsafe {
|
||||
self.remove_bundle(
|
||||
bundle_id,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
)
|
||||
};
|
||||
self.location = unsafe { self.remove_bundle(bundle_id, caller) };
|
||||
self.world.flush();
|
||||
self.update_location();
|
||||
self
|
||||
@ -2257,10 +2161,7 @@ impl<'w> EntityWorldMut<'w> {
|
||||
/// If the entity has been despawned while this `EntityWorldMut` is still alive.
|
||||
#[track_caller]
|
||||
pub fn despawn(self) {
|
||||
self.despawn_with_caller(
|
||||
#[cfg(feature = "track_location")]
|
||||
Location::caller(),
|
||||
);
|
||||
self.despawn_with_caller(MaybeLocation::caller());
|
||||
}
|
||||
|
||||
/// Despawns the provided entity and its descendants.
|
||||
@ -2272,10 +2173,7 @@ impl<'w> EntityWorldMut<'w> {
|
||||
self.despawn();
|
||||
}
|
||||
|
||||
pub(crate) fn despawn_with_caller(
|
||||
self,
|
||||
#[cfg(feature = "track_location")] caller: &'static Location,
|
||||
) {
|
||||
pub(crate) fn despawn_with_caller(self, caller: MaybeLocation) {
|
||||
self.assert_not_despawned();
|
||||
let world = self.world;
|
||||
let archetype = &world.archetypes[self.location.archetype_id];
|
||||
@ -2294,7 +2192,6 @@ impl<'w> EntityWorldMut<'w> {
|
||||
ON_DESPAWN,
|
||||
self.entity,
|
||||
archetype.components(),
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
}
|
||||
@ -2302,7 +2199,6 @@ impl<'w> EntityWorldMut<'w> {
|
||||
archetype,
|
||||
self.entity,
|
||||
archetype.components(),
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
if archetype.has_replace_observer() {
|
||||
@ -2310,7 +2206,6 @@ impl<'w> EntityWorldMut<'w> {
|
||||
ON_REPLACE,
|
||||
self.entity,
|
||||
archetype.components(),
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
}
|
||||
@ -2318,7 +2213,6 @@ impl<'w> EntityWorldMut<'w> {
|
||||
archetype,
|
||||
self.entity,
|
||||
archetype.components(),
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
if archetype.has_remove_observer() {
|
||||
@ -2326,7 +2220,6 @@ impl<'w> EntityWorldMut<'w> {
|
||||
ON_REMOVE,
|
||||
self.entity,
|
||||
archetype.components(),
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
}
|
||||
@ -2334,7 +2227,6 @@ impl<'w> EntityWorldMut<'w> {
|
||||
archetype,
|
||||
self.entity,
|
||||
archetype.components(),
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
}
|
||||
@ -2406,8 +2298,6 @@ impl<'w> EntityWorldMut<'w> {
|
||||
}
|
||||
world.flush();
|
||||
|
||||
#[cfg(feature = "track_location")]
|
||||
{
|
||||
// SAFETY: No structural changes
|
||||
unsafe {
|
||||
world
|
||||
@ -2415,7 +2305,6 @@ impl<'w> EntityWorldMut<'w> {
|
||||
.set_spawned_or_despawned_by(self.entity.index(), caller);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Ensures any commands triggered by the actions of Self are applied, equivalent to [`World::flush`]
|
||||
pub fn flush(self) -> Entity {
|
||||
@ -2579,24 +2468,17 @@ impl<'w> EntityWorldMut<'w> {
|
||||
&mut self,
|
||||
observer: impl IntoObserverSystem<E, B, M>,
|
||||
) -> &mut Self {
|
||||
self.observe_with_caller(
|
||||
observer,
|
||||
#[cfg(feature = "track_location")]
|
||||
Location::caller(),
|
||||
)
|
||||
self.observe_with_caller(observer, MaybeLocation::caller())
|
||||
}
|
||||
|
||||
pub(crate) fn observe_with_caller<E: Event, B: Bundle, M>(
|
||||
&mut self,
|
||||
observer: impl IntoObserverSystem<E, B, M>,
|
||||
#[cfg(feature = "track_location")] caller: &'static Location<'static>,
|
||||
caller: MaybeLocation,
|
||||
) -> &mut Self {
|
||||
self.assert_not_despawned();
|
||||
self.world.spawn_with_caller(
|
||||
Observer::new(observer).with_entity(self.entity),
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
self.world
|
||||
.spawn_with_caller(Observer::new(observer).with_entity(self.entity), caller);
|
||||
self.world.flush();
|
||||
self.update_location();
|
||||
self
|
||||
@ -2754,12 +2636,11 @@ impl<'w> EntityWorldMut<'w> {
|
||||
}
|
||||
|
||||
/// Returns the source code location from which this entity has last been spawned.
|
||||
#[cfg(feature = "track_location")]
|
||||
pub fn spawned_by(&self) -> &'static Location<'static> {
|
||||
pub fn spawned_by(&self) -> MaybeLocation {
|
||||
self.world()
|
||||
.entities()
|
||||
.entity_get_spawned_or_despawned_by(self.entity)
|
||||
.unwrap()
|
||||
.map(|location| location.unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
@ -2770,14 +2651,13 @@ unsafe fn trigger_on_replace_and_on_remove_hooks_and_observers(
|
||||
archetype: &Archetype,
|
||||
entity: Entity,
|
||||
bundle_info: &BundleInfo,
|
||||
#[cfg(feature = "track_location")] caller: &'static Location<'static>,
|
||||
caller: MaybeLocation,
|
||||
) {
|
||||
if archetype.has_replace_observer() {
|
||||
deferred_world.trigger_observers(
|
||||
ON_REPLACE,
|
||||
entity,
|
||||
bundle_info.iter_explicit_components(),
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
}
|
||||
@ -2785,7 +2665,6 @@ unsafe fn trigger_on_replace_and_on_remove_hooks_and_observers(
|
||||
archetype,
|
||||
entity,
|
||||
bundle_info.iter_explicit_components(),
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
if archetype.has_remove_observer() {
|
||||
@ -2793,7 +2672,6 @@ unsafe fn trigger_on_replace_and_on_remove_hooks_and_observers(
|
||||
ON_REMOVE,
|
||||
entity,
|
||||
bundle_info.iter_explicit_components(),
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
}
|
||||
@ -2801,7 +2679,6 @@ unsafe fn trigger_on_replace_and_on_remove_hooks_and_observers(
|
||||
archetype,
|
||||
entity,
|
||||
bundle_info.iter_explicit_components(),
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
}
|
||||
@ -3315,8 +3192,7 @@ impl<'w> FilteredEntityRef<'w> {
|
||||
}
|
||||
|
||||
/// Returns the source code location from which this entity has been spawned.
|
||||
#[cfg(feature = "track_location")]
|
||||
pub fn spawned_by(&self) -> &'static Location<'static> {
|
||||
pub fn spawned_by(&self) -> MaybeLocation {
|
||||
self.entity.spawned_by()
|
||||
}
|
||||
}
|
||||
@ -3679,8 +3555,7 @@ impl<'w> FilteredEntityMut<'w> {
|
||||
}
|
||||
|
||||
/// Returns the source code location from which this entity has last been spawned.
|
||||
#[cfg(feature = "track_location")]
|
||||
pub fn spawned_by(&self) -> &'static Location<'static> {
|
||||
pub fn spawned_by(&self) -> MaybeLocation {
|
||||
self.entity.spawned_by()
|
||||
}
|
||||
}
|
||||
@ -3859,8 +3734,7 @@ where
|
||||
}
|
||||
|
||||
/// Returns the source code location from which this entity has been spawned.
|
||||
#[cfg(feature = "track_location")]
|
||||
pub fn spawned_by(&self) -> &'static Location<'static> {
|
||||
pub fn spawned_by(&self) -> MaybeLocation {
|
||||
self.entity.spawned_by()
|
||||
}
|
||||
}
|
||||
@ -4017,8 +3891,7 @@ where
|
||||
}
|
||||
|
||||
/// Returns the source code location from which this entity has been spawned.
|
||||
#[cfg(feature = "track_location")]
|
||||
pub fn spawned_by(&self) -> &'static Location<'static> {
|
||||
pub fn spawned_by(&self) -> MaybeLocation {
|
||||
self.entity.spawned_by()
|
||||
}
|
||||
}
|
||||
@ -4090,7 +3963,7 @@ unsafe fn insert_dynamic_bundle<
|
||||
location: EntityLocation,
|
||||
components: I,
|
||||
storage_types: S,
|
||||
#[cfg(feature = "track_location")] caller: &'static Location<'static>,
|
||||
caller: MaybeLocation,
|
||||
) -> EntityLocation {
|
||||
struct DynamicInsertBundle<'a, I: Iterator<Item = (StorageType, OwningPtr<'a>)>> {
|
||||
components: I,
|
||||
@ -4112,14 +3985,7 @@ unsafe fn insert_dynamic_bundle<
|
||||
// SAFETY: location matches current entity.
|
||||
unsafe {
|
||||
bundle_inserter
|
||||
.insert(
|
||||
entity,
|
||||
location,
|
||||
bundle,
|
||||
InsertMode::Replace,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
)
|
||||
.insert(entity, location, bundle, InsertMode::Replace, caller)
|
||||
.0
|
||||
}
|
||||
}
|
||||
@ -4425,13 +4291,11 @@ mod tests {
|
||||
use alloc::{vec, vec::Vec};
|
||||
use bevy_ptr::{OwningPtr, Ptr};
|
||||
use core::panic::AssertUnwindSafe;
|
||||
|
||||
#[cfg(feature = "track_location")]
|
||||
use {core::panic::Location, std::sync::OnceLock};
|
||||
use std::sync::OnceLock;
|
||||
|
||||
use crate::component::HookContext;
|
||||
use crate::{
|
||||
change_detection::MutUntyped,
|
||||
change_detection::{MaybeLocation, MutUntyped},
|
||||
component::ComponentId,
|
||||
prelude::*,
|
||||
system::{assert_is_system, RunSystemOnce as _},
|
||||
@ -5710,7 +5574,6 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "track_location")]
|
||||
fn update_despawned_by_after_observers() {
|
||||
let mut world = World::new();
|
||||
|
||||
@ -5718,19 +5581,19 @@ mod tests {
|
||||
#[component(on_remove = get_tracked)]
|
||||
struct C;
|
||||
|
||||
static TRACKED: OnceLock<&'static Location<'static>> = OnceLock::new();
|
||||
static TRACKED: OnceLock<MaybeLocation> = OnceLock::new();
|
||||
fn get_tracked(world: DeferredWorld, HookContext { entity, .. }: HookContext) {
|
||||
TRACKED.get_or_init(|| {
|
||||
world
|
||||
.entities
|
||||
.entity_get_spawned_or_despawned_by(entity)
|
||||
.unwrap()
|
||||
.map(|l| l.unwrap())
|
||||
});
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn caller_spawn(world: &mut World) -> (Entity, &'static Location<'static>) {
|
||||
let caller = Location::caller();
|
||||
fn caller_spawn(world: &mut World) -> (Entity, MaybeLocation) {
|
||||
let caller = MaybeLocation::caller();
|
||||
(world.spawn(C).id(), caller)
|
||||
}
|
||||
let (entity, spawner) = caller_spawn(&mut world);
|
||||
@ -5740,13 +5603,13 @@ mod tests {
|
||||
world
|
||||
.entities()
|
||||
.entity_get_spawned_or_despawned_by(entity)
|
||||
.unwrap()
|
||||
.map(|l| l.unwrap())
|
||||
);
|
||||
|
||||
#[track_caller]
|
||||
fn caller_despawn(world: &mut World, entity: Entity) -> &'static Location<'static> {
|
||||
fn caller_despawn(world: &mut World, entity: Entity) -> MaybeLocation {
|
||||
world.despawn(entity);
|
||||
Location::caller()
|
||||
MaybeLocation::caller()
|
||||
}
|
||||
let despawner = caller_despawn(&mut world, entity);
|
||||
|
||||
@ -5756,7 +5619,7 @@ mod tests {
|
||||
world
|
||||
.entities()
|
||||
.entity_get_spawned_or_despawned_by(entity)
|
||||
.unwrap()
|
||||
.map(|l| l.unwrap())
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -5,9 +5,7 @@ use crate::{
|
||||
resource::Resource,
|
||||
world::{unsafe_world_cell::UnsafeWorldCell, World},
|
||||
};
|
||||
use bevy_ptr::Ptr;
|
||||
#[cfg(feature = "track_location")]
|
||||
use bevy_ptr::UnsafeCellDeref;
|
||||
use bevy_ptr::{Ptr, UnsafeCellDeref};
|
||||
|
||||
/// Provides read-only access to a set of [`Resource`]s defined by the contained [`Access`].
|
||||
///
|
||||
@ -159,17 +157,16 @@ impl<'w, 's> FilteredResources<'w, 's> {
|
||||
return None;
|
||||
}
|
||||
// SAFETY: We have read access to this resource
|
||||
unsafe { self.world.get_resource_with_ticks(component_id) }.map(
|
||||
|(value, ticks, _caller)| Ref {
|
||||
unsafe { self.world.get_resource_with_ticks(component_id) }.map(|(value, ticks, caller)| {
|
||||
Ref {
|
||||
// SAFETY: `component_id` was obtained from the type ID of `R`.
|
||||
value: unsafe { value.deref() },
|
||||
// SAFETY: We have read access to the resource, so no mutable reference can exist.
|
||||
ticks: unsafe { Ticks::from_tick_cells(ticks, self.last_run, self.this_run) },
|
||||
#[cfg(feature = "track_location")]
|
||||
// SAFETY: We have read access to the resource, so no mutable reference can exist.
|
||||
changed_by: unsafe { _caller.deref() },
|
||||
},
|
||||
)
|
||||
changed_by: unsafe { caller.map(|caller| caller.deref()) },
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Gets a pointer to the resource with the given [`ComponentId`] if it exists and the `FilteredResources` has access to it.
|
||||
@ -477,17 +474,16 @@ impl<'w, 's> FilteredResourcesMut<'w, 's> {
|
||||
return None;
|
||||
}
|
||||
// SAFETY: We have access to this resource in `access`, and the caller ensures that there are no conflicting borrows for the duration of the returned value.
|
||||
unsafe { self.world.get_resource_with_ticks(component_id) }.map(
|
||||
|(value, ticks, _caller)| MutUntyped {
|
||||
unsafe { self.world.get_resource_with_ticks(component_id) }.map(|(value, ticks, caller)| {
|
||||
MutUntyped {
|
||||
// SAFETY: We have exclusive access to the underlying storage.
|
||||
value: unsafe { value.assert_unique() },
|
||||
// SAFETY: We have exclusive access to the underlying storage.
|
||||
ticks: unsafe { TicksMut::from_tick_cells(ticks, self.last_run, self.this_run) },
|
||||
#[cfg(feature = "track_location")]
|
||||
// SAFETY: We have exclusive access to the underlying storage.
|
||||
changed_by: unsafe { _caller.deref_mut() },
|
||||
},
|
||||
)
|
||||
changed_by: unsafe { caller.map(|caller| caller.deref_mut()) },
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -36,7 +36,7 @@ use crate::{
|
||||
Bundle, BundleEffect, BundleInfo, BundleInserter, BundleSpawner, Bundles, InsertMode,
|
||||
NoBundleEffect,
|
||||
},
|
||||
change_detection::{MutUntyped, TicksMut},
|
||||
change_detection::{MaybeLocation, MutUntyped, TicksMut},
|
||||
component::{
|
||||
Component, ComponentDescriptor, ComponentHooks, ComponentId, ComponentInfo, ComponentTicks,
|
||||
Components, Mutable, RequiredComponents, RequiredComponentsError, Tick,
|
||||
@ -59,17 +59,11 @@ use crate::{
|
||||
};
|
||||
use alloc::{boxed::Box, vec::Vec};
|
||||
use bevy_platform_support::sync::atomic::{AtomicU32, Ordering};
|
||||
use bevy_ptr::{OwningPtr, Ptr};
|
||||
use bevy_ptr::{OwningPtr, Ptr, UnsafeCellDeref};
|
||||
use core::{any::TypeId, fmt};
|
||||
use log::warn;
|
||||
use unsafe_world_cell::{UnsafeEntityCell, UnsafeWorldCell};
|
||||
|
||||
#[cfg(feature = "track_location")]
|
||||
use bevy_ptr::UnsafeCellDeref;
|
||||
|
||||
#[cfg(feature = "track_location")]
|
||||
use core::panic::Location;
|
||||
|
||||
/// Stores and exposes operations on [entities](Entity), [components](Component), resources,
|
||||
/// and their associated metadata.
|
||||
///
|
||||
@ -1013,13 +1007,7 @@ impl World {
|
||||
self.flush();
|
||||
let entity = self.entities.alloc();
|
||||
// SAFETY: entity was just allocated
|
||||
unsafe {
|
||||
self.spawn_at_empty_internal(
|
||||
entity,
|
||||
#[cfg(feature = "track_location")]
|
||||
Location::caller(),
|
||||
)
|
||||
}
|
||||
unsafe { self.spawn_at_empty_internal(entity, MaybeLocation::caller()) }
|
||||
}
|
||||
|
||||
/// Spawns a new [`Entity`] with a given [`Bundle`] of [components](`Component`) and returns
|
||||
@ -1084,31 +1072,21 @@ impl World {
|
||||
/// ```
|
||||
#[track_caller]
|
||||
pub fn spawn<B: Bundle>(&mut self, bundle: B) -> EntityWorldMut {
|
||||
self.spawn_with_caller(
|
||||
bundle,
|
||||
#[cfg(feature = "track_location")]
|
||||
Location::caller(),
|
||||
)
|
||||
self.spawn_with_caller(bundle, MaybeLocation::caller())
|
||||
}
|
||||
|
||||
pub(crate) fn spawn_with_caller<B: Bundle>(
|
||||
&mut self,
|
||||
bundle: B,
|
||||
#[cfg(feature = "track_location")] caller: &'static Location<'static>,
|
||||
caller: MaybeLocation,
|
||||
) -> EntityWorldMut {
|
||||
self.flush();
|
||||
let change_tick = self.change_tick();
|
||||
let entity = self.entities.alloc();
|
||||
let mut bundle_spawner = BundleSpawner::new::<B>(self, change_tick);
|
||||
// SAFETY: bundle's type matches `bundle_info`, entity is allocated but non-existent
|
||||
let (mut entity_location, after_effect) = unsafe {
|
||||
bundle_spawner.spawn_non_existent(
|
||||
entity,
|
||||
bundle,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
)
|
||||
};
|
||||
let (mut entity_location, after_effect) =
|
||||
unsafe { bundle_spawner.spawn_non_existent(entity, bundle, caller) };
|
||||
|
||||
// SAFETY: command_queue is not referenced anywhere else
|
||||
if !unsafe { self.command_queue.is_empty() } {
|
||||
@ -1119,7 +1097,6 @@ impl World {
|
||||
.unwrap_or(EntityLocation::INVALID);
|
||||
}
|
||||
|
||||
#[cfg(feature = "track_location")]
|
||||
self.entities
|
||||
.set_spawned_or_despawned_by(entity.index(), caller);
|
||||
|
||||
@ -1134,7 +1111,7 @@ impl World {
|
||||
unsafe fn spawn_at_empty_internal(
|
||||
&mut self,
|
||||
entity: Entity,
|
||||
#[cfg(feature = "track_location")] caller: &'static Location,
|
||||
caller: MaybeLocation,
|
||||
) -> EntityWorldMut {
|
||||
let archetype = self.archetypes.empty_mut();
|
||||
// PERF: consider avoiding allocating entities in the empty archetype unless needed
|
||||
@ -1144,7 +1121,6 @@ impl World {
|
||||
let location = unsafe { archetype.allocate(entity, table_row) };
|
||||
self.entities.set(entity.index(), location);
|
||||
|
||||
#[cfg(feature = "track_location")]
|
||||
self.entities
|
||||
.set_spawned_or_despawned_by(entity.index(), caller);
|
||||
|
||||
@ -1179,12 +1155,7 @@ impl World {
|
||||
I: IntoIterator,
|
||||
I::Item: Bundle<Effect: NoBundleEffect>,
|
||||
{
|
||||
SpawnBatchIter::new(
|
||||
self,
|
||||
iter.into_iter(),
|
||||
#[cfg(feature = "track_location")]
|
||||
Location::caller(),
|
||||
)
|
||||
SpawnBatchIter::new(self, iter.into_iter(), MaybeLocation::caller())
|
||||
}
|
||||
|
||||
/// Retrieves a reference to the given `entity`'s [`Component`] of the given type.
|
||||
@ -1317,11 +1288,7 @@ impl World {
|
||||
#[track_caller]
|
||||
#[inline]
|
||||
pub fn despawn(&mut self, entity: Entity) -> bool {
|
||||
if let Err(error) = self.despawn_with_caller(
|
||||
entity,
|
||||
#[cfg(feature = "track_location")]
|
||||
Location::caller(),
|
||||
) {
|
||||
if let Err(error) = self.despawn_with_caller(entity, MaybeLocation::caller()) {
|
||||
warn!("{error}");
|
||||
false
|
||||
} else {
|
||||
@ -1341,25 +1308,18 @@ impl World {
|
||||
#[track_caller]
|
||||
#[inline]
|
||||
pub fn try_despawn(&mut self, entity: Entity) -> Result<(), TryDespawnError> {
|
||||
self.despawn_with_caller(
|
||||
entity,
|
||||
#[cfg(feature = "track_location")]
|
||||
Location::caller(),
|
||||
)
|
||||
self.despawn_with_caller(entity, MaybeLocation::caller())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn despawn_with_caller(
|
||||
&mut self,
|
||||
entity: Entity,
|
||||
#[cfg(feature = "track_location")] caller: &'static Location,
|
||||
caller: MaybeLocation,
|
||||
) -> Result<(), TryDespawnError> {
|
||||
self.flush();
|
||||
if let Ok(entity) = self.get_entity_mut(entity) {
|
||||
entity.despawn_with_caller(
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
entity.despawn_with_caller(caller);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(TryDespawnError {
|
||||
@ -1630,8 +1590,7 @@ impl World {
|
||||
#[inline]
|
||||
#[track_caller]
|
||||
pub fn init_resource<R: Resource + FromWorld>(&mut self) -> ComponentId {
|
||||
#[cfg(feature = "track_location")]
|
||||
let caller = Location::caller();
|
||||
let caller = MaybeLocation::caller();
|
||||
let component_id = self.components.register_resource::<R>();
|
||||
if self
|
||||
.storages
|
||||
@ -1643,12 +1602,7 @@ impl World {
|
||||
OwningPtr::make(value, |ptr| {
|
||||
// SAFETY: component_id was just initialized and corresponds to resource of type R.
|
||||
unsafe {
|
||||
self.insert_resource_by_id(
|
||||
component_id,
|
||||
ptr,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
self.insert_resource_by_id(component_id, ptr, caller);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -1663,11 +1617,7 @@ impl World {
|
||||
#[inline]
|
||||
#[track_caller]
|
||||
pub fn insert_resource<R: Resource>(&mut self, value: R) {
|
||||
self.insert_resource_with_caller(
|
||||
value,
|
||||
#[cfg(feature = "track_location")]
|
||||
Location::caller(),
|
||||
);
|
||||
self.insert_resource_with_caller(value, MaybeLocation::caller());
|
||||
}
|
||||
|
||||
/// Split into a new function so we can pass the calling location into the function when using
|
||||
@ -1676,18 +1626,13 @@ impl World {
|
||||
pub(crate) fn insert_resource_with_caller<R: Resource>(
|
||||
&mut self,
|
||||
value: R,
|
||||
#[cfg(feature = "track_location")] caller: &'static Location,
|
||||
caller: MaybeLocation,
|
||||
) {
|
||||
let component_id = self.components.register_resource::<R>();
|
||||
OwningPtr::make(value, |ptr| {
|
||||
// SAFETY: component_id was just initialized and corresponds to resource of type R.
|
||||
unsafe {
|
||||
self.insert_resource_by_id(
|
||||
component_id,
|
||||
ptr,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
self.insert_resource_by_id(component_id, ptr, caller);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -1706,8 +1651,7 @@ impl World {
|
||||
#[inline]
|
||||
#[track_caller]
|
||||
pub fn init_non_send_resource<R: 'static + FromWorld>(&mut self) -> ComponentId {
|
||||
#[cfg(feature = "track_location")]
|
||||
let caller = Location::caller();
|
||||
let caller = MaybeLocation::caller();
|
||||
let component_id = self.components.register_non_send::<R>();
|
||||
if self
|
||||
.storages
|
||||
@ -1719,12 +1663,7 @@ impl World {
|
||||
OwningPtr::make(value, |ptr| {
|
||||
// SAFETY: component_id was just initialized and corresponds to resource of type R.
|
||||
unsafe {
|
||||
self.insert_non_send_by_id(
|
||||
component_id,
|
||||
ptr,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
self.insert_non_send_by_id(component_id, ptr, caller);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -1743,18 +1682,12 @@ impl World {
|
||||
#[inline]
|
||||
#[track_caller]
|
||||
pub fn insert_non_send_resource<R: 'static>(&mut self, value: R) {
|
||||
#[cfg(feature = "track_location")]
|
||||
let caller = Location::caller();
|
||||
let caller = MaybeLocation::caller();
|
||||
let component_id = self.components.register_non_send::<R>();
|
||||
OwningPtr::make(value, |ptr| {
|
||||
// SAFETY: component_id was just initialized and corresponds to resource of type R.
|
||||
unsafe {
|
||||
self.insert_non_send_by_id(
|
||||
component_id,
|
||||
ptr,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
self.insert_non_send_by_id(component_id, ptr, caller);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -2029,8 +1962,7 @@ impl World {
|
||||
&mut self,
|
||||
func: impl FnOnce() -> R,
|
||||
) -> Mut<'_, R> {
|
||||
#[cfg(feature = "track_location")]
|
||||
let caller = Location::caller();
|
||||
let caller = MaybeLocation::caller();
|
||||
let change_tick = self.change_tick();
|
||||
let last_change_tick = self.last_change_tick();
|
||||
|
||||
@ -2040,12 +1972,7 @@ impl World {
|
||||
OwningPtr::make(func(), |ptr| {
|
||||
// SAFETY: component_id was just initialized and corresponds to resource of type R.
|
||||
unsafe {
|
||||
data.insert(
|
||||
ptr,
|
||||
change_tick,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
data.insert(ptr, change_tick, caller);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -2093,8 +2020,7 @@ impl World {
|
||||
/// ```
|
||||
#[track_caller]
|
||||
pub fn get_resource_or_init<R: Resource + FromWorld>(&mut self) -> Mut<'_, R> {
|
||||
#[cfg(feature = "track_location")]
|
||||
let caller = Location::caller();
|
||||
let caller = MaybeLocation::caller();
|
||||
let change_tick = self.change_tick();
|
||||
let last_change_tick = self.last_change_tick();
|
||||
|
||||
@ -2109,12 +2035,7 @@ impl World {
|
||||
OwningPtr::make(value, |ptr| {
|
||||
// SAFETY: component_id was just initialized and corresponds to resource of type R.
|
||||
unsafe {
|
||||
self.insert_resource_by_id(
|
||||
component_id,
|
||||
ptr,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
self.insert_resource_by_id(component_id, ptr, caller);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -2241,11 +2162,7 @@ impl World {
|
||||
I::IntoIter: Iterator<Item = (Entity, B)>,
|
||||
B: Bundle<Effect: NoBundleEffect>,
|
||||
{
|
||||
self.insert_or_spawn_batch_with_caller(
|
||||
iter,
|
||||
#[cfg(feature = "track_location")]
|
||||
Location::caller(),
|
||||
)
|
||||
self.insert_or_spawn_batch_with_caller(iter, MaybeLocation::caller())
|
||||
}
|
||||
|
||||
/// Split into a new function so we can pass the calling location into the function when using
|
||||
@ -2254,7 +2171,7 @@ impl World {
|
||||
pub(crate) fn insert_or_spawn_batch_with_caller<I, B>(
|
||||
&mut self,
|
||||
iter: I,
|
||||
#[cfg(feature = "track_location")] caller: &'static Location,
|
||||
caller: MaybeLocation,
|
||||
) -> Result<(), Vec<Entity>>
|
||||
where
|
||||
I: IntoIterator,
|
||||
@ -2304,7 +2221,6 @@ impl World {
|
||||
location,
|
||||
bundle,
|
||||
InsertMode::Replace,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
)
|
||||
};
|
||||
@ -2326,7 +2242,6 @@ impl World {
|
||||
location,
|
||||
bundle,
|
||||
InsertMode::Replace,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
)
|
||||
};
|
||||
@ -2338,27 +2253,13 @@ impl World {
|
||||
AllocAtWithoutReplacement::DidNotExist => {
|
||||
if let SpawnOrInsert::Spawn(ref mut spawner) = spawn_or_insert {
|
||||
// SAFETY: `entity` is allocated (but non existent), bundle matches inserter
|
||||
unsafe {
|
||||
spawner.spawn_non_existent(
|
||||
entity,
|
||||
bundle,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
)
|
||||
};
|
||||
unsafe { spawner.spawn_non_existent(entity, bundle, caller) };
|
||||
} else {
|
||||
// SAFETY: we initialized this bundle_id in `init_info`
|
||||
let mut spawner =
|
||||
unsafe { BundleSpawner::new_with_id(self, bundle_id, change_tick) };
|
||||
// SAFETY: `entity` is valid, `location` matches entity, bundle matches inserter
|
||||
unsafe {
|
||||
spawner.spawn_non_existent(
|
||||
entity,
|
||||
bundle,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
)
|
||||
};
|
||||
unsafe { spawner.spawn_non_existent(entity, bundle, caller) };
|
||||
spawn_or_insert = SpawnOrInsert::Spawn(spawner);
|
||||
}
|
||||
}
|
||||
@ -2397,12 +2298,7 @@ impl World {
|
||||
I::IntoIter: Iterator<Item = (Entity, B)>,
|
||||
B: Bundle<Effect: NoBundleEffect>,
|
||||
{
|
||||
self.insert_batch_with_caller(
|
||||
batch,
|
||||
InsertMode::Replace,
|
||||
#[cfg(feature = "track_location")]
|
||||
Location::caller(),
|
||||
);
|
||||
self.insert_batch_with_caller(batch, InsertMode::Replace, MaybeLocation::caller());
|
||||
}
|
||||
|
||||
/// For a given batch of ([`Entity`], [`Bundle`]) pairs,
|
||||
@ -2427,12 +2323,7 @@ impl World {
|
||||
I::IntoIter: Iterator<Item = (Entity, B)>,
|
||||
B: Bundle<Effect: NoBundleEffect>,
|
||||
{
|
||||
self.insert_batch_with_caller(
|
||||
batch,
|
||||
InsertMode::Keep,
|
||||
#[cfg(feature = "track_location")]
|
||||
Location::caller(),
|
||||
);
|
||||
self.insert_batch_with_caller(batch, InsertMode::Keep, MaybeLocation::caller());
|
||||
}
|
||||
|
||||
/// Split into a new function so we can differentiate the calling location.
|
||||
@ -2445,7 +2336,7 @@ impl World {
|
||||
&mut self,
|
||||
batch: I,
|
||||
insert_mode: InsertMode,
|
||||
#[cfg(feature = "track_location")] caller: &'static Location,
|
||||
caller: MaybeLocation,
|
||||
) where
|
||||
I: IntoIterator,
|
||||
I::IntoIter: Iterator<Item = (Entity, B)>,
|
||||
@ -2485,7 +2376,6 @@ impl World {
|
||||
first_location,
|
||||
first_bundle,
|
||||
insert_mode,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
)
|
||||
};
|
||||
@ -2508,14 +2398,9 @@ impl World {
|
||||
}
|
||||
// SAFETY: `entity` is valid, `location` matches entity, bundle matches inserter
|
||||
unsafe {
|
||||
cache.inserter.insert(
|
||||
entity,
|
||||
location,
|
||||
bundle,
|
||||
insert_mode,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
)
|
||||
cache
|
||||
.inserter
|
||||
.insert(entity, location, bundle, insert_mode, caller)
|
||||
};
|
||||
} else {
|
||||
panic!("error[B0003]: Could not insert a bundle (of type `{}`) for entity {entity}, which {}. See: https://bevyengine.org/learn/errors/b0003", core::any::type_name::<B>(), self.entities.entity_does_not_exist_error_details(entity));
|
||||
@ -2547,12 +2432,7 @@ impl World {
|
||||
I::IntoIter: Iterator<Item = (Entity, B)>,
|
||||
B: Bundle<Effect: NoBundleEffect>,
|
||||
{
|
||||
self.try_insert_batch_with_caller(
|
||||
batch,
|
||||
InsertMode::Replace,
|
||||
#[cfg(feature = "track_location")]
|
||||
Location::caller(),
|
||||
)
|
||||
self.try_insert_batch_with_caller(batch, InsertMode::Replace, MaybeLocation::caller())
|
||||
}
|
||||
/// For a given batch of ([`Entity`], [`Bundle`]) pairs,
|
||||
/// adds the `Bundle` of components to each `Entity` without overwriting.
|
||||
@ -2574,12 +2454,7 @@ impl World {
|
||||
I::IntoIter: Iterator<Item = (Entity, B)>,
|
||||
B: Bundle<Effect: NoBundleEffect>,
|
||||
{
|
||||
self.try_insert_batch_with_caller(
|
||||
batch,
|
||||
InsertMode::Keep,
|
||||
#[cfg(feature = "track_location")]
|
||||
Location::caller(),
|
||||
)
|
||||
self.try_insert_batch_with_caller(batch, InsertMode::Keep, MaybeLocation::caller())
|
||||
}
|
||||
|
||||
/// Split into a new function so we can differentiate the calling location.
|
||||
@ -2596,7 +2471,7 @@ impl World {
|
||||
&mut self,
|
||||
batch: I,
|
||||
insert_mode: InsertMode,
|
||||
#[cfg(feature = "track_location")] caller: &'static Location,
|
||||
caller: MaybeLocation,
|
||||
) -> Result<(), TryInsertBatchError>
|
||||
where
|
||||
I: IntoIterator,
|
||||
@ -2642,7 +2517,6 @@ impl World {
|
||||
first_location,
|
||||
first_bundle,
|
||||
insert_mode,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
)
|
||||
};
|
||||
@ -2674,14 +2548,9 @@ impl World {
|
||||
}
|
||||
// SAFETY: `entity` is valid, `location` matches entity, bundle matches inserter
|
||||
unsafe {
|
||||
cache.inserter.insert(
|
||||
entity,
|
||||
location,
|
||||
bundle,
|
||||
insert_mode,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
)
|
||||
cache
|
||||
.inserter
|
||||
.insert(entity, location, bundle, insert_mode, caller)
|
||||
};
|
||||
} else {
|
||||
invalid_entities.push(entity);
|
||||
@ -2745,7 +2614,7 @@ impl World {
|
||||
let change_tick = self.change_tick();
|
||||
|
||||
let component_id = self.components.get_resource_id(TypeId::of::<R>())?;
|
||||
let (ptr, mut ticks, mut _caller) = self
|
||||
let (ptr, mut ticks, mut caller) = self
|
||||
.storages
|
||||
.resources
|
||||
.get_mut(component_id)
|
||||
@ -2761,8 +2630,7 @@ impl World {
|
||||
last_run: last_change_tick,
|
||||
this_run: change_tick,
|
||||
},
|
||||
#[cfg(feature = "track_location")]
|
||||
changed_by: &mut _caller,
|
||||
changed_by: caller.as_mut(),
|
||||
};
|
||||
let result = f(self, value_mut);
|
||||
assert!(!self.contains_resource::<R>(),
|
||||
@ -2774,12 +2642,7 @@ impl World {
|
||||
// SAFETY: pointer is of type R
|
||||
unsafe {
|
||||
self.storages.resources.get_mut(component_id).map(|info| {
|
||||
info.insert_with_ticks(
|
||||
ptr,
|
||||
ticks,
|
||||
#[cfg(feature = "track_location")]
|
||||
_caller,
|
||||
);
|
||||
info.insert_with_ticks(ptr, ticks, caller);
|
||||
})
|
||||
}
|
||||
})?;
|
||||
@ -2834,19 +2697,14 @@ impl World {
|
||||
&mut self,
|
||||
component_id: ComponentId,
|
||||
value: OwningPtr<'_>,
|
||||
#[cfg(feature = "track_location")] caller: &'static Location,
|
||||
caller: MaybeLocation,
|
||||
) {
|
||||
let change_tick = self.change_tick();
|
||||
|
||||
let resource = self.initialize_resource_internal(component_id);
|
||||
// SAFETY: `value` is valid for `component_id`, ensured by caller
|
||||
unsafe {
|
||||
resource.insert(
|
||||
value,
|
||||
change_tick,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
resource.insert(value, change_tick, caller);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2868,19 +2726,14 @@ impl World {
|
||||
&mut self,
|
||||
component_id: ComponentId,
|
||||
value: OwningPtr<'_>,
|
||||
#[cfg(feature = "track_location")] caller: &'static Location,
|
||||
caller: MaybeLocation,
|
||||
) {
|
||||
let change_tick = self.change_tick();
|
||||
|
||||
let resource = self.initialize_non_send_internal(component_id);
|
||||
// SAFETY: `value` is valid for `component_id`, ensured by caller
|
||||
unsafe {
|
||||
resource.insert(
|
||||
value,
|
||||
change_tick,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
);
|
||||
resource.insert(value, change_tick, caller);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3410,7 +3263,7 @@ impl World {
|
||||
.get_info(component_id)
|
||||
.debug_checked_unwrap()
|
||||
};
|
||||
let (ptr, ticks, _caller) = data.get_with_ticks()?;
|
||||
let (ptr, ticks, caller) = data.get_with_ticks()?;
|
||||
|
||||
// SAFETY:
|
||||
// - We have exclusive access to the world, so no other code can be aliasing the `TickCells`
|
||||
@ -3429,11 +3282,10 @@ impl World {
|
||||
// - We iterate one resource at a time, and we let go of each `PtrMut` before getting the next one
|
||||
value: unsafe { ptr.assert_unique() },
|
||||
ticks,
|
||||
#[cfg(feature = "track_location")]
|
||||
// SAFETY:
|
||||
// - We have exclusive access to the world, so no other code can be aliasing the `Ptr`
|
||||
// - We iterate one resource at a time, and we let go of each `PtrMut` before getting the next one
|
||||
changed_by: unsafe { _caller.deref_mut() },
|
||||
changed_by: unsafe { caller.map(|caller| caller.deref_mut()) },
|
||||
};
|
||||
|
||||
Some((component_info, mut_untyped))
|
||||
@ -3744,7 +3596,7 @@ impl<T: Default> FromWorld for T {
|
||||
mod tests {
|
||||
use super::{FromWorld, World};
|
||||
use crate::{
|
||||
change_detection::DetectChangesMut,
|
||||
change_detection::{DetectChangesMut, MaybeLocation},
|
||||
component::{ComponentCloneBehavior, ComponentDescriptor, ComponentInfo, StorageType},
|
||||
entity::hash_set::EntityHashSet,
|
||||
entity_disabling::{DefaultQueryFilters, Disabled},
|
||||
@ -4007,12 +3859,7 @@ mod tests {
|
||||
OwningPtr::make(value, |ptr| {
|
||||
// SAFETY: value is valid for the layout of `TestResource`
|
||||
unsafe {
|
||||
world.insert_resource_by_id(
|
||||
component_id,
|
||||
ptr,
|
||||
#[cfg(feature = "track_location")]
|
||||
panic::Location::caller(),
|
||||
);
|
||||
world.insert_resource_by_id(component_id, ptr, MaybeLocation::caller());
|
||||
}
|
||||
});
|
||||
|
||||
@ -4056,12 +3903,7 @@ mod tests {
|
||||
OwningPtr::make(value, |ptr| {
|
||||
// SAFETY: value is valid for the component layout
|
||||
unsafe {
|
||||
world.insert_resource_by_id(
|
||||
component_id,
|
||||
ptr,
|
||||
#[cfg(feature = "track_location")]
|
||||
panic::Location::caller(),
|
||||
);
|
||||
world.insert_resource_by_id(component_id, ptr, MaybeLocation::caller());
|
||||
}
|
||||
});
|
||||
|
||||
@ -4402,7 +4244,6 @@ mod tests {
|
||||
Err(EntityFetchError::NoSuchEntity(e, ..)) if e == e1));
|
||||
}
|
||||
|
||||
#[cfg(feature = "track_location")]
|
||||
#[test]
|
||||
#[track_caller]
|
||||
fn entity_spawn_despawn_tracking() {
|
||||
@ -4412,23 +4253,23 @@ mod tests {
|
||||
let entity = world.spawn_empty().id();
|
||||
assert_eq!(
|
||||
world.entities.entity_get_spawned_or_despawned_by(entity),
|
||||
Some(Location::caller())
|
||||
MaybeLocation::new(Some(Location::caller()))
|
||||
);
|
||||
world.despawn(entity);
|
||||
assert_eq!(
|
||||
world.entities.entity_get_spawned_or_despawned_by(entity),
|
||||
Some(Location::caller())
|
||||
MaybeLocation::new(Some(Location::caller()))
|
||||
);
|
||||
let new = world.spawn_empty().id();
|
||||
assert_eq!(entity.index(), new.index());
|
||||
assert_eq!(
|
||||
world.entities.entity_get_spawned_or_despawned_by(entity),
|
||||
None
|
||||
MaybeLocation::new(None)
|
||||
);
|
||||
world.despawn(new);
|
||||
assert_eq!(
|
||||
world.entities.entity_get_spawned_or_despawned_by(entity),
|
||||
None
|
||||
MaybeLocation::new(None)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -1,11 +1,10 @@
|
||||
use crate::{
|
||||
bundle::{Bundle, BundleSpawner, NoBundleEffect},
|
||||
change_detection::MaybeLocation,
|
||||
entity::{Entity, EntitySetIterator},
|
||||
world::World,
|
||||
};
|
||||
use core::iter::FusedIterator;
|
||||
#[cfg(feature = "track_location")]
|
||||
use core::panic::Location;
|
||||
|
||||
/// An iterator that spawns a series of entities and returns the [ID](Entity) of
|
||||
/// each spawned entity.
|
||||
@ -18,8 +17,7 @@ where
|
||||
{
|
||||
inner: I,
|
||||
spawner: BundleSpawner<'w>,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller: &'static Location<'static>,
|
||||
caller: MaybeLocation,
|
||||
}
|
||||
|
||||
impl<'w, I> SpawnBatchIter<'w, I>
|
||||
@ -29,11 +27,7 @@ where
|
||||
{
|
||||
#[inline]
|
||||
#[track_caller]
|
||||
pub(crate) fn new(
|
||||
world: &'w mut World,
|
||||
iter: I,
|
||||
#[cfg(feature = "track_location")] caller: &'static Location,
|
||||
) -> Self {
|
||||
pub(crate) fn new(world: &'w mut World, iter: I, caller: MaybeLocation) -> Self {
|
||||
// Ensure all entity allocations are accounted for so `self.entities` can realloc if
|
||||
// necessary
|
||||
world.flush();
|
||||
@ -50,7 +44,6 @@ where
|
||||
Self {
|
||||
inner: iter,
|
||||
spawner,
|
||||
#[cfg(feature = "track_location")]
|
||||
caller,
|
||||
}
|
||||
}
|
||||
@ -80,17 +73,7 @@ where
|
||||
fn next(&mut self) -> Option<Entity> {
|
||||
let bundle = self.inner.next()?;
|
||||
// SAFETY: bundle matches spawner type
|
||||
unsafe {
|
||||
Some(
|
||||
self.spawner
|
||||
.spawn(
|
||||
bundle,
|
||||
#[cfg(feature = "track_location")]
|
||||
self.caller,
|
||||
)
|
||||
.0,
|
||||
)
|
||||
}
|
||||
unsafe { Some(self.spawner.spawn(bundle, self.caller).0) }
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
|
||||
@ -4,7 +4,7 @@ use super::{Mut, Ref, World, WorldId};
|
||||
use crate::{
|
||||
archetype::{Archetype, Archetypes},
|
||||
bundle::Bundles,
|
||||
change_detection::{MaybeUnsafeCellLocation, MutUntyped, Ticks, TicksMut},
|
||||
change_detection::{MaybeLocation, MutUntyped, Ticks, TicksMut},
|
||||
component::{ComponentId, ComponentTicks, Components, Mutable, StorageType, Tick, TickCells},
|
||||
entity::{Entities, Entity, EntityBorrow, EntityLocation},
|
||||
observer::Observers,
|
||||
@ -16,13 +16,10 @@ use crate::{
|
||||
world::RawCommandQueue,
|
||||
};
|
||||
use bevy_platform_support::sync::atomic::Ordering;
|
||||
use bevy_ptr::Ptr;
|
||||
use core::{any::TypeId, cell::UnsafeCell, fmt::Debug, marker::PhantomData, ptr};
|
||||
use bevy_ptr::{Ptr, UnsafeCellDeref};
|
||||
use core::{any::TypeId, cell::UnsafeCell, fmt::Debug, marker::PhantomData, panic::Location, ptr};
|
||||
use thiserror::Error;
|
||||
|
||||
#[cfg(feature = "track_location")]
|
||||
use {bevy_ptr::UnsafeCellDeref, core::panic::Location};
|
||||
|
||||
/// 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.
|
||||
///
|
||||
@ -389,7 +386,7 @@ impl<'w> UnsafeWorldCell<'w> {
|
||||
|
||||
// SAFETY: caller ensures `self` has permission to access the resource
|
||||
// caller also ensure that no mutable reference to the resource exists
|
||||
let (ptr, ticks, _caller) = unsafe { self.get_resource_with_ticks(component_id)? };
|
||||
let (ptr, ticks, caller) = unsafe { self.get_resource_with_ticks(component_id)? };
|
||||
|
||||
// SAFETY: `component_id` was obtained from the type ID of `R`
|
||||
let value = unsafe { ptr.deref::<R>() };
|
||||
@ -399,13 +396,11 @@ impl<'w> UnsafeWorldCell<'w> {
|
||||
unsafe { Ticks::from_tick_cells(ticks, self.last_change_tick(), self.change_tick()) };
|
||||
|
||||
// SAFETY: caller ensures that no mutable reference to the resource exists
|
||||
#[cfg(feature = "track_location")]
|
||||
let caller = unsafe { _caller.deref() };
|
||||
let caller = caller.map(|caller| unsafe { caller.deref() });
|
||||
|
||||
Some(Ref {
|
||||
value,
|
||||
ticks,
|
||||
#[cfg(feature = "track_location")]
|
||||
changed_by: caller,
|
||||
})
|
||||
}
|
||||
@ -512,7 +507,7 @@ impl<'w> UnsafeWorldCell<'w> {
|
||||
self.assert_allows_mutable_access();
|
||||
// SAFETY: we only access data that the caller has ensured is unaliased and `self`
|
||||
// has permission to access.
|
||||
let (ptr, ticks, _caller) = unsafe { self.storages() }
|
||||
let (ptr, ticks, caller) = unsafe { self.storages() }
|
||||
.resources
|
||||
.get(component_id)?
|
||||
.get_with_ticks()?;
|
||||
@ -530,11 +525,10 @@ impl<'w> UnsafeWorldCell<'w> {
|
||||
// - caller ensures that the resource is unaliased
|
||||
value: unsafe { ptr.assert_unique() },
|
||||
ticks,
|
||||
#[cfg(feature = "track_location")]
|
||||
// SAFETY:
|
||||
// - caller ensures that `self` has permission to access the resource
|
||||
// - caller ensures that the resource is unaliased
|
||||
changed_by: unsafe { _caller.deref_mut() },
|
||||
changed_by: unsafe { caller.map(|caller| caller.deref_mut()) },
|
||||
})
|
||||
}
|
||||
|
||||
@ -581,7 +575,7 @@ impl<'w> UnsafeWorldCell<'w> {
|
||||
let change_tick = self.change_tick();
|
||||
// SAFETY: we only access data that the caller has ensured is unaliased and `self`
|
||||
// has permission to access.
|
||||
let (ptr, ticks, _caller) = unsafe { self.storages() }
|
||||
let (ptr, ticks, caller) = unsafe { self.storages() }
|
||||
.non_send_resources
|
||||
.get(component_id)?
|
||||
.get_with_ticks()?;
|
||||
@ -596,9 +590,8 @@ impl<'w> UnsafeWorldCell<'w> {
|
||||
// SAFETY: This function has exclusive access to the world so nothing aliases `ptr`.
|
||||
value: unsafe { ptr.assert_unique() },
|
||||
ticks,
|
||||
#[cfg(feature = "track_location")]
|
||||
// SAFETY: This function has exclusive access to the world
|
||||
changed_by: unsafe { _caller.deref_mut() },
|
||||
changed_by: unsafe { caller.map(|caller| caller.deref_mut()) },
|
||||
})
|
||||
}
|
||||
|
||||
@ -611,7 +604,11 @@ impl<'w> UnsafeWorldCell<'w> {
|
||||
pub(crate) unsafe fn get_resource_with_ticks(
|
||||
self,
|
||||
component_id: ComponentId,
|
||||
) -> Option<(Ptr<'w>, TickCells<'w>, MaybeUnsafeCellLocation<'w>)> {
|
||||
) -> Option<(
|
||||
Ptr<'w>,
|
||||
TickCells<'w>,
|
||||
MaybeLocation<&'w UnsafeCell<&'static Location<'static>>>,
|
||||
)> {
|
||||
// SAFETY:
|
||||
// - caller ensures there is no `&mut World`
|
||||
// - caller ensures there are no mutable borrows of this resource
|
||||
@ -634,7 +631,11 @@ impl<'w> UnsafeWorldCell<'w> {
|
||||
pub(crate) unsafe fn get_non_send_with_ticks(
|
||||
self,
|
||||
component_id: ComponentId,
|
||||
) -> Option<(Ptr<'w>, TickCells<'w>, MaybeUnsafeCellLocation<'w>)> {
|
||||
) -> Option<(
|
||||
Ptr<'w>,
|
||||
TickCells<'w>,
|
||||
MaybeLocation<&'w UnsafeCell<&'static Location<'static>>>,
|
||||
)> {
|
||||
// SAFETY:
|
||||
// - caller ensures there is no `&mut World`
|
||||
// - caller ensures there are no mutable borrows of this resource
|
||||
@ -808,12 +809,11 @@ impl<'w> UnsafeEntityCell<'w> {
|
||||
self.entity,
|
||||
self.location,
|
||||
)
|
||||
.map(|(value, cells, _caller)| Ref {
|
||||
.map(|(value, cells, caller)| Ref {
|
||||
// SAFETY: returned component is of type T
|
||||
value: value.deref::<T>(),
|
||||
ticks: Ticks::from_tick_cells(cells, last_change_tick, change_tick),
|
||||
#[cfg(feature = "track_location")]
|
||||
changed_by: _caller.deref(),
|
||||
changed_by: caller.map(|caller| caller.deref()),
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -930,12 +930,11 @@ impl<'w> UnsafeEntityCell<'w> {
|
||||
self.entity,
|
||||
self.location,
|
||||
)
|
||||
.map(|(value, cells, _caller)| Mut {
|
||||
.map(|(value, cells, caller)| Mut {
|
||||
// SAFETY: returned component is of type T
|
||||
value: value.assert_unique().deref_mut::<T>(),
|
||||
ticks: TicksMut::from_tick_cells(cells, last_change_tick, change_tick),
|
||||
#[cfg(feature = "track_location")]
|
||||
changed_by: _caller.deref_mut(),
|
||||
changed_by: caller.map(|caller| caller.deref_mut()),
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -1054,7 +1053,7 @@ impl<'w> UnsafeEntityCell<'w> {
|
||||
self.entity,
|
||||
self.location,
|
||||
)
|
||||
.map(|(value, cells, _caller)| MutUntyped {
|
||||
.map(|(value, cells, caller)| MutUntyped {
|
||||
// SAFETY: world access validated by caller and ties world lifetime to `MutUntyped` lifetime
|
||||
value: value.assert_unique(),
|
||||
ticks: TicksMut::from_tick_cells(
|
||||
@ -1062,20 +1061,18 @@ impl<'w> UnsafeEntityCell<'w> {
|
||||
self.world.last_change_tick(),
|
||||
self.world.change_tick(),
|
||||
),
|
||||
#[cfg(feature = "track_location")]
|
||||
changed_by: _caller.deref_mut(),
|
||||
changed_by: caller.map(|caller| caller.deref_mut()),
|
||||
})
|
||||
.ok_or(GetEntityMutByIdError::ComponentNotFound)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the source code location from which this entity has been spawned.
|
||||
#[cfg(feature = "track_location")]
|
||||
pub fn spawned_by(self) -> &'static Location<'static> {
|
||||
pub fn spawned_by(self) -> MaybeLocation {
|
||||
self.world()
|
||||
.entities()
|
||||
.entity_get_spawned_or_despawned_by(self.entity)
|
||||
.unwrap()
|
||||
.map(|o| o.unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
@ -1159,7 +1156,11 @@ unsafe fn get_component_and_ticks(
|
||||
storage_type: StorageType,
|
||||
entity: Entity,
|
||||
location: EntityLocation,
|
||||
) -> Option<(Ptr<'_>, TickCells<'_>, MaybeUnsafeCellLocation<'_>)> {
|
||||
) -> Option<(
|
||||
Ptr<'_>,
|
||||
TickCells<'_>,
|
||||
MaybeLocation<&UnsafeCell<&'static Location<'static>>>,
|
||||
)> {
|
||||
match storage_type {
|
||||
StorageType::Table => {
|
||||
let table = world.fetch_table(location)?;
|
||||
@ -1175,12 +1176,9 @@ unsafe fn get_component_and_ticks(
|
||||
.get_changed_tick(component_id, location.table_row)
|
||||
.debug_checked_unwrap(),
|
||||
},
|
||||
#[cfg(feature = "track_location")]
|
||||
table
|
||||
.get_changed_by(component_id, location.table_row)
|
||||
.debug_checked_unwrap(),
|
||||
#[cfg(not(feature = "track_location"))]
|
||||
(),
|
||||
.map(|changed_by| changed_by.debug_checked_unwrap()),
|
||||
))
|
||||
}
|
||||
StorageType::SparseSet => world.fetch_sparse_set(component_id)?.get_with_ticks(entity),
|
||||
|
||||
Loading…
Reference in New Issue
Block a user