From 0be06af2eace057125195f369c3751439654e117 Mon Sep 17 00:00:00 2001 From: mramirez Date: Tue, 11 Oct 2022 19:22:25 -0400 Subject: [PATCH] Add iter_entities to World (#6228) --- crates/bevy_ecs/src/world/mod.rs | 81 +++++++++++++++++++++++++++++++- 1 file changed, 80 insertions(+), 1 deletion(-) diff --git a/crates/bevy_ecs/src/world/mod.rs b/crates/bevy_ecs/src/world/mod.rs index 128c5e8dcf094..3e45e8c100fea 100644 --- a/crates/bevy_ecs/src/world/mod.rs +++ b/crates/bevy_ecs/src/world/mod.rs @@ -320,6 +320,16 @@ impl World { Some(EntityRef::new(self, entity, location)) } + /// Returns an [`Entity`] iterator of current entities. + /// + /// This is useful in contexts where you only have read-only access to the [`World`]. + #[inline] + pub fn iter_entities(&self) -> impl Iterator + '_ { + self.archetypes + .iter() + .flat_map(|archetype| archetype.entities().iter().copied()) + } + /// Retrieves an [`EntityMut`] that exposes read and write operations for the given `entity`. /// Returns [`None`] if the `entity` does not exist. Use [`World::entity_mut`] if you don't want /// to unwrap the [`EntityMut`] yourself. @@ -1634,7 +1644,7 @@ mod tests { system::Resource, }; use bevy_ecs_macros::Component; - use bevy_utils::HashSet; + use bevy_utils::{HashMap, HashSet}; use std::{ any::TypeId, panic, @@ -1907,4 +1917,73 @@ mod tests { [Some(baz_id)].into() ); } + + #[test] + fn iterate_entities() { + let mut world = World::new(); + let mut entity_counters = HashMap::new(); + + let iterate_and_count_entities = |world: &World, entity_counters: &mut HashMap<_, _>| { + entity_counters.clear(); + for entity in world.iter_entities() { + let counter = entity_counters.entry(entity).or_insert(0); + *counter += 1; + } + }; + + // Adding one entity and validating iteration + let ent0 = world.spawn((Foo, Bar, Baz)).id(); + + iterate_and_count_entities(&world, &mut entity_counters); + assert_eq!(entity_counters[&ent0], 1); + assert_eq!(entity_counters.len(), 1); + + // Spawning three more entities and then validating iteration + let ent1 = world.spawn((Foo, Bar)).id(); + let ent2 = world.spawn((Bar, Baz)).id(); + let ent3 = world.spawn((Foo, Baz)).id(); + + iterate_and_count_entities(&world, &mut entity_counters); + + assert_eq!(entity_counters[&ent0], 1); + assert_eq!(entity_counters[&ent1], 1); + assert_eq!(entity_counters[&ent2], 1); + assert_eq!(entity_counters[&ent3], 1); + assert_eq!(entity_counters.len(), 4); + + // Despawning first entity and then validating the iteration + assert!(world.despawn(ent0)); + + iterate_and_count_entities(&world, &mut entity_counters); + + assert_eq!(entity_counters[&ent1], 1); + assert_eq!(entity_counters[&ent2], 1); + assert_eq!(entity_counters[&ent3], 1); + assert_eq!(entity_counters.len(), 3); + + // Spawning three more entities, despawning three and then validating the iteration + let ent4 = world.spawn(Foo).id(); + let ent5 = world.spawn(Bar).id(); + let ent6 = world.spawn(Baz).id(); + + assert!(world.despawn(ent2)); + assert!(world.despawn(ent3)); + assert!(world.despawn(ent4)); + + iterate_and_count_entities(&world, &mut entity_counters); + + assert_eq!(entity_counters[&ent1], 1); + assert_eq!(entity_counters[&ent5], 1); + assert_eq!(entity_counters[&ent6], 1); + assert_eq!(entity_counters.len(), 3); + + // Despawning remaining entities and then validating the iteration + assert!(world.despawn(ent1)); + assert!(world.despawn(ent5)); + assert!(world.despawn(ent6)); + + iterate_and_count_entities(&world, &mut entity_counters); + + assert_eq!(entity_counters.len(), 0); + } }