doc improvements

This commit is contained in:
Elliott Pierce 2025-05-31 17:40:09 -04:00
parent 8956adcc5b
commit 0c194b734a
10 changed files with 53 additions and 54 deletions

View File

@ -1579,7 +1579,7 @@ mod tests {
app.add_systems(EnterMainMenu, (foo, bar)); app.add_systems(EnterMainMenu, (foo, bar));
app.world_mut().run_schedule(EnterMainMenu); app.world_mut().run_schedule(EnterMainMenu);
assert_eq!(app.world().entities().count_active(), 2); assert_eq!(app.world().entities().count_constructed(), 2);
} }
#[test] #[test]

View File

@ -22,6 +22,6 @@ impl EntityCountDiagnosticsPlugin {
pub const ENTITY_COUNT: DiagnosticPath = DiagnosticPath::const_new("entity_count"); pub const ENTITY_COUNT: DiagnosticPath = DiagnosticPath::const_new("entity_count");
pub fn diagnostic_system(mut diagnostics: Diagnostics, entities: &Entities) { pub fn diagnostic_system(mut diagnostics: Diagnostics, entities: &Entities) {
diagnostics.add_measurement(&Self::ENTITY_COUNT, || entities.count_active() as f64); diagnostics.add_measurement(&Self::ENTITY_COUNT, || entities.count_constructed() as f64);
} }
} }

View File

@ -761,7 +761,7 @@ impl<'a> Iterator for AllocEntitiesIterator<'a> {
impl<'a> ExactSizeIterator for AllocEntitiesIterator<'a> {} impl<'a> ExactSizeIterator for AllocEntitiesIterator<'a> {}
impl<'a> core::iter::FusedIterator for AllocEntitiesIterator<'a> {} impl<'a> core::iter::FusedIterator for AllocEntitiesIterator<'a> {}
// SAFETY: Newly reserved entity values are unique. // SAFETY: Newly allocated entity values are unique.
unsafe impl EntitySetIterator for AllocEntitiesIterator<'_> {} unsafe impl EntitySetIterator for AllocEntitiesIterator<'_> {}
/// [`Entities`] tracks all know [`EntityRow`]s and their metadata. /// [`Entities`] tracks all know [`EntityRow`]s and their metadata.
@ -781,8 +781,7 @@ impl Entities {
self.meta.clear(); self.meta.clear();
} }
/// Returns the [`EntityLocation`] of an [`Entity`]. /// Returns the [`EntityLocation`] of an [`Entity`] if it exists and is constructed.
/// Note: for non-constructed entities, returns `None`.
#[inline] #[inline]
pub fn get_constructed( pub fn get_constructed(
&self, &self,
@ -829,7 +828,7 @@ impl Entities {
} }
} }
/// Returns the [`EntityIdLocation`] of an [`Entity`]. /// Returns the [`EntityIdLocation`] of an [`Entity`] if it exists.
#[inline] #[inline]
pub fn get(&self, entity: Entity) -> Result<EntityIdLocation, EntityDoesNotExistError> { pub fn get(&self, entity: Entity) -> Result<EntityIdLocation, EntityDoesNotExistError> {
match self.meta.get(entity.index() as usize) { match self.meta.get(entity.index() as usize) {
@ -866,14 +865,22 @@ impl Entities {
.unwrap_or(Entity::from_raw(row)) .unwrap_or(Entity::from_raw(row))
} }
/// Returns whether the entity at this `row` is constructed or not.
#[inline]
pub fn is_row_constructed(&self, row: EntityRow) -> bool {
self.meta
.get(row.index() as usize)
.map(|meta| meta.location.is_some())
.unwrap_or_default()
}
/// Returns true if the entity exists. /// Returns true if the entity exists.
/// This will return true for entities that exist but have not been constructed. /// This will return true for entities that exist but have not been constructed.
pub fn contains(&self, entity: Entity) -> bool { pub fn contains(&self, entity: Entity) -> bool {
self.resolve_from_row(entity.row()).generation() == entity.generation() self.resolve_from_row(entity.row()).generation() == entity.generation()
} }
/// Returns true if the entity exists in the world *now*. /// Returns true if the entity exists and are constructed.
/// This will return false if the `entity` is not constructed.
pub fn contains_constructed(&self, entity: Entity) -> bool { pub fn contains_constructed(&self, entity: Entity) -> bool {
self.get_constructed(entity).is_ok() self.get_constructed(entity).is_ok()
} }
@ -922,8 +929,7 @@ impl Entities {
) -> EntityIdLocation { ) -> EntityIdLocation {
self.ensure_row(row); self.ensure_row(row);
// SAFETY: We just did `ensure_row` // SAFETY: We just did `ensure_row`
let meta = unsafe { self.meta.get_unchecked_mut(row.index() as usize) }; self.update(row, location)
mem::replace(&mut meta.location, location)
} }
/// Ensures row is valid. /// Ensures row is valid.
@ -931,9 +937,9 @@ impl Entities {
fn ensure_row(&mut self, row: EntityRow) { fn ensure_row(&mut self, row: EntityRow) {
#[cold] // to help with branch prediction #[cold] // to help with branch prediction
fn expand(meta: &mut Vec<EntityMeta>, len: usize) { fn expand(meta: &mut Vec<EntityMeta>, len: usize) {
meta.resize(len, EntityMeta::EMPTY); meta.resize(len, EntityMeta::FRESH);
// Set these up too while we're here. // Set these up too while we're here.
meta.resize(meta.capacity(), EntityMeta::EMPTY); meta.resize(meta.capacity(), EntityMeta::FRESH);
} }
let index = row.index() as usize; let index = row.index() as usize;
@ -947,7 +953,7 @@ impl Entities {
/// ///
/// # Safety /// # Safety
/// ///
/// - `row` must its [`EntityIdLocation`] set to `None`. /// - `row` must be destructed (have no location) already.
pub(crate) unsafe fn mark_free(&mut self, row: EntityRow, generations: u32) -> Entity { pub(crate) unsafe fn mark_free(&mut self, row: EntityRow, generations: u32) -> Entity {
// We need to do this in case an entity is being freed that was never constructed. // We need to do this in case an entity is being freed that was never constructed.
self.ensure_row(row); self.ensure_row(row);
@ -966,7 +972,7 @@ impl Entities {
/// Mark an [`EntityRow`] as constructed or destructed in the given tick. /// Mark an [`EntityRow`] as constructed or destructed in the given tick.
/// ///
/// # Safety /// # Safety
/// - `row` must have either been constructed or destructed, ensuring its row is valid. /// - `row` must have been constructed at least once, ensuring its row is valid.
#[inline] #[inline]
pub(crate) unsafe fn mark_construct_or_destruct( pub(crate) unsafe fn mark_construct_or_destruct(
&mut self, &mut self,
@ -979,11 +985,9 @@ impl Entities {
meta.spawned_or_despawned = SpawnedOrDespawned { by, at }; meta.spawned_or_despawned = SpawnedOrDespawned { by, at };
} }
/// Try to get the source code location from which this entity has last been /// Try to get the source code location from which this entity has last been constructed or destructed.
/// spawned, despawned or flushed.
/// ///
/// Returns `None` if its index has been reused by another entity /// Returns `None` if the entity does not exist or has never been construced/destructed.
/// or if this entity has never existed.
pub fn entity_get_spawned_or_despawned_by( pub fn entity_get_spawned_or_despawned_by(
&self, &self,
entity: Entity, entity: Entity,
@ -994,21 +998,17 @@ impl Entities {
}) })
} }
/// Try to get the [`Tick`] at which this entity has last been /// Try to get the [`Tick`] at which this entity has last been constructed or destructed.
/// spawned, despawned or flushed.
/// ///
/// Returns `None` if its index has been reused by another entity or if this entity /// Returns `None` if the entity does not exist or has never been construced/destructed.
/// has never been spawned.
pub fn entity_get_spawned_or_despawned_at(&self, entity: Entity) -> Option<Tick> { pub fn entity_get_spawned_or_despawned_at(&self, entity: Entity) -> Option<Tick> {
self.entity_get_spawned_or_despawned(entity) self.entity_get_spawned_or_despawned(entity)
.map(|spawned_or_despawned| spawned_or_despawned.at) .map(|spawned_or_despawned| spawned_or_despawned.at)
} }
/// Try to get the [`SpawnedOrDespawned`] related to the entity's last spawn, /// Try to get the [`SpawnedOrDespawned`] related to the entity's last construction or destruction.
/// despawn or flush.
/// ///
/// Returns `None` if its index has been reused by another entity or if /// Returns `None` if the entity does not exist or has never been construced/destructed.
/// this entity has never been spawned.
#[inline] #[inline]
fn entity_get_spawned_or_despawned(&self, entity: Entity) -> Option<SpawnedOrDespawned> { fn entity_get_spawned_or_despawned(&self, entity: Entity) -> Option<SpawnedOrDespawned> {
self.meta self.meta
@ -1016,8 +1016,7 @@ impl Entities {
.filter(|meta| .filter(|meta|
// Generation is incremented immediately upon despawn // Generation is incremented immediately upon despawn
(meta.generation == entity.generation) (meta.generation == entity.generation)
|| meta.location.is_none() || (meta.location.is_none() && meta.generation == entity.generation.after_versions(1)))
&& (meta.generation == entity.generation.after_versions(1)))
.map(|meta| meta.spawned_or_despawned) .map(|meta| meta.spawned_or_despawned)
} }
@ -1051,22 +1050,22 @@ impl Entities {
self.meta.len() as u32 self.meta.len() as u32
} }
/// Checks if any entity has been allocated /// Checks if any entity has been declared
#[inline] #[inline]
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
self.len() == 0 self.len() == 0
} }
/// Counts the number of entities currently participating in the world, those that have locations. /// Counts the number of entities currently constructed, those that have locations.
pub fn count_active(&self) -> u32 { pub fn count_constructed(&self) -> u32 {
self.meta self.meta
.iter() .iter()
.filter(|meta| meta.location.is_some()) .filter(|meta| meta.location.is_some())
.count() as u32 .count() as u32
} }
/// Returns true if there are any entities active in the world, entities that have locations. /// Returns true if there are any entities currently constructed, entities that have locations.
pub fn any_active(&self) -> bool { pub fn any_constructed(&self) -> bool {
self.meta.iter().any(|meta| meta.location.is_some()) self.meta.iter().any(|meta| meta.location.is_some())
} }
} }
@ -1152,7 +1151,7 @@ struct EntityMeta {
generation: EntityGeneration, generation: EntityGeneration,
/// The current location of the [`EntityRow`]. /// The current location of the [`EntityRow`].
location: EntityIdLocation, location: EntityIdLocation,
/// Location and tick of the last spawn, despawn or flush of this entity. /// Location and tick of the last construct/destruct
spawned_or_despawned: SpawnedOrDespawned, spawned_or_despawned: SpawnedOrDespawned,
} }
@ -1163,8 +1162,8 @@ struct SpawnedOrDespawned {
} }
impl EntityMeta { impl EntityMeta {
/// meta for **pending entity** /// The metadata for a fresh entity: Never constructed/destructed, no location, etc.
const EMPTY: EntityMeta = EntityMeta { const FRESH: EntityMeta = EntityMeta {
generation: EntityGeneration::FIRST, generation: EntityGeneration::FIRST,
location: None, location: None,
spawned_or_despawned: SpawnedOrDespawned { spawned_or_despawned: SpawnedOrDespawned {

View File

@ -374,9 +374,9 @@ mod tests {
.construct((TableStored("def"), A(456))) .construct((TableStored("def"), A(456)))
.unwrap(); .unwrap();
assert_eq!(world.entities.count_active(), 2); assert_eq!(world.entities.count_constructed(), 2);
assert!(world.despawn(e1)); assert!(world.despawn(e1));
assert_eq!(world.entities.count_active(), 1); assert_eq!(world.entities.count_constructed(), 1);
assert!(world.get::<TableStored>(e1).is_none()); assert!(world.get::<TableStored>(e1).is_none());
assert!(world.get::<A>(e1).is_none()); assert!(world.get::<A>(e1).is_none());
assert_eq!(world.get::<TableStored>(e4).unwrap().0, "def"); assert_eq!(world.get::<TableStored>(e4).unwrap().0, "def");
@ -388,9 +388,9 @@ mod tests {
let mut world = World::new(); let mut world = World::new();
let e = world.spawn((TableStored("abc"), A(123))).id(); let e = world.spawn((TableStored("abc"), A(123))).id();
let f = world.spawn((TableStored("def"), A(456))).id(); let f = world.spawn((TableStored("def"), A(456))).id();
assert_eq!(world.entities.count_active(), 2); assert_eq!(world.entities.count_constructed(), 2);
assert!(world.despawn(e)); assert!(world.despawn(e));
assert_eq!(world.entities.count_active(), 1); assert_eq!(world.entities.count_constructed(), 1);
assert!(world.get::<TableStored>(e).is_none()); assert!(world.get::<TableStored>(e).is_none());
assert!(world.get::<A>(e).is_none()); assert!(world.get::<A>(e).is_none());
assert_eq!(world.get::<TableStored>(f).unwrap().0, "def"); assert_eq!(world.get::<TableStored>(f).unwrap().0, "def");
@ -403,9 +403,9 @@ mod tests {
let e = world.spawn((TableStored("abc"), SparseStored(123))).id(); let e = world.spawn((TableStored("abc"), SparseStored(123))).id();
let f = world.spawn((TableStored("def"), SparseStored(456))).id(); let f = world.spawn((TableStored("def"), SparseStored(456))).id();
assert_eq!(world.entities.count_active(), 2); assert_eq!(world.entities.count_constructed(), 2);
assert!(world.despawn(e)); assert!(world.despawn(e));
assert_eq!(world.entities.count_active(), 1); assert_eq!(world.entities.count_constructed(), 1);
assert!(world.get::<TableStored>(e).is_none()); assert!(world.get::<TableStored>(e).is_none());
assert!(world.get::<SparseStored>(e).is_none()); assert!(world.get::<SparseStored>(e).is_none());
assert_eq!(world.get::<TableStored>(f).unwrap().0, "def"); assert_eq!(world.get::<TableStored>(f).unwrap().0, "def");
@ -1640,7 +1640,7 @@ mod tests {
assert_eq!(q1.iter(&world).len(), 1); assert_eq!(q1.iter(&world).len(), 1);
assert_eq!(q2.iter(&world).len(), 1); assert_eq!(q2.iter(&world).len(), 1);
assert_eq!(world.entities().count_active(), 2); assert_eq!(world.entities().count_constructed(), 2);
world.clear_entities(); world.clear_entities();
@ -1655,7 +1655,7 @@ mod tests {
"world should not contain sparse set components" "world should not contain sparse set components"
); );
assert_eq!( assert_eq!(
world.entities().count_active(), world.entities().count_constructed(),
0, 0,
"world should not have any entities" "world should not have any entities"
); );

View File

@ -1079,7 +1079,7 @@ mod tests {
world.spawn(A).flush(); world.spawn(A).flush();
assert_eq!(vec!["add_2", "add_1"], world.resource::<Order>().0); assert_eq!(vec!["add_2", "add_1"], world.resource::<Order>().0);
// Our A entity plus our two observers // Our A entity plus our two observers
assert_eq!(world.entities().count_active(), 3); assert_eq!(world.entities().count_constructed(), 3);
} }
#[test] #[test]

View File

@ -2375,7 +2375,7 @@ mod tests {
.spawn((W(1u32), W(2u64))) .spawn((W(1u32), W(2u64)))
.id(); .id();
command_queue.apply(&mut world); command_queue.apply(&mut world);
assert_eq!(world.entities().count_active(), 1); assert_eq!(world.entities().count_constructed(), 1);
let results = world let results = world
.query::<(&W<u32>, &W<u64>)>() .query::<(&W<u32>, &W<u64>)>()
.iter(&world) .iter(&world)

View File

@ -423,9 +423,9 @@ mod tests {
#[test] #[test]
fn command_processing() { fn command_processing() {
let mut world = World::new(); let mut world = World::new();
assert_eq!(world.entities.count_active(), 0); assert_eq!(world.entities.count_constructed(), 0);
world.run_system_once(spawn_entity).unwrap(); world.run_system_once(spawn_entity).unwrap();
assert_eq!(world.entities.count_active(), 1); assert_eq!(world.entities.count_constructed(), 1);
} }
#[test] #[test]

View File

@ -657,9 +657,9 @@ mod tests {
let exclusive_system_id = world.register_system(|world: &mut World| { let exclusive_system_id = world.register_system(|world: &mut World| {
world.spawn_empty(); world.spawn_empty();
}); });
let entity_count = world.entities.count_active(); let entity_count = world.entities.count_constructed();
let _ = world.run_system(exclusive_system_id); let _ = world.run_system(exclusive_system_id);
assert_eq!(world.entities.count_active(), entity_count + 1); assert_eq!(world.entities.count_constructed(), entity_count + 1);
} }
#[test] #[test]

View File

@ -420,12 +420,12 @@ mod test {
let mut world = World::new(); let mut world = World::new();
queue.apply(&mut world); queue.apply(&mut world);
assert_eq!(world.entities().count_active(), 2); assert_eq!(world.entities().count_constructed(), 2);
// The previous call to `apply` cleared the queue. // The previous call to `apply` cleared the queue.
// This call should do nothing. // This call should do nothing.
queue.apply(&mut world); queue.apply(&mut world);
assert_eq!(world.entities().count_active(), 2); assert_eq!(world.entities().count_constructed(), 2);
} }
#[expect( #[expect(
@ -459,7 +459,7 @@ mod test {
queue.push(SpawnCommand); queue.push(SpawnCommand);
queue.push(SpawnCommand); queue.push(SpawnCommand);
queue.apply(&mut world); queue.apply(&mut world);
assert_eq!(world.entities().count_active(), 3); assert_eq!(world.entities().count_constructed(), 3);
} }
#[test] #[test]

View File

@ -3672,7 +3672,7 @@ impl fmt::Debug for World {
// Accessing any data stored in the world would be unsound. // Accessing any data stored in the world would be unsound.
f.debug_struct("World") f.debug_struct("World")
.field("id", &self.id) .field("id", &self.id)
.field("entity_count", &self.entities.count_active()) .field("entity_count", &self.entities.count_constructed())
.field("archetype_count", &self.archetypes.len()) .field("archetype_count", &self.archetypes.len())
.field("component_count", &self.components.len()) .field("component_count", &self.components.len())
.field("resource_count", &self.storages.resources.len()) .field("resource_count", &self.storages.resources.len())