From 5a9bc28502166a44572f9633a6cb7beb3ce6b046 Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Mon, 20 Jan 2025 16:26:08 -0500 Subject: [PATCH] Support non-Vec data structures in relations (#17447) # Objective The existing `RelationshipSourceCollection` uses `Vec` as the only possible backing for our relationships. While a reasonable choice, benchmarking use cases might reveal that a different data type is better or faster. For example: - Not all relationships require a stable ordering between the relationship sources (i.e. children). In cases where we a) have many such relations and b) don't care about the ordering between them, a hash set is likely a better datastructure than a `Vec`. - The number of children-like entities may be small on average, and a `smallvec` may be faster ## Solution - Implement `RelationshipSourceCollection` for `EntityHashSet`, our custom entity-optimized `HashSet`. -~~Implement `DoubleEndedIterator` for `EntityHashSet` to make things compile.~~ - This implementation was cursed and very surprising. - Instead, by moving the iterator type on `RelationshipSourceCollection` from an erased RPTIT to an explicit associated type we can add a trait bound on the offending methods! - Implement `RelationshipSourceCollection` for `SmallVec` ## Testing I've added a pair of new tests to make sure this pattern compiles successfully in practice! ## Migration Guide `EntityHashSet` and `EntityHashMap` are no longer re-exported in `bevy_ecs::entity` directly. If you were not using `bevy_ecs` / `bevy`'s `prelude`, you can access them through their now-public modules, `hash_set` and `hash_map` instead. ## Notes to reviewers The `EntityHashSet::Iter` type needs to be public for this impl to be allowed. I initially renamed it to something that wasn't ambiguous and re-exported it, but as @Victoronz pointed out, that was somewhat unidiomatic. In https://github.com/bevyengine/bevy/pull/17447/commits/1a8564898f1803cae4e99bbf909a40ab824fb8a0, I instead made the `entity_hash_set` public (and its `entity_hash_set`) sister public, and removed the re-export. I prefer this design (give me module docs please), but it leads to a lot of churn in this PR. Let me know which you'd prefer, and if you'd like me to split that change out into its own micro PR. --- benches/benches/bevy_ecs/world/entity_hash.rs | 2 +- .../bevy_core_pipeline/src/oit/resolve/mod.rs | 2 +- crates/bevy_ecs/Cargo.toml | 2 +- crates/bevy_ecs/src/entity/hash_map.rs | 4 + crates/bevy_ecs/src/entity/hash_set.rs | 14 ++ crates/bevy_ecs/src/entity/map_entities.rs | 6 +- crates/bevy_ecs/src/entity/mod.rs | 7 +- crates/bevy_ecs/src/entity/visit_entities.rs | 2 +- crates/bevy_ecs/src/observer/mod.rs | 2 +- crates/bevy_ecs/src/relationship/mod.rs | 12 +- .../src/relationship/relationship_query.rs | 6 + .../relationship_source_collection.rs | 143 +++++++++++++++++- crates/bevy_ecs/src/world/deferred_world.rs | 10 +- crates/bevy_ecs/src/world/entity_fetch.rs | 2 +- crates/bevy_ecs/src/world/mod.rs | 30 ++-- crates/bevy_gilrs/src/lib.rs | 2 +- crates/bevy_gltf/src/loader.rs | 2 +- .../src/directional_navigation.rs | 2 +- crates/bevy_pbr/src/cluster/mod.rs | 2 +- crates/bevy_pbr/src/components.rs | 2 +- crates/bevy_pbr/src/light/mod.rs | 2 +- .../bevy_pbr/src/meshlet/instance_manager.rs | 2 +- .../bevy_pbr/src/meshlet/resource_manager.rs | 2 +- crates/bevy_pbr/src/render/light.rs | 2 +- .../src/batching/gpu_preprocessing.rs | 2 +- crates/bevy_render/src/primitives/mod.rs | 2 +- crates/bevy_render/src/view/visibility/mod.rs | 2 +- .../bevy_render/src/view/visibility/range.rs | 2 +- crates/bevy_render/src/view/window/mod.rs | 2 +- .../bevy_render/src/view/window/screenshot.rs | 2 +- crates/bevy_scene/src/dynamic_scene.rs | 5 +- crates/bevy_scene/src/scene.rs | 2 +- crates/bevy_scene/src/scene_spawner.rs | 2 +- crates/bevy_scene/src/serde.rs | 2 +- crates/bevy_text/src/text2d.rs | 2 +- crates/bevy_ui/src/layout/mod.rs | 2 +- crates/bevy_ui/src/layout/ui_surface.rs | 2 +- crates/bevy_ui/src/render/mod.rs | 2 +- crates/bevy_ui/src/widget/text.rs | 2 +- crates/bevy_winit/src/accessibility.rs | 2 +- crates/bevy_winit/src/winit_windows.rs | 2 +- .../tools/scene_viewer/animation_plugin.rs | 4 +- 42 files changed, 237 insertions(+), 66 deletions(-) diff --git a/benches/benches/bevy_ecs/world/entity_hash.rs b/benches/benches/bevy_ecs/world/entity_hash.rs index d4ba9b6598..5e92443bf1 100644 --- a/benches/benches/bevy_ecs/world/entity_hash.rs +++ b/benches/benches/bevy_ecs/world/entity_hash.rs @@ -1,4 +1,4 @@ -use bevy_ecs::entity::{Entity, EntityHashSet}; +use bevy_ecs::entity::{hash_set::EntityHashSet, Entity}; use criterion::{BenchmarkId, Criterion, Throughput}; use rand::{Rng, SeedableRng}; use rand_chacha::ChaCha8Rng; diff --git a/crates/bevy_core_pipeline/src/oit/resolve/mod.rs b/crates/bevy_core_pipeline/src/oit/resolve/mod.rs index a0e97e0770..690f95fda3 100644 --- a/crates/bevy_core_pipeline/src/oit/resolve/mod.rs +++ b/crates/bevy_core_pipeline/src/oit/resolve/mod.rs @@ -6,7 +6,7 @@ use bevy_app::Plugin; use bevy_asset::{load_internal_asset, Handle}; use bevy_derive::Deref; use bevy_ecs::{ - entity::{EntityHashMap, EntityHashSet}, + entity::{hash_map::EntityHashMap, hash_set::EntityHashSet}, prelude::*, }; use bevy_image::BevyDefault as _; diff --git a/crates/bevy_ecs/Cargo.toml b/crates/bevy_ecs/Cargo.toml index 66d2643124..ff9b89405f 100644 --- a/crates/bevy_ecs/Cargo.toml +++ b/crates/bevy_ecs/Cargo.toml @@ -125,7 +125,7 @@ derive_more = { version = "1", default-features = false, features = [ ] } nonmax = { version = "0.5", default-features = false } arrayvec = { version = "0.7.4", default-features = false, optional = true } -smallvec = { version = "1", features = ["union"] } +smallvec = { version = "1", features = ["union", "const_generics"] } indexmap = { version = "2.5.0", default-features = false } variadics_please = { version = "1.1", default-features = false } spin = { version = "0.9.8", default-features = false, features = [ diff --git a/crates/bevy_ecs/src/entity/hash_map.rs b/crates/bevy_ecs/src/entity/hash_map.rs index 20ec6767ba..9246b23690 100644 --- a/crates/bevy_ecs/src/entity/hash_map.rs +++ b/crates/bevy_ecs/src/entity/hash_map.rs @@ -1,3 +1,7 @@ +//! Contains the [`EntityHashMap`] type, a [`HashMap`] pre-configured to use [`EntityHash`] hashing. +//! +//! This module is a lightweight wrapper around [`hashbrown`](bevy_utils::hashbrown)'s [`HashMap`] that is more performant for [`Entity`] keys. + use core::{ fmt::{self, Debug, Formatter}, iter::FusedIterator, diff --git a/crates/bevy_ecs/src/entity/hash_set.rs b/crates/bevy_ecs/src/entity/hash_set.rs index 12538d873b..6fe1f32264 100644 --- a/crates/bevy_ecs/src/entity/hash_set.rs +++ b/crates/bevy_ecs/src/entity/hash_set.rs @@ -1,3 +1,7 @@ +//! Contains the [`EntityHashSet`] type, a [`HashSet`] pre-configured to use [`EntityHash`] hashing. +//! +//! This module is a lightweight wrapper around [`hashbrown`](bevy_utils::hashbrown)'s [`HashSet`] that is more performant for [`Entity`] keys. + use core::{ fmt::{self, Debug, Formatter}, iter::FusedIterator, @@ -38,6 +42,16 @@ impl EntityHashSet { Self(HashSet::with_capacity_and_hasher(n, EntityHash)) } + /// Returns the number of elements in the set. + pub fn len(&self) -> usize { + self.0.len() + } + + /// Returns `true` if the set contains no elements. + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } + /// Returns the inner [`HashSet`]. pub fn into_inner(self) -> HashSet { self.0 diff --git a/crates/bevy_ecs/src/entity/map_entities.rs b/crates/bevy_ecs/src/entity/map_entities.rs index 5b0de2359d..688b523380 100644 --- a/crates/bevy_ecs/src/entity/map_entities.rs +++ b/crates/bevy_ecs/src/entity/map_entities.rs @@ -4,7 +4,7 @@ use crate::{ world::World, }; -use super::{EntityHashMap, VisitEntitiesMut}; +use super::{hash_map::EntityHashMap, VisitEntitiesMut}; /// Operation to map all contained [`Entity`] fields in a type to new values. /// @@ -71,7 +71,7 @@ impl MapEntities for T { /// /// ``` /// # use bevy_ecs::entity::{Entity, EntityMapper}; -/// # use bevy_ecs::entity::EntityHashMap; +/// # use bevy_ecs::entity::hash_map::EntityHashMap; /// # /// pub struct SimpleEntityMapper { /// map: EntityHashMap, @@ -194,7 +194,7 @@ impl<'m> SceneEntityMapper<'m> { #[cfg(test)] mod tests { use crate::{ - entity::{Entity, EntityHashMap, EntityMapper, SceneEntityMapper}, + entity::{hash_map::EntityHashMap, Entity, EntityMapper, SceneEntityMapper}, world::World, }; diff --git a/crates/bevy_ecs/src/entity/mod.rs b/crates/bevy_ecs/src/entity/mod.rs index fd9b4a39bf..4666ac2c9d 100644 --- a/crates/bevy_ecs/src/entity/mod.rs +++ b/crates/bevy_ecs/src/entity/mod.rs @@ -53,11 +53,8 @@ pub use visit_entities::*; mod hash; pub use hash::*; -mod hash_map; -mod hash_set; - -pub use hash_map::EntityHashMap; -pub use hash_set::EntityHashSet; +pub mod hash_map; +pub mod hash_set; use crate::{ archetype::{ArchetypeId, ArchetypeRow}, diff --git a/crates/bevy_ecs/src/entity/visit_entities.rs b/crates/bevy_ecs/src/entity/visit_entities.rs index 0896d72081..0f957ca265 100644 --- a/crates/bevy_ecs/src/entity/visit_entities.rs +++ b/crates/bevy_ecs/src/entity/visit_entities.rs @@ -58,7 +58,7 @@ impl VisitEntitiesMut for Entity { mod tests { use crate::{ self as bevy_ecs, - entity::{EntityHashMap, MapEntities, SceneEntityMapper}, + entity::{hash_map::EntityHashMap, MapEntities, SceneEntityMapper}, world::World, }; use alloc::{string::String, vec, vec::Vec}; diff --git a/crates/bevy_ecs/src/observer/mod.rs b/crates/bevy_ecs/src/observer/mod.rs index 9f147dd91b..c07aa6606d 100644 --- a/crates/bevy_ecs/src/observer/mod.rs +++ b/crates/bevy_ecs/src/observer/mod.rs @@ -9,7 +9,7 @@ pub use runner::*; use crate::{ archetype::ArchetypeFlags, component::ComponentId, - entity::EntityHashMap, + entity::hash_map::EntityHashMap, prelude::*, system::IntoObserverSystem, world::{DeferredWorld, *}, diff --git a/crates/bevy_ecs/src/relationship/mod.rs b/crates/bevy_ecs/src/relationship/mod.rs index 54105c0d73..08dac0ec51 100644 --- a/crates/bevy_ecs/src/relationship/mod.rs +++ b/crates/bevy_ecs/src/relationship/mod.rs @@ -130,12 +130,22 @@ pub trait Relationship: Component + Sized { } } +/// The iterator type for the source entities in a [`RelationshipTarget`] collection, +/// as defined in the [`RelationshipSourceCollection`] trait. +pub type SourceIter<'w, R> = + <::Collection as RelationshipSourceCollection>::SourceIter<'w>; + /// A [`Component`] containing the collection of entities that relate to this [`Entity`] via the associated `Relationship` type. /// See the [`Relationship`] documentation for more information. pub trait RelationshipTarget: Component + Sized { /// The [`Relationship`] that populates this [`RelationshipTarget`] collection. type Relationship: Relationship; /// The collection type that stores the "source" entities for this [`RelationshipTarget`] component. + /// + /// Check the list of types which implement [`RelationshipSourceCollection`] for the data structures that can be used inside of your component. + /// If you need a new collection type, you can implement the [`RelationshipSourceCollection`] trait + /// for a type you own which wraps the collection you want to use (to avoid the orphan rule), + /// or open an issue on the Bevy repository to request first-party support for your collection type. type Collection: RelationshipSourceCollection; /// Returns a reference to the stored [`RelationshipTarget::Collection`]. @@ -210,7 +220,7 @@ pub trait RelationshipTarget: Component + Sized { /// Iterates the entities stored in this collection. #[inline] - fn iter(&self) -> impl DoubleEndedIterator { + fn iter(&self) -> SourceIter<'_, Self> { self.collection().iter() } diff --git a/crates/bevy_ecs/src/relationship/relationship_query.rs b/crates/bevy_ecs/src/relationship/relationship_query.rs index f47b6c14ca..f22be81cd8 100644 --- a/crates/bevy_ecs/src/relationship/relationship_query.rs +++ b/crates/bevy_ecs/src/relationship/relationship_query.rs @@ -7,6 +7,8 @@ use crate::{ use alloc::collections::VecDeque; use smallvec::SmallVec; +use super::SourceIter; + impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { /// If the given `entity` contains the `R` [`Relationship`] component, returns the /// target entity of that relationship. @@ -59,6 +61,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { ) -> impl Iterator + 'w where ::ReadOnly: WorldQuery = &'w S>, + SourceIter<'w, S>: DoubleEndedIterator, { self.iter_descendants_depth_first(entity).filter(|entity| { self.get(*entity) @@ -114,6 +117,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter> Query<'w, 's, D, F> { ) -> DescendantDepthFirstIter<'w, 's, D, F, S> where D::ReadOnly: WorldQuery = &'w S>, + SourceIter<'w, S>: DoubleEndedIterator, { DescendantDepthFirstIter::new(self, entity) } @@ -195,6 +199,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter, S: RelationshipTarget> DescendantDepthFirstIter<'w, 's, D, F, S> where D::ReadOnly: WorldQuery = &'w S>, + SourceIter<'w, S>: DoubleEndedIterator, { /// Returns a new [`DescendantDepthFirstIter`]. pub fn new(children_query: &'w Query<'w, 's, D, F>, entity: Entity) -> Self { @@ -211,6 +216,7 @@ impl<'w, 's, D: QueryData, F: QueryFilter, S: RelationshipTarget> Iterator for DescendantDepthFirstIter<'w, 's, D, F, S> where D::ReadOnly: WorldQuery = &'w S>, + SourceIter<'w, S>: DoubleEndedIterator, { type Item = Entity; diff --git a/crates/bevy_ecs/src/relationship/relationship_source_collection.rs b/crates/bevy_ecs/src/relationship/relationship_source_collection.rs index 0158f05f4b..d9b26a720d 100644 --- a/crates/bevy_ecs/src/relationship/relationship_source_collection.rs +++ b/crates/bevy_ecs/src/relationship/relationship_source_collection.rs @@ -1,9 +1,21 @@ -use crate::entity::Entity; +use crate::entity::{hash_set::EntityHashSet, Entity}; use alloc::vec::Vec; +use smallvec::SmallVec; /// The internal [`Entity`] collection used by a [`RelationshipTarget`](crate::relationship::RelationshipTarget) component. /// This is not intended to be modified directly by users, as it could invalidate the correctness of relationships. pub trait RelationshipSourceCollection { + /// The type of iterator returned by the `iter` method. + /// + /// This is an associated type (rather than using a method that returns an opaque return-position impl trait) + /// to ensure that all methods and traits (like [`DoubleEndedIterator`]) of the underlying collection's iterator + /// are available to the user when implemented without unduly restricting the possible collections. + /// + /// The [`SourceIter`](super::SourceIter) type alias can be helpful to reduce confusion when working with this associated type. + type SourceIter<'a>: Iterator + where + Self: 'a; + /// Returns an instance with the given pre-allocated entity `capacity`. fn with_capacity(capacity: usize) -> Self; @@ -14,7 +26,7 @@ pub trait RelationshipSourceCollection { fn remove(&mut self, entity: Entity); /// Iterates all entities in the collection. - fn iter(&self) -> impl DoubleEndedIterator; + fn iter(&self) -> Self::SourceIter<'_>; /// Returns the current length of the collection. fn len(&self) -> usize; @@ -27,6 +39,8 @@ pub trait RelationshipSourceCollection { } impl RelationshipSourceCollection for Vec { + type SourceIter<'a> = core::iter::Copied>; + fn with_capacity(capacity: usize) -> Self { Vec::with_capacity(capacity) } @@ -41,7 +55,7 @@ impl RelationshipSourceCollection for Vec { } } - fn iter(&self) -> impl DoubleEndedIterator { + fn iter(&self) -> Self::SourceIter<'_> { <[Entity]>::iter(self).copied() } @@ -49,3 +63,126 @@ impl RelationshipSourceCollection for Vec { Vec::len(self) } } + +impl RelationshipSourceCollection for EntityHashSet { + type SourceIter<'a> = core::iter::Copied>; + + fn with_capacity(capacity: usize) -> Self { + EntityHashSet::with_capacity(capacity) + } + + fn add(&mut self, entity: Entity) { + self.insert(entity); + } + + fn remove(&mut self, entity: Entity) { + // We need to call the remove method on the underlying hash set, + // which takes its argument by reference + self.0.remove(&entity); + } + + fn iter(&self) -> Self::SourceIter<'_> { + self.iter().copied() + } + + fn len(&self) -> usize { + self.len() + } +} + +impl RelationshipSourceCollection for SmallVec<[Entity; N]> { + type SourceIter<'a> = core::iter::Copied>; + + fn with_capacity(capacity: usize) -> Self { + SmallVec::with_capacity(capacity) + } + + fn add(&mut self, entity: Entity) { + SmallVec::push(self, entity); + } + + fn remove(&mut self, entity: Entity) { + if let Some(index) = <[Entity]>::iter(self).position(|e| *e == entity) { + SmallVec::remove(self, index); + } + } + + fn iter(&self) -> Self::SourceIter<'_> { + <[Entity]>::iter(self).copied() + } + + fn len(&self) -> usize { + SmallVec::len(self) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate as bevy_ecs; + use crate::prelude::{Component, World}; + use crate::relationship::RelationshipTarget; + + #[test] + fn vec_relationship_source_collection() { + #[derive(Component)] + #[relationship(relationship_target = RelTarget)] + struct Rel(Entity); + + #[derive(Component)] + #[relationship_target(relationship = Rel, despawn_descendants)] + struct RelTarget(Vec); + + let mut world = World::new(); + let a = world.spawn_empty().id(); + let b = world.spawn_empty().id(); + + world.entity_mut(a).insert(Rel(b)); + + let rel_target = world.get::(b).unwrap(); + let collection = rel_target.collection(); + assert_eq!(collection, &alloc::vec!(a)); + } + + #[test] + fn entity_hash_set_relationship_source_collection() { + #[derive(Component)] + #[relationship(relationship_target = RelTarget)] + struct Rel(Entity); + + #[derive(Component)] + #[relationship_target(relationship = Rel, despawn_descendants)] + struct RelTarget(EntityHashSet); + + let mut world = World::new(); + let a = world.spawn_empty().id(); + let b = world.spawn_empty().id(); + + world.entity_mut(a).insert(Rel(b)); + + let rel_target = world.get::(b).unwrap(); + let collection = rel_target.collection(); + assert_eq!(collection, &EntityHashSet::from([a])); + } + + #[test] + fn smallvec_relationship_source_collection() { + #[derive(Component)] + #[relationship(relationship_target = RelTarget)] + struct Rel(Entity); + + #[derive(Component)] + #[relationship_target(relationship = Rel, despawn_descendants)] + struct RelTarget(SmallVec<[Entity; 4]>); + + let mut world = World::new(); + let a = world.spawn_empty().id(); + let b = world.spawn_empty().id(); + + world.entity_mut(a).insert(Rel(b)); + + let rel_target = world.get::(b).unwrap(); + let collection = rel_target.collection(); + assert_eq!(collection, &SmallVec::from_buf([a])); + } +} diff --git a/crates/bevy_ecs/src/world/deferred_world.rs b/crates/bevy_ecs/src/world/deferred_world.rs index 3564b8eae1..9a6674afe5 100644 --- a/crates/bevy_ecs/src/world/deferred_world.rs +++ b/crates/bevy_ecs/src/world/deferred_world.rs @@ -189,8 +189,8 @@ impl<'w> DeferredWorld<'w> { /// For examples, see [`DeferredWorld::entity_mut`]. /// /// [`EntityMut`]: crate::world::EntityMut - /// [`&EntityHashSet`]: crate::entity::EntityHashSet - /// [`EntityHashMap`]: crate::entity::EntityHashMap + /// [`&EntityHashSet`]: crate::entity::hash_set::EntityHashSet + /// [`EntityHashMap`]: crate::entity::hash_map::EntityHashMap /// [`Vec`]: alloc::vec::Vec #[inline] pub fn get_entity_mut( @@ -298,7 +298,7 @@ impl<'w> DeferredWorld<'w> { /// ## [`&EntityHashSet`] /// /// ``` - /// # use bevy_ecs::{prelude::*, entity::EntityHashSet, world::DeferredWorld}; + /// # use bevy_ecs::{prelude::*, entity::hash_set::EntityHashSet, world::DeferredWorld}; /// #[derive(Component)] /// struct Position { /// x: f32, @@ -321,8 +321,8 @@ impl<'w> DeferredWorld<'w> { /// ``` /// /// [`EntityMut`]: crate::world::EntityMut - /// [`&EntityHashSet`]: crate::entity::EntityHashSet - /// [`EntityHashMap`]: crate::entity::EntityHashMap + /// [`&EntityHashSet`]: crate::entity::hash_set::EntityHashSet + /// [`EntityHashMap`]: crate::entity::hash_map::EntityHashMap /// [`Vec`]: alloc::vec::Vec #[inline] pub fn entity_mut(&mut self, entities: F) -> F::DeferredMut<'_> { diff --git a/crates/bevy_ecs/src/world/entity_fetch.rs b/crates/bevy_ecs/src/world/entity_fetch.rs index 05a5c51aff..466dcc31d0 100644 --- a/crates/bevy_ecs/src/world/entity_fetch.rs +++ b/crates/bevy_ecs/src/world/entity_fetch.rs @@ -2,7 +2,7 @@ use alloc::vec::Vec; use core::mem::MaybeUninit; use crate::{ - entity::{Entity, EntityHashMap, EntityHashSet}, + entity::{hash_map::EntityHashMap, hash_set::EntityHashSet, Entity}, world::{ error::EntityFetchError, unsafe_world_cell::UnsafeWorldCell, EntityMut, EntityRef, EntityWorldMut, diff --git a/crates/bevy_ecs/src/world/mod.rs b/crates/bevy_ecs/src/world/mod.rs index 0f943ef03d..7ebd8b07f0 100644 --- a/crates/bevy_ecs/src/world/mod.rs +++ b/crates/bevy_ecs/src/world/mod.rs @@ -647,10 +647,10 @@ impl World { /// } /// ``` /// - /// ## [`EntityHashSet`](crate::entity::EntityHashMap) + /// ## [`EntityHashSet`](crate::entity::hash_map::EntityHashMap) /// /// ``` - /// # use bevy_ecs::{prelude::*, entity::EntityHashSet}; + /// # use bevy_ecs::{prelude::*, entity::hash_set::EntityHashSet}; /// #[derive(Component)] /// struct Position { /// x: f32, @@ -668,7 +668,7 @@ impl World { /// } /// ``` /// - /// [`EntityHashSet`]: crate::entity::EntityHashSet + /// [`EntityHashSet`]: crate::entity::hash_set::EntityHashSet #[inline] #[track_caller] pub fn entity(&self, entities: F) -> F::Ref<'_> { @@ -699,8 +699,8 @@ impl World { /// such as adding or removing components, or despawning the entity. /// - Pass a slice of [`Entity`]s to receive a [`Vec`]. /// - Pass an array of [`Entity`]s to receive an equally-sized array of [`EntityMut`]s. - /// - Pass a reference to a [`EntityHashSet`](crate::entity::EntityHashMap) to receive an - /// [`EntityHashMap`](crate::entity::EntityHashMap). + /// - Pass a reference to a [`EntityHashSet`](crate::entity::hash_map::EntityHashMap) to receive an + /// [`EntityHashMap`](crate::entity::hash_map::EntityHashMap). /// /// In order to perform structural changes on the returned entity reference, /// such as adding or removing components, or despawning the entity, only a @@ -781,10 +781,10 @@ impl World { /// } /// ``` /// - /// ## [`EntityHashSet`](crate::entity::EntityHashMap) + /// ## [`EntityHashSet`](crate::entity::hash_map::EntityHashMap) /// /// ``` - /// # use bevy_ecs::{prelude::*, entity::EntityHashSet}; + /// # use bevy_ecs::{prelude::*, entity::hash_set::EntityHashSet}; /// #[derive(Component)] /// struct Position { /// x: f32, @@ -804,7 +804,7 @@ impl World { /// } /// ``` /// - /// [`EntityHashSet`]: crate::entity::EntityHashSet + /// [`EntityHashSet`]: crate::entity::hash_set::EntityHashSet #[inline] #[track_caller] pub fn entity_mut(&mut self, entities: F) -> F::Mut<'_> { @@ -853,8 +853,8 @@ impl World { /// - Pass an [`Entity`] to receive a single [`EntityRef`]. /// - Pass a slice of [`Entity`]s to receive a [`Vec`]. /// - Pass an array of [`Entity`]s to receive an equally-sized array of [`EntityRef`]s. - /// - Pass a reference to a [`EntityHashSet`](crate::entity::EntityHashMap) to receive an - /// [`EntityHashMap`](crate::entity::EntityHashMap). + /// - Pass a reference to a [`EntityHashSet`](crate::entity::hash_map::EntityHashMap) to receive an + /// [`EntityHashMap`](crate::entity::hash_map::EntityHashMap). /// /// # Errors /// @@ -865,7 +865,7 @@ impl World { /// /// For examples, see [`World::entity`]. /// - /// [`EntityHashSet`]: crate::entity::EntityHashSet + /// [`EntityHashSet`]: crate::entity::hash_set::EntityHashSet #[inline] pub fn get_entity(&self, entities: F) -> Result, Entity> { let cell = self.as_unsafe_world_cell_readonly(); @@ -884,8 +884,8 @@ impl World { /// such as adding or removing components, or despawning the entity. /// - Pass a slice of [`Entity`]s to receive a [`Vec`]. /// - Pass an array of [`Entity`]s to receive an equally-sized array of [`EntityMut`]s. - /// - Pass a reference to a [`EntityHashSet`](crate::entity::EntityHashMap) to receive an - /// [`EntityHashMap`](crate::entity::EntityHashMap). + /// - Pass a reference to a [`EntityHashSet`](crate::entity::hash_map::EntityHashMap) to receive an + /// [`EntityHashMap`](crate::entity::hash_map::EntityHashMap). /// /// In order to perform structural changes on the returned entity reference, /// such as adding or removing components, or despawning the entity, only a @@ -903,7 +903,7 @@ impl World { /// /// For examples, see [`World::entity_mut`]. /// - /// [`EntityHashSet`]: crate::entity::EntityHashSet + /// [`EntityHashSet`]: crate::entity::hash_set::EntityHashSet #[inline] pub fn get_entity_mut( &mut self, @@ -3696,7 +3696,7 @@ mod tests { use crate::{ change_detection::DetectChangesMut, component::{ComponentDescriptor, ComponentInfo, StorageType}, - entity::EntityHashSet, + entity::hash_set::EntityHashSet, ptr::OwningPtr, system::Resource, world::error::EntityFetchError, diff --git a/crates/bevy_gilrs/src/lib.rs b/crates/bevy_gilrs/src/lib.rs index b8d83adbf3..404b6894ac 100644 --- a/crates/bevy_gilrs/src/lib.rs +++ b/crates/bevy_gilrs/src/lib.rs @@ -15,7 +15,7 @@ mod gilrs_system; mod rumble; use bevy_app::{App, Plugin, PostUpdate, PreStartup, PreUpdate}; -use bevy_ecs::entity::EntityHashMap; +use bevy_ecs::entity::hash_map::EntityHashMap; use bevy_ecs::prelude::*; use bevy_input::InputSystem; use bevy_utils::{synccell::SyncCell, HashMap}; diff --git a/crates/bevy_gltf/src/loader.rs b/crates/bevy_gltf/src/loader.rs index 5b9810d184..487515a6d9 100644 --- a/crates/bevy_gltf/src/loader.rs +++ b/crates/bevy_gltf/src/loader.rs @@ -10,7 +10,7 @@ use bevy_asset::{ use bevy_color::{Color, LinearRgba}; use bevy_core_pipeline::prelude::Camera3d; use bevy_ecs::{ - entity::{Entity, EntityHashMap}, + entity::{hash_map::EntityHashMap, Entity}, hierarchy::ChildSpawner, name::Name, world::World, diff --git a/crates/bevy_input_focus/src/directional_navigation.rs b/crates/bevy_input_focus/src/directional_navigation.rs index fd64cd41a7..c6428c444b 100644 --- a/crates/bevy_input_focus/src/directional_navigation.rs +++ b/crates/bevy_input_focus/src/directional_navigation.rs @@ -17,7 +17,7 @@ use bevy_app::prelude::*; use bevy_ecs::{ - entity::{EntityHashMap, EntityHashSet}, + entity::{hash_map::EntityHashMap, hash_set::EntityHashSet}, prelude::*, system::SystemParam, }; diff --git a/crates/bevy_pbr/src/cluster/mod.rs b/crates/bevy_pbr/src/cluster/mod.rs index eb7834871b..6a2baa554a 100644 --- a/crates/bevy_pbr/src/cluster/mod.rs +++ b/crates/bevy_pbr/src/cluster/mod.rs @@ -5,7 +5,7 @@ use core::num::NonZero; use bevy_core_pipeline::core_3d::Camera3d; use bevy_ecs::{ component::Component, - entity::{Entity, EntityHashMap}, + entity::{hash_map::EntityHashMap, Entity}, query::{With, Without}, reflect::ReflectComponent, system::{Commands, Query, Res, Resource}, diff --git a/crates/bevy_pbr/src/components.rs b/crates/bevy_pbr/src/components.rs index 189862cc55..d5418910eb 100644 --- a/crates/bevy_pbr/src/components.rs +++ b/crates/bevy_pbr/src/components.rs @@ -1,6 +1,6 @@ use bevy_derive::{Deref, DerefMut}; use bevy_ecs::component::Component; -use bevy_ecs::entity::{Entity, EntityHashMap}; +use bevy_ecs::entity::{hash_map::EntityHashMap, Entity}; use bevy_ecs::reflect::ReflectComponent; use bevy_reflect::{std_traits::ReflectDefault, Reflect}; use bevy_render::sync_world::MainEntity; diff --git a/crates/bevy_pbr/src/light/mod.rs b/crates/bevy_pbr/src/light/mod.rs index 5525029ef4..00d60993c4 100644 --- a/crates/bevy_pbr/src/light/mod.rs +++ b/crates/bevy_pbr/src/light/mod.rs @@ -1,7 +1,7 @@ use core::ops::DerefMut; use bevy_ecs::{ - entity::{EntityHashMap, EntityHashSet}, + entity::{hash_map::EntityHashMap, hash_set::EntityHashSet}, prelude::*, }; use bevy_math::{ops, Mat4, Vec3A, Vec4}; diff --git a/crates/bevy_pbr/src/meshlet/instance_manager.rs b/crates/bevy_pbr/src/meshlet/instance_manager.rs index 7a78abe482..e87f100f8a 100644 --- a/crates/bevy_pbr/src/meshlet/instance_manager.rs +++ b/crates/bevy_pbr/src/meshlet/instance_manager.rs @@ -5,7 +5,7 @@ use crate::{ }; use bevy_asset::{AssetEvent, AssetServer, Assets, UntypedAssetId}; use bevy_ecs::{ - entity::{Entities, Entity, EntityHashMap}, + entity::{hash_map::EntityHashMap, Entities, Entity}, event::EventReader, query::Has, system::{Local, Query, Res, ResMut, Resource, SystemState}, diff --git a/crates/bevy_pbr/src/meshlet/resource_manager.rs b/crates/bevy_pbr/src/meshlet/resource_manager.rs index c918990869..05c7e52249 100644 --- a/crates/bevy_pbr/src/meshlet/resource_manager.rs +++ b/crates/bevy_pbr/src/meshlet/resource_manager.rs @@ -7,7 +7,7 @@ use bevy_core_pipeline::{ }; use bevy_ecs::{ component::Component, - entity::{Entity, EntityHashMap}, + entity::{hash_map::EntityHashMap, Entity}, query::AnyOf, system::{Commands, Query, Res, ResMut, Resource}, }; diff --git a/crates/bevy_pbr/src/render/light.rs b/crates/bevy_pbr/src/render/light.rs index 4a1187400e..63fca28aed 100644 --- a/crates/bevy_pbr/src/render/light.rs +++ b/crates/bevy_pbr/src/render/light.rs @@ -6,7 +6,7 @@ use bevy_color::ColorToComponents; use bevy_core_pipeline::core_3d::{Camera3d, CORE_3D_DEPTH_FORMAT}; use bevy_derive::{Deref, DerefMut}; use bevy_ecs::{ - entity::{EntityHashMap, EntityHashSet}, + entity::{hash_map::EntityHashMap, hash_set::EntityHashSet}, prelude::*, system::lifetimeless::Read, }; diff --git a/crates/bevy_render/src/batching/gpu_preprocessing.rs b/crates/bevy_render/src/batching/gpu_preprocessing.rs index 2e893616f9..d9cfbbf334 100644 --- a/crates/bevy_render/src/batching/gpu_preprocessing.rs +++ b/crates/bevy_render/src/batching/gpu_preprocessing.rs @@ -4,7 +4,7 @@ use core::any::TypeId; use bevy_app::{App, Plugin}; use bevy_ecs::{ - entity::{Entity, EntityHashMap}, + entity::{hash_map::EntityHashMap, Entity}, query::{Has, With}, schedule::IntoSystemConfigs as _, system::{Query, Res, ResMut, Resource, StaticSystemParam}, diff --git a/crates/bevy_render/src/primitives/mod.rs b/crates/bevy_render/src/primitives/mod.rs index 48c0652fef..9123e95b5e 100644 --- a/crates/bevy_render/src/primitives/mod.rs +++ b/crates/bevy_render/src/primitives/mod.rs @@ -1,6 +1,6 @@ use core::borrow::Borrow; -use bevy_ecs::{component::Component, entity::EntityHashMap, reflect::ReflectComponent}; +use bevy_ecs::{component::Component, entity::hash_map::EntityHashMap, reflect::ReflectComponent}; use bevy_math::{Affine3A, Mat3A, Mat4, Vec3, Vec3A, Vec4, Vec4Swizzles}; use bevy_reflect::prelude::*; diff --git a/crates/bevy_render/src/view/visibility/mod.rs b/crates/bevy_render/src/view/visibility/mod.rs index d0c84bd70a..0e329deefd 100644 --- a/crates/bevy_render/src/view/visibility/mod.rs +++ b/crates/bevy_render/src/view/visibility/mod.rs @@ -4,7 +4,7 @@ mod render_layers; use core::any::TypeId; use bevy_ecs::component::ComponentId; -use bevy_ecs::entity::EntityHashSet; +use bevy_ecs::entity::hash_set::EntityHashSet; use bevy_ecs::world::DeferredWorld; use derive_more::derive::{Deref, DerefMut}; pub use range::*; diff --git a/crates/bevy_render/src/view/visibility/range.rs b/crates/bevy_render/src/view/visibility/range.rs index d62a9ffb69..e6f6484d05 100644 --- a/crates/bevy_render/src/view/visibility/range.rs +++ b/crates/bevy_render/src/view/visibility/range.rs @@ -9,7 +9,7 @@ use core::{ use bevy_app::{App, Plugin, PostUpdate}; use bevy_ecs::{ component::Component, - entity::{Entity, EntityHashMap}, + entity::{hash_map::EntityHashMap, Entity}, query::{Changed, With}, reflect::ReflectComponent, removal_detection::RemovedComponents, diff --git a/crates/bevy_render/src/view/window/mod.rs b/crates/bevy_render/src/view/window/mod.rs index e6c257e4a6..87d5654e7b 100644 --- a/crates/bevy_render/src/view/window/mod.rs +++ b/crates/bevy_render/src/view/window/mod.rs @@ -4,7 +4,7 @@ use crate::{ Extract, ExtractSchedule, Render, RenderApp, RenderSet, WgpuWrapper, }; use bevy_app::{App, Plugin}; -use bevy_ecs::{entity::EntityHashMap, prelude::*}; +use bevy_ecs::{entity::hash_map::EntityHashMap, prelude::*}; use bevy_utils::{default, HashSet}; use bevy_window::{ CompositeAlphaMode, PresentMode, PrimaryWindow, RawHandleWrapper, Window, WindowClosing, diff --git a/crates/bevy_render/src/view/window/screenshot.rs b/crates/bevy_render/src/view/window/screenshot.rs index 81adc30486..574153e694 100644 --- a/crates/bevy_render/src/view/window/screenshot.rs +++ b/crates/bevy_render/src/view/window/screenshot.rs @@ -20,7 +20,7 @@ use bevy_app::{First, Plugin, Update}; use bevy_asset::{load_internal_asset, Handle}; use bevy_derive::{Deref, DerefMut}; use bevy_ecs::{ - entity::EntityHashMap, event::event_update_system, prelude::*, system::SystemState, + entity::hash_map::EntityHashMap, event::event_update_system, prelude::*, system::SystemState, }; use bevy_image::{Image, TextureFormatPixelInfo}; use bevy_reflect::Reflect; diff --git a/crates/bevy_scene/src/dynamic_scene.rs b/crates/bevy_scene/src/dynamic_scene.rs index f8adb6d070..2c16693a54 100644 --- a/crates/bevy_scene/src/dynamic_scene.rs +++ b/crates/bevy_scene/src/dynamic_scene.rs @@ -2,7 +2,7 @@ use crate::{ron, DynamicSceneBuilder, Scene, SceneSpawnError}; use bevy_asset::Asset; use bevy_ecs::reflect::ReflectResource; use bevy_ecs::{ - entity::{Entity, EntityHashMap, SceneEntityMapper}, + entity::{hash_map::EntityHashMap, Entity, SceneEntityMapper}, reflect::{AppTypeRegistry, ReflectComponent, ReflectMapEntities}, world::World, }; @@ -200,7 +200,8 @@ mod tests { use bevy_ecs::{ component::Component, entity::{ - Entity, EntityHashMap, EntityMapper, MapEntities, VisitEntities, VisitEntitiesMut, + hash_map::EntityHashMap, Entity, EntityMapper, MapEntities, VisitEntities, + VisitEntitiesMut, }, hierarchy::Parent, reflect::{AppTypeRegistry, ReflectComponent, ReflectMapEntities, ReflectResource}, diff --git a/crates/bevy_scene/src/scene.rs b/crates/bevy_scene/src/scene.rs index aba8a55d46..232acf3456 100644 --- a/crates/bevy_scene/src/scene.rs +++ b/crates/bevy_scene/src/scene.rs @@ -1,7 +1,7 @@ use crate::{DynamicScene, SceneSpawnError}; use bevy_asset::Asset; use bevy_ecs::{ - entity::{Entity, EntityHashMap, SceneEntityMapper}, + entity::{hash_map::EntityHashMap, Entity, SceneEntityMapper}, reflect::{AppTypeRegistry, ReflectComponent, ReflectMapEntities, ReflectResource}, world::World, }; diff --git a/crates/bevy_scene/src/scene_spawner.rs b/crates/bevy_scene/src/scene_spawner.rs index 9d3c99996d..038f114432 100644 --- a/crates/bevy_scene/src/scene_spawner.rs +++ b/crates/bevy_scene/src/scene_spawner.rs @@ -1,7 +1,7 @@ use crate::{DynamicScene, Scene}; use bevy_asset::{AssetEvent, AssetId, Assets, Handle}; use bevy_ecs::{ - entity::{Entity, EntityHashMap}, + entity::{hash_map::EntityHashMap, Entity}, event::{Event, EventCursor, Events}, hierarchy::Parent, reflect::AppTypeRegistry, diff --git a/crates/bevy_scene/src/serde.rs b/crates/bevy_scene/src/serde.rs index a59fa67692..d1fc5a89d3 100644 --- a/crates/bevy_scene/src/serde.rs +++ b/crates/bevy_scene/src/serde.rs @@ -515,7 +515,7 @@ mod tests { DynamicScene, DynamicSceneBuilder, }; use bevy_ecs::{ - entity::{Entity, EntityHashMap, VisitEntities, VisitEntitiesMut}, + entity::{hash_map::EntityHashMap, Entity, VisitEntities, VisitEntitiesMut}, prelude::{Component, ReflectComponent, ReflectResource, Resource, World}, query::{With, Without}, reflect::{AppTypeRegistry, ReflectMapEntities}, diff --git a/crates/bevy_text/src/text2d.rs b/crates/bevy_text/src/text2d.rs index 41979af4da..31c1ad76e3 100644 --- a/crates/bevy_text/src/text2d.rs +++ b/crates/bevy_text/src/text2d.rs @@ -7,7 +7,7 @@ use crate::{ use bevy_asset::Assets; use bevy_color::LinearRgba; use bevy_derive::{Deref, DerefMut}; -use bevy_ecs::entity::EntityHashSet; +use bevy_ecs::entity::hash_set::EntityHashSet; use bevy_ecs::{ change_detection::{DetectChanges, Ref}, component::{require, Component}, diff --git a/crates/bevy_ui/src/layout/mod.rs b/crates/bevy_ui/src/layout/mod.rs index f80d86cb4c..6d017592c7 100644 --- a/crates/bevy_ui/src/layout/mod.rs +++ b/crates/bevy_ui/src/layout/mod.rs @@ -4,7 +4,7 @@ use crate::{ OverflowAxis, ScrollPosition, UiScale, UiTargetCamera, Val, }; use bevy_ecs::{ - entity::{EntityHashMap, EntityHashSet}, + entity::{hash_map::EntityHashMap, hash_set::EntityHashSet}, prelude::*, system::SystemParam, }; diff --git a/crates/bevy_ui/src/layout/ui_surface.rs b/crates/bevy_ui/src/layout/ui_surface.rs index b57d1041a3..9dac92f597 100644 --- a/crates/bevy_ui/src/layout/ui_surface.rs +++ b/crates/bevy_ui/src/layout/ui_surface.rs @@ -3,7 +3,7 @@ use core::fmt; use taffy::TaffyTree; use bevy_ecs::{ - entity::{Entity, EntityHashMap}, + entity::{hash_map::EntityHashMap, Entity}, prelude::Resource, }; use bevy_math::{UVec2, Vec2}; diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index fded21965e..9992761971 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -18,7 +18,7 @@ use bevy_color::{Alpha, ColorToComponents, LinearRgba}; use bevy_core_pipeline::core_2d::graph::{Core2d, Node2d}; use bevy_core_pipeline::core_3d::graph::{Core3d, Node3d}; use bevy_core_pipeline::{core_2d::Camera2d, core_3d::Camera3d}; -use bevy_ecs::entity::EntityHashMap; +use bevy_ecs::entity::hash_map::EntityHashMap; use bevy_ecs::prelude::*; use bevy_image::prelude::*; use bevy_math::{FloatOrd, Mat4, Rect, UVec4, Vec2, Vec3, Vec3Swizzles, Vec4Swizzles}; diff --git a/crates/bevy_ui/src/widget/text.rs b/crates/bevy_ui/src/widget/text.rs index 237d7abfb2..1f0dcc6541 100644 --- a/crates/bevy_ui/src/widget/text.rs +++ b/crates/bevy_ui/src/widget/text.rs @@ -7,7 +7,7 @@ use bevy_color::Color; use bevy_derive::{Deref, DerefMut}; use bevy_ecs::{ change_detection::DetectChanges, - entity::{Entity, EntityHashMap}, + entity::{hash_map::EntityHashMap, Entity}, prelude::{require, Component}, query::With, reflect::ReflectComponent, diff --git a/crates/bevy_winit/src/accessibility.rs b/crates/bevy_winit/src/accessibility.rs index 939916f6eb..c6955bd21d 100644 --- a/crates/bevy_winit/src/accessibility.rs +++ b/crates/bevy_winit/src/accessibility.rs @@ -15,7 +15,7 @@ use bevy_a11y::{ }; use bevy_app::{App, Plugin, PostUpdate}; use bevy_derive::{Deref, DerefMut}; -use bevy_ecs::{entity::EntityHashMap, prelude::*}; +use bevy_ecs::{entity::hash_map::EntityHashMap, prelude::*}; use bevy_window::{PrimaryWindow, Window, WindowClosed}; /// Maps window entities to their `AccessKit` [`Adapter`]s. diff --git a/crates/bevy_winit/src/winit_windows.rs b/crates/bevy_winit/src/winit_windows.rs index f7b948a6bd..9f7896d4c7 100644 --- a/crates/bevy_winit/src/winit_windows.rs +++ b/crates/bevy_winit/src/winit_windows.rs @@ -1,7 +1,7 @@ use bevy_a11y::AccessibilityRequested; use bevy_ecs::entity::Entity; -use bevy_ecs::entity::EntityHashMap; +use bevy_ecs::entity::hash_map::EntityHashMap; use bevy_utils::HashMap; use bevy_window::{ CursorGrabMode, MonitorSelection, Window, WindowMode, WindowPosition, WindowResolution, diff --git a/examples/tools/scene_viewer/animation_plugin.rs b/examples/tools/scene_viewer/animation_plugin.rs index 7438392739..298a10199f 100644 --- a/examples/tools/scene_viewer/animation_plugin.rs +++ b/examples/tools/scene_viewer/animation_plugin.rs @@ -1,7 +1,9 @@ //! Control animations of entities in the loaded scene. use std::collections::HashMap; -use bevy::{animation::AnimationTarget, ecs::entity::EntityHashMap, gltf::Gltf, prelude::*}; +use bevy::{ + animation::AnimationTarget, ecs::entity::hash_map::EntityHashMap, gltf::Gltf, prelude::*, +}; use crate::scene_viewer_plugin::SceneHandle;