From 1c67e020f77e575ee1561b3f274921b981af29f8 Mon Sep 17 00:00:00 2001 From: Doonv <58695417+doonv@users.noreply.github.com> Date: Mon, 12 Feb 2024 17:02:24 +0200 Subject: [PATCH] Move `EntityHash` related types into `bevy_ecs` (#11498) # Objective Reduce the size of `bevy_utils` (https://github.com/bevyengine/bevy/issues/11478) ## Solution Move `EntityHash` related types into `bevy_ecs`. This also allows us access to `Entity`, which means we no longer need `EntityHashMap`'s first generic argument. --- ## Changelog - Moved `bevy::utils::{EntityHash, EntityHasher, EntityHashMap, EntityHashSet}` into `bevy::ecs::entity::hash` . - Removed `EntityHashMap`'s first generic argument. It is now hardcoded to always be `Entity`. ## Migration Guide - Uses of `bevy::utils::{EntityHash, EntityHasher, EntityHashMap, EntityHashSet}` now have to be imported from `bevy::ecs::entity::hash`. - Uses of `EntityHashMap` no longer have to specify the first generic parameter. It is now hardcoded to always be `Entity`. --- benches/Cargo.toml | 4 +- .../world}/entity_hash.rs | 5 +- benches/benches/bevy_ecs/world/mod.rs | 11 +- crates/bevy_ecs/Cargo.toml | 1 + crates/bevy_ecs/src/entity/hash.rs | 99 +++++++++++ crates/bevy_ecs/src/entity/map_entities.rs | 35 ++-- crates/bevy_ecs/src/entity/mod.rs | 19 ++- crates/bevy_ecs/src/reflect/map_entities.rs | 21 +-- crates/bevy_ecs/src/reflect/mod.rs | 6 +- crates/bevy_gltf/src/loader.rs | 5 +- crates/bevy_pbr/src/bundle.rs | 6 +- crates/bevy_pbr/src/light.rs | 5 +- crates/bevy_pbr/src/light_probe/mod.rs | 1 + crates/bevy_pbr/src/lightmap/mod.rs | 5 +- crates/bevy_pbr/src/render/light.rs | 8 +- crates/bevy_pbr/src/render/mesh.rs | 5 +- crates/bevy_pbr/src/render/morph.rs | 4 +- crates/bevy_pbr/src/render/skin.rs | 4 +- crates/bevy_reflect/src/impls/std.rs | 6 +- crates/bevy_render/src/extract_instances.rs | 4 +- crates/bevy_render/src/primitives/mod.rs | 5 +- crates/bevy_render/src/view/window/mod.rs | 10 +- .../bevy_render/src/view/window/screenshot.rs | 5 +- crates/bevy_scene/src/dynamic_scene.rs | 9 +- crates/bevy_scene/src/scene.rs | 2 +- crates/bevy_scene/src/scene_spawner.rs | 7 +- crates/bevy_scene/src/serde.rs | 2 +- crates/bevy_sprite/src/mesh2d/material.rs | 5 +- crates/bevy_sprite/src/mesh2d/mesh.rs | 4 +- crates/bevy_sprite/src/render/mod.rs | 5 +- crates/bevy_ui/src/layout/mod.rs | 9 +- crates/bevy_ui/src/render/mod.rs | 5 +- crates/bevy_utils/src/lib.rs | 158 +++++------------- crates/bevy_winit/src/accessibility.rs | 6 +- crates/bevy_winit/src/winit_windows.rs | 5 +- 35 files changed, 262 insertions(+), 229 deletions(-) rename benches/benches/{bevy_utils => bevy_ecs/world}/entity_hash.rs (96%) create mode 100644 crates/bevy_ecs/src/entity/hash.rs diff --git a/benches/Cargo.toml b/benches/Cargo.toml index 7afdde7e2001e..e64a79d2b389a 100644 --- a/benches/Cargo.toml +++ b/benches/Cargo.toml @@ -63,6 +63,6 @@ path = "benches/bevy_math/bezier.rs" harness = false [[bench]] -name = "utils" -path = "benches/bevy_utils/entity_hash.rs" +name = "entity_hash" +path = "benches/bevy_ecs/world/entity_hash.rs" harness = false diff --git a/benches/benches/bevy_utils/entity_hash.rs b/benches/benches/bevy_ecs/world/entity_hash.rs similarity index 96% rename from benches/benches/bevy_utils/entity_hash.rs rename to benches/benches/bevy_ecs/world/entity_hash.rs index 44cf80ba9a4ec..03faf268330ca 100644 --- a/benches/benches/bevy_utils/entity_hash.rs +++ b/benches/benches/bevy_ecs/world/entity_hash.rs @@ -1,5 +1,4 @@ -use bevy_ecs::entity::Entity; -use bevy_utils::EntityHashSet; +use bevy_ecs::entity::{Entity, EntityHashMap, EntityHashSet}; use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion, Throughput}; use rand::{Rng, SeedableRng}; use rand_chacha::ChaCha8Rng; @@ -28,7 +27,7 @@ fn make_entity(rng: &mut impl Rng, size: usize) -> Entity { e } -fn entity_set_build_and_lookup(c: &mut Criterion) { +pub fn entity_set_build_and_lookup(c: &mut Criterion) { let mut group = c.benchmark_group("entity_hash"); for size in SIZES { // Get some random-but-consistent entities to use for all the benches below. diff --git a/benches/benches/bevy_ecs/world/mod.rs b/benches/benches/bevy_ecs/world/mod.rs index f594d082d7fb0..421f7a06ad239 100644 --- a/benches/benches/bevy_ecs/world/mod.rs +++ b/benches/benches/bevy_ecs/world/mod.rs @@ -1,13 +1,17 @@ use criterion::criterion_group; mod commands; -mod spawn; -mod world_get; - use commands::*; + +mod spawn; use spawn::*; + +mod world_get; use world_get::*; +mod entity_hash; +use entity_hash::*; + criterion_group!( world_benches, empty_commands, @@ -30,4 +34,5 @@ criterion_group!( query_get_many::<2>, query_get_many::<5>, query_get_many::<10>, + entity_set_build_and_lookup ); diff --git a/crates/bevy_ecs/Cargo.toml b/crates/bevy_ecs/Cargo.toml index 2239d1648e922..c707e90ef0ba8 100644 --- a/crates/bevy_ecs/Cargo.toml +++ b/crates/bevy_ecs/Cargo.toml @@ -32,6 +32,7 @@ thiserror = "1.0" [dev-dependencies] rand = "0.8" +static_assertions = "1.1.0" [[example]] name = "events" diff --git a/crates/bevy_ecs/src/entity/hash.rs b/crates/bevy_ecs/src/entity/hash.rs new file mode 100644 index 0000000000000..b3de84e52d264 --- /dev/null +++ b/crates/bevy_ecs/src/entity/hash.rs @@ -0,0 +1,99 @@ +use std::hash::{BuildHasher, Hasher}; + +#[cfg(feature = "bevy_reflect")] +use bevy_reflect::Reflect; +use bevy_utils::hashbrown; + +use super::Entity; + +/// A [`BuildHasher`] that results in a [`EntityHasher`]. +#[derive(Default, Clone)] +#[cfg_attr(feature = "bevy_reflect", derive(Reflect))] +pub struct EntityHash; + +impl BuildHasher for EntityHash { + type Hasher = EntityHasher; + + fn build_hasher(&self) -> Self::Hasher { + Self::Hasher::default() + } +} + +/// A very fast hash that is only designed to work on generational indices +/// like [`Entity`]. It will panic if attempting to hash a type containing +/// non-u64 fields. +/// +/// This is heavily optimized for typical cases, where you have mostly live +/// entities, and works particularly well for contiguous indices. +/// +/// If you have an unusual case -- say all your indices are multiples of 256 +/// or most of the entities are dead generations -- then you might want also to +/// try [`AHasher`](bevy_utils::AHasher) for a slower hash computation but fewer lookup conflicts. +#[derive(Debug, Default)] +pub struct EntityHasher { + hash: u64, +} + +impl Hasher for EntityHasher { + #[inline] + fn finish(&self) -> u64 { + self.hash + } + + fn write(&mut self, _bytes: &[u8]) { + panic!("EntityHasher can only hash u64 fields."); + } + + #[inline] + fn write_u64(&mut self, bits: u64) { + // SwissTable (and thus `hashbrown`) cares about two things from the hash: + // - H1: low bits (masked by `2ⁿ-1`) to pick the slot in which to store the item + // - H2: high 7 bits are used to SIMD optimize hash collision probing + // For more see + + // This hash function assumes that the entity ids are still well-distributed, + // so for H1 leaves the entity id alone in the low bits so that id locality + // will also give memory locality for things spawned together. + // For H2, take advantage of the fact that while multiplication doesn't + // spread entropy to the low bits, it's incredibly good at spreading it + // upward, which is exactly where we need it the most. + + // While this does include the generation in the output, it doesn't do so + // *usefully*. H1 won't care until you have over 3 billion entities in + // the table, and H2 won't care until something hits generation 33 million. + // Thus the comment suggesting that this is best for live entities, + // where there won't be generation conflicts where it would matter. + + // The high 32 bits of this are ⅟φ for Fibonacci hashing. That works + // particularly well for hashing for the same reason as described in + // + // It loses no information because it has a modular inverse. + // (Specifically, `0x144c_bc89_u32 * 0x9e37_79b9_u32 == 1`.) + // + // The low 32 bits make that part of the just product a pass-through. + const UPPER_PHI: u64 = 0x9e37_79b9_0000_0001; + + // This is `(MAGIC * index + generation) << 32 + index`, in a single instruction. + self.hash = bits.wrapping_mul(UPPER_PHI); + } +} + +/// A [`HashMap`](hashbrown::HashMap) pre-configured to use [`EntityHash`] hashing. +pub type EntityHashMap = hashbrown::HashMap; + +/// A [`HashSet`](hashbrown::HashSet) pre-configured to use [`EntityHash`] hashing. +pub type EntityHashSet = hashbrown::HashSet; + +#[cfg(test)] +mod tests { + use super::*; + #[cfg(feature = "bevy_reflect")] + use bevy_reflect::Reflect; + use static_assertions::assert_impl_all; + + // Check that the HashMaps are Clone if the key/values are Clone + assert_impl_all!(EntityHashMap::: Clone); + // EntityHashMap should implement Reflect + #[cfg(feature = "bevy_reflect")] + assert_impl_all!(EntityHashMap::: Reflect); +} diff --git a/crates/bevy_ecs/src/entity/map_entities.rs b/crates/bevy_ecs/src/entity/map_entities.rs index 59949c1603615..1b8a2943707dc 100644 --- a/crates/bevy_ecs/src/entity/map_entities.rs +++ b/crates/bevy_ecs/src/entity/map_entities.rs @@ -3,7 +3,8 @@ use crate::{ identifier::masks::{IdentifierMask, HIGH_MASK}, world::World, }; -use bevy_utils::EntityHashMap; + +use super::EntityHashMap; /// Operation to map all contained [`Entity`] fields in a type to new values. /// @@ -11,7 +12,7 @@ use bevy_utils::EntityHashMap; /// as references in components copied from another world will be invalid. This trait /// allows defining custom mappings for these references via [`EntityMappers`](EntityMapper), which /// inject the entity mapping strategy between your `MapEntities` type and the current world -/// (usually by using an [`EntityHashMap`] between source entities and entities in the +/// (usually by using an [`EntityHashMap`] between source entities and entities in the /// current world). /// /// Implementing this trait correctly is required for properly loading components @@ -47,7 +48,7 @@ pub trait MapEntities { /// An implementor of this trait knows how to map an [`Entity`] into another [`Entity`]. /// -/// Usually this is done by using an [`EntityHashMap`] to map source entities +/// Usually this is done by using an [`EntityHashMap`] to map source entities /// (mapper inputs) to the current world's entities (mapper outputs). /// /// More generally, this can be used to map [`Entity`] references between any two [`Worlds`](World). @@ -56,10 +57,10 @@ pub trait MapEntities { /// /// ``` /// # use bevy_ecs::entity::{Entity, EntityMapper}; -/// # use bevy_utils::EntityHashMap; +/// # use bevy_ecs::entity::EntityHashMap; /// # /// pub struct SimpleEntityMapper { -/// map: EntityHashMap, +/// map: EntityHashMap, /// } /// /// // Example implementation of EntityMapper where we map an entity to another entity if it exists @@ -97,7 +98,7 @@ impl EntityMapper for SceneEntityMapper<'_> { } } -/// A wrapper for [`EntityHashMap`], augmenting it with the ability to allocate new [`Entity`] references in a destination +/// A wrapper for [`EntityHashMap`], augmenting it with the ability to allocate new [`Entity`] references in a destination /// world. These newly allocated references are guaranteed to never point to any living entity in that world. /// /// References are allocated by returning increasing generations starting from an internally initialized base @@ -110,9 +111,9 @@ pub struct SceneEntityMapper<'m> { /// or over the network. This is required as [`Entity`] identifiers are opaque; you cannot and do not want to reuse /// identifiers directly. /// - /// On its own, a [`EntityHashMap`] is not capable of allocating new entity identifiers, which is needed to map references + /// On its own, a [`EntityHashMap`] is not capable of allocating new entity identifiers, which is needed to map references /// to entities that lie outside the source entity set. This functionality can be accessed through [`SceneEntityMapper::world_scope()`]. - map: &'m mut EntityHashMap, + map: &'m mut EntityHashMap, /// A base [`Entity`] used to allocate new references. dead_start: Entity, /// The number of generations this mapper has allocated thus far. @@ -129,18 +130,18 @@ impl<'m> SceneEntityMapper<'m> { self.map_entity(entity) } - /// Gets a reference to the underlying [`EntityHashMap`]. - pub fn get_map(&'m self) -> &'m EntityHashMap { + /// Gets a reference to the underlying [`EntityHashMap`]. + pub fn get_map(&'m self) -> &'m EntityHashMap { self.map } - /// Gets a mutable reference to the underlying [`EntityHashMap`]. - pub fn get_map_mut(&'m mut self) -> &'m mut EntityHashMap { + /// Gets a mutable reference to the underlying [`EntityHashMap`]. + pub fn get_map_mut(&'m mut self) -> &'m mut EntityHashMap { self.map } /// Creates a new [`SceneEntityMapper`], spawning a temporary base [`Entity`] in the provided [`World`] - fn new(map: &'m mut EntityHashMap, world: &mut World) -> Self { + fn new(map: &'m mut EntityHashMap, world: &mut World) -> Self { Self { map, // SAFETY: Entities data is kept in a valid state via `EntityMapper::world_scope` @@ -160,14 +161,14 @@ impl<'m> SceneEntityMapper<'m> { assert!(entities.reserve_generations(self.dead_start.index(), self.generations)); } - /// Creates an [`SceneEntityMapper`] from a provided [`World`] and [`EntityHashMap`], then calls the + /// Creates an [`SceneEntityMapper`] from a provided [`World`] and [`EntityHashMap`], then calls the /// provided function with it. This allows one to allocate new entity references in this [`World`] that are /// guaranteed to never point at a living entity now or in the future. This functionality is useful for safely /// mapping entity identifiers that point at entities outside the source world. The passed function, `f`, is called /// within the scope of this world. Its return value is then returned from `world_scope` as the generic type /// parameter `R`. pub fn world_scope( - entity_map: &'m mut EntityHashMap, + entity_map: &'m mut EntityHashMap, world: &mut World, f: impl FnOnce(&mut World, &mut Self) -> R, ) -> R { @@ -180,10 +181,8 @@ impl<'m> SceneEntityMapper<'m> { #[cfg(test)] mod tests { - use bevy_utils::EntityHashMap; - use crate::{ - entity::{Entity, EntityMapper, SceneEntityMapper}, + entity::{Entity, EntityHashMap, EntityMapper, SceneEntityMapper}, world::World, }; diff --git a/crates/bevy_ecs/src/entity/mod.rs b/crates/bevy_ecs/src/entity/mod.rs index ab7d167cff67c..efc0a22458195 100644 --- a/crates/bevy_ecs/src/entity/mod.rs +++ b/crates/bevy_ecs/src/entity/mod.rs @@ -36,9 +36,14 @@ //! [`EntityWorldMut::insert`]: crate::world::EntityWorldMut::insert //! [`EntityWorldMut::remove`]: crate::world::EntityWorldMut::remove mod map_entities; +#[cfg(feature = "bevy_reflect")] +use bevy_reflect::{Reflect, ReflectDeserialize, ReflectSerialize}; +pub use map_entities::*; + +mod hash; +pub use hash::*; use bevy_utils::tracing::warn; -pub use map_entities::*; use crate::{ archetype::{ArchetypeId, ArchetypeRow}, @@ -123,6 +128,11 @@ type IdCursor = isize; /// [`Query::get`]: crate::system::Query::get /// [`World`]: crate::world::World #[derive(Clone, Copy)] +#[cfg_attr(feature = "bevy_reflect", derive(Reflect))] +#[cfg_attr( + feature = "bevy_reflect", + reflect_value(Hash, PartialEq, Serialize, Deserialize) +)] // Alignment repr necessary to allow LLVM to better output // optimised codegen for `to_bits`, `PartialEq` and `Ord`. #[repr(C, align(8))] @@ -218,7 +228,7 @@ impl Entity { /// // ... replace the entities with valid ones. /// ``` /// - /// Deriving [`Reflect`](bevy_reflect::Reflect) for a component that has an `Entity` field: + /// Deriving [`Reflect`] for a component that has an `Entity` field: /// /// ```no_run /// # use bevy_ecs::{prelude::*, component::*}; @@ -1092,7 +1102,7 @@ mod tests { #[test] fn entity_hash_keeps_similar_ids_together() { use std::hash::BuildHasher; - let hash = bevy_utils::EntityHash; + let hash = EntityHash; let first_id = 0xC0FFEE << 8; let first_hash = hash.hash_one(Entity::from_raw(first_id)); @@ -1107,7 +1117,8 @@ mod tests { #[test] fn entity_hash_id_bitflip_affects_high_7_bits() { use std::hash::BuildHasher; - let hash = bevy_utils::EntityHash; + + let hash = EntityHash; let first_id = 0xC0FFEE; let first_hash = hash.hash_one(Entity::from_raw(first_id)) >> 57; diff --git a/crates/bevy_ecs/src/reflect/map_entities.rs b/crates/bevy_ecs/src/reflect/map_entities.rs index af9d1ef451f9d..0d783885dab63 100644 --- a/crates/bevy_ecs/src/reflect/map_entities.rs +++ b/crates/bevy_ecs/src/reflect/map_entities.rs @@ -1,10 +1,9 @@ use crate::{ component::Component, - entity::{Entity, MapEntities, SceneEntityMapper}, + entity::{Entity, EntityHashMap, MapEntities, SceneEntityMapper}, world::World, }; use bevy_reflect::FromType; -use bevy_utils::EntityHashMap; /// For a specific type of component, this maps any fields with values of type [`Entity`] to a new world. /// Since a given `Entity` ID is only valid for the world it came from, when performing deserialization @@ -18,33 +17,29 @@ pub struct ReflectMapEntities { } impl ReflectMapEntities { - /// A general method for applying [`MapEntities`] behavior to all elements in an [`EntityHashMap`]. + /// A general method for applying [`MapEntities`] behavior to all elements in an [`EntityHashMap`]. /// - /// Be mindful in its usage: Works best in situations where the entities in the [`EntityHashMap`] are newly + /// Be mindful in its usage: Works best in situations where the entities in the [`EntityHashMap`] are newly /// created, before systems have a chance to add new components. If some of the entities referred to - /// by the [`EntityHashMap`] might already contain valid entity references, you should use [`map_entities`](Self::map_entities). + /// by the [`EntityHashMap`] might already contain valid entity references, you should use [`map_entities`](Self::map_entities). /// /// An example of this: A scene can be loaded with `Parent` components, but then a `Parent` component can be added /// to these entities after they have been loaded. If you reload the scene using [`map_all_entities`](Self::map_all_entities), those `Parent` /// components with already valid entity references could be updated to point at something else entirely. - pub fn map_all_entities( - &self, - world: &mut World, - entity_map: &mut EntityHashMap, - ) { + pub fn map_all_entities(&self, world: &mut World, entity_map: &mut EntityHashMap) { SceneEntityMapper::world_scope(entity_map, world, self.map_all_entities); } - /// A general method for applying [`MapEntities`] behavior to elements in an [`EntityHashMap`]. Unlike + /// A general method for applying [`MapEntities`] behavior to elements in an [`EntityHashMap`]. Unlike /// [`map_all_entities`](Self::map_all_entities), this is applied to specific entities, not all values - /// in the [`EntityHashMap`]. + /// in the [`EntityHashMap`]. /// /// This is useful mostly for when you need to be careful not to update components that already contain valid entity /// values. See [`map_all_entities`](Self::map_all_entities) for more details. pub fn map_entities( &self, world: &mut World, - entity_map: &mut EntityHashMap, + entity_map: &mut EntityHashMap, entities: &[Entity], ) { SceneEntityMapper::world_scope(entity_map, world, |world, mapper| { diff --git a/crates/bevy_ecs/src/reflect/mod.rs b/crates/bevy_ecs/src/reflect/mod.rs index 544ad02932472..720fe8dbf5ae6 100644 --- a/crates/bevy_ecs/src/reflect/mod.rs +++ b/crates/bevy_ecs/src/reflect/mod.rs @@ -3,8 +3,8 @@ use std::ops::{Deref, DerefMut}; use crate as bevy_ecs; -use crate::{entity::Entity, system::Resource}; -use bevy_reflect::{impl_reflect_value, ReflectDeserialize, ReflectSerialize, TypeRegistryArc}; +use crate::system::Resource; +use bevy_reflect::TypeRegistryArc; mod bundle; mod component; @@ -40,5 +40,3 @@ impl DerefMut for AppTypeRegistry { &mut self.0 } } - -impl_reflect_value!((in bevy_ecs) Entity(Hash, PartialEq, Serialize, Deserialize)); diff --git a/crates/bevy_gltf/src/loader.rs b/crates/bevy_gltf/src/loader.rs index 2ce9c2162c8c7..ff1aced2f680b 100644 --- a/crates/bevy_gltf/src/loader.rs +++ b/crates/bevy_gltf/src/loader.rs @@ -4,6 +4,7 @@ use bevy_asset::{ }; use bevy_core::Name; use bevy_core_pipeline::prelude::Camera3dBundle; +use bevy_ecs::entity::EntityHashMap; use bevy_ecs::{entity::Entity, world::World}; use bevy_hierarchy::{BuildWorldChildren, WorldChildBuilder}; use bevy_log::{error, warn}; @@ -33,7 +34,7 @@ use bevy_scene::Scene; #[cfg(not(target_arch = "wasm32"))] use bevy_tasks::IoTaskPool; use bevy_transform::components::Transform; -use bevy_utils::{EntityHashMap, HashMap, HashSet}; +use bevy_utils::{HashMap, HashSet}; use gltf::{ accessor::Iter, mesh::{util::ReadIndices, Mode}, @@ -930,7 +931,7 @@ fn load_node( load_context: &mut LoadContext, settings: &GltfLoaderSettings, node_index_to_entity_map: &mut HashMap, - entity_to_skin_index_map: &mut EntityHashMap, + entity_to_skin_index_map: &mut EntityHashMap, active_camera_found: &mut bool, parent_transform: &Transform, ) -> Result<(), GltfError> { diff --git a/crates/bevy_pbr/src/bundle.rs b/crates/bevy_pbr/src/bundle.rs index 6c7829bd1242d..beb8789c5625f 100644 --- a/crates/bevy_pbr/src/bundle.rs +++ b/crates/bevy_pbr/src/bundle.rs @@ -3,7 +3,8 @@ use crate::{ StandardMaterial, }; use bevy_asset::Handle; -use bevy_ecs::{bundle::Bundle, component::Component, prelude::Entity, reflect::ReflectComponent}; +use bevy_ecs::entity::EntityHashMap; +use bevy_ecs::{bundle::Bundle, component::Component, reflect::ReflectComponent}; use bevy_reflect::Reflect; use bevy_render::{ mesh::Mesh, @@ -11,7 +12,6 @@ use bevy_render::{ view::{InheritedVisibility, ViewVisibility, Visibility, VisibleEntities}, }; use bevy_transform::components::{GlobalTransform, Transform}; -use bevy_utils::EntityHashMap; /// A component bundle for PBR entities with a [`Mesh`] and a [`StandardMaterial`]. pub type PbrBundle = MaterialMeshBundle; @@ -75,7 +75,7 @@ impl CubemapVisibleEntities { pub struct CascadesVisibleEntities { /// Map of view entity to the visible entities for each cascade frustum. #[reflect(ignore)] - pub entities: EntityHashMap>, + pub entities: EntityHashMap>, } /// A component bundle for [`PointLight`] entities. diff --git a/crates/bevy_pbr/src/light.rs b/crates/bevy_pbr/src/light.rs index 582460f8a73f5..ffc1e67d0502c 100644 --- a/crates/bevy_pbr/src/light.rs +++ b/crates/bevy_pbr/src/light.rs @@ -1,5 +1,6 @@ use std::collections::HashSet; +use bevy_ecs::entity::EntityHashMap; use bevy_ecs::prelude::*; use bevy_math::{ AspectRatio, Mat4, UVec2, UVec3, Vec2, Vec3, Vec3A, Vec3Swizzles, Vec4, Vec4Swizzles, @@ -16,7 +17,7 @@ use bevy_render::{ view::{InheritedVisibility, RenderLayers, ViewVisibility, VisibleEntities}, }; use bevy_transform::components::{GlobalTransform, Transform}; -use bevy_utils::{tracing::warn, EntityHashMap}; +use bevy_utils::tracing::warn; use crate::*; @@ -390,7 +391,7 @@ impl From for CascadeShadowConfig { #[reflect(Component)] pub struct Cascades { /// Map from a view to the configuration of each of its [`Cascade`]s. - pub(crate) cascades: EntityHashMap>, + pub(crate) cascades: EntityHashMap>, } #[derive(Clone, Debug, Default, Reflect)] diff --git a/crates/bevy_pbr/src/light_probe/mod.rs b/crates/bevy_pbr/src/light_probe/mod.rs index 30b042cc40539..4cb9325a410dd 100644 --- a/crates/bevy_pbr/src/light_probe/mod.rs +++ b/crates/bevy_pbr/src/light_probe/mod.rs @@ -159,6 +159,7 @@ pub struct LightProbesUniform { intensity_for_view: f32, } +/// A GPU buffer that stores information about all light probes. #[derive(Resource, Default, Deref, DerefMut)] pub struct LightProbesBuffer(DynamicUniformBuffer); diff --git a/crates/bevy_pbr/src/lightmap/mod.rs b/crates/bevy_pbr/src/lightmap/mod.rs index 3185507fbb55c..c34ac4885707e 100644 --- a/crates/bevy_pbr/src/lightmap/mod.rs +++ b/crates/bevy_pbr/src/lightmap/mod.rs @@ -30,6 +30,7 @@ use bevy_app::{App, Plugin}; use bevy_asset::{load_internal_asset, AssetId, Handle}; +use bevy_ecs::entity::EntityHashMap; use bevy_ecs::{ component::Component, entity::Entity, @@ -43,7 +44,7 @@ use bevy_render::{ mesh::Mesh, render_asset::RenderAssets, render_resource::Shader, texture::Image, view::ViewVisibility, Extract, ExtractSchedule, RenderApp, }; -use bevy_utils::{EntityHashMap, HashSet}; +use bevy_utils::HashSet; use crate::RenderMeshInstances; @@ -104,7 +105,7 @@ pub struct RenderLightmaps { /// /// Entities without lightmaps, or for which the mesh or lightmap isn't /// loaded, won't have entries in this table. - pub(crate) render_lightmaps: EntityHashMap, + pub(crate) render_lightmaps: EntityHashMap, /// All active lightmap images in the scene. /// diff --git a/crates/bevy_pbr/src/render/light.rs b/crates/bevy_pbr/src/render/light.rs index fa40a03a37c56..40319be1eea3c 100644 --- a/crates/bevy_pbr/src/render/light.rs +++ b/crates/bevy_pbr/src/render/light.rs @@ -1,4 +1,5 @@ use bevy_core_pipeline::core_3d::{Transparent3d, CORE_3D_DEPTH_FORMAT}; +use bevy_ecs::entity::EntityHashMap; use bevy_ecs::prelude::*; use bevy_math::{Mat4, UVec3, UVec4, Vec2, Vec3, Vec3Swizzles, Vec4, Vec4Swizzles}; use bevy_render::{ @@ -21,7 +22,6 @@ use bevy_utils::tracing::info_span; use bevy_utils::{ nonmax::NonMaxU32, tracing::{error, warn}, - EntityHashMap, }; use std::{hash::Hash, num::NonZeroU64, ops::Range}; @@ -50,8 +50,8 @@ pub struct ExtractedDirectionalLight { shadow_depth_bias: f32, shadow_normal_bias: f32, cascade_shadow_config: CascadeShadowConfig, - cascades: EntityHashMap>, - frusta: EntityHashMap>, + cascades: EntityHashMap>, + frusta: EntityHashMap>, render_layers: RenderLayers, } @@ -586,7 +586,7 @@ pub const CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT: u32 = 3; #[derive(Resource)] pub struct GlobalLightMeta { pub gpu_point_lights: GpuPointLights, - pub entity_to_index: EntityHashMap, + pub entity_to_index: EntityHashMap, } impl FromWorld for GlobalLightMeta { diff --git a/crates/bevy_pbr/src/render/mesh.rs b/crates/bevy_pbr/src/render/mesh.rs index 11a2cce0f2ed1..b8d8b4dfd28b2 100644 --- a/crates/bevy_pbr/src/render/mesh.rs +++ b/crates/bevy_pbr/src/render/mesh.rs @@ -10,6 +10,7 @@ use bevy_core_pipeline::{ deferred::{AlphaMask3dDeferred, Opaque3dDeferred}, }; use bevy_derive::{Deref, DerefMut}; +use bevy_ecs::entity::EntityHashMap; use bevy_ecs::{ prelude::*, query::ROQueryItem, @@ -33,7 +34,7 @@ use bevy_render::{ Extract, ExtractSchedule, Render, RenderApp, RenderSet, }; use bevy_transform::components::GlobalTransform; -use bevy_utils::{tracing::error, EntityHashMap, Entry, HashMap, Hashed}; +use bevy_utils::{tracing::error, Entry, HashMap, Hashed}; use std::cell::Cell; use thread_local::ThreadLocal; @@ -254,7 +255,7 @@ pub struct RenderMeshInstance { } #[derive(Default, Resource, Deref, DerefMut)] -pub struct RenderMeshInstances(EntityHashMap); +pub struct RenderMeshInstances(EntityHashMap); pub fn extract_meshes( mut render_mesh_instances: ResMut, diff --git a/crates/bevy_pbr/src/render/morph.rs b/crates/bevy_pbr/src/render/morph.rs index 61dfef75d5280..7516bb495b7f1 100644 --- a/crates/bevy_pbr/src/render/morph.rs +++ b/crates/bevy_pbr/src/render/morph.rs @@ -1,6 +1,7 @@ use std::{iter, mem}; use bevy_derive::{Deref, DerefMut}; +use bevy_ecs::entity::EntityHashMap; use bevy_ecs::prelude::*; use bevy_render::{ batching::NoAutomaticBatching, @@ -10,7 +11,6 @@ use bevy_render::{ view::ViewVisibility, Extract, }; -use bevy_utils::EntityHashMap; use bytemuck::Pod; #[derive(Component)] @@ -19,7 +19,7 @@ pub struct MorphIndex { } #[derive(Default, Resource, Deref, DerefMut)] -pub struct MorphIndices(EntityHashMap); +pub struct MorphIndices(EntityHashMap); #[derive(Resource)] pub struct MorphUniform { diff --git a/crates/bevy_pbr/src/render/skin.rs b/crates/bevy_pbr/src/render/skin.rs index bfb12fd794427..8ad3c35d6ee47 100644 --- a/crates/bevy_pbr/src/render/skin.rs +++ b/crates/bevy_pbr/src/render/skin.rs @@ -1,5 +1,6 @@ use bevy_asset::Assets; use bevy_derive::{Deref, DerefMut}; +use bevy_ecs::entity::EntityHashMap; use bevy_ecs::prelude::*; use bevy_math::Mat4; use bevy_render::{ @@ -11,7 +12,6 @@ use bevy_render::{ Extract, }; use bevy_transform::prelude::GlobalTransform; -use bevy_utils::EntityHashMap; /// Maximum number of joints supported for skinned meshes. pub const MAX_JOINTS: usize = 256; @@ -31,7 +31,7 @@ impl SkinIndex { } #[derive(Default, Resource, Deref, DerefMut)] -pub struct SkinIndices(EntityHashMap); +pub struct SkinIndices(EntityHashMap); // Notes on implementation: see comment on top of the `extract_skins` system. #[derive(Resource)] diff --git a/crates/bevy_reflect/src/impls/std.rs b/crates/bevy_reflect/src/impls/std.rs index 4a1b26ac4ea56..86f0984a829df 100644 --- a/crates/bevy_reflect/src/impls/std.rs +++ b/crates/bevy_reflect/src/impls/std.rs @@ -80,7 +80,6 @@ impl_reflect_value!(isize( impl_reflect_value!(f32(Debug, PartialEq, Serialize, Deserialize, Default)); impl_reflect_value!(f64(Debug, PartialEq, Serialize, Deserialize, Default)); impl_type_path!(str); -impl_type_path!(::bevy_utils::EntityHash); impl_reflect_value!(::alloc::string::String( Debug, Hash, @@ -1655,15 +1654,12 @@ mod tests { Enum, FromReflect, Reflect, ReflectSerialize, TypeInfo, TypeRegistry, Typed, VariantInfo, VariantType, }; + use bevy_utils::HashMap; use bevy_utils::{Duration, Instant}; - use bevy_utils::{EntityHashMap, HashMap}; use static_assertions::assert_impl_all; use std::f32::consts::{PI, TAU}; use std::path::Path; - // EntityHashMap should implement Reflect - assert_impl_all!(EntityHashMap: Reflect); - #[test] fn can_serialize_duration() { let mut type_registry = TypeRegistry::default(); diff --git a/crates/bevy_render/src/extract_instances.rs b/crates/bevy_render/src/extract_instances.rs index 96fcfea7cb84e..5f09184d22ec3 100644 --- a/crates/bevy_render/src/extract_instances.rs +++ b/crates/bevy_render/src/extract_instances.rs @@ -10,11 +10,11 @@ use bevy_app::{App, Plugin}; use bevy_asset::{Asset, AssetId, Handle}; use bevy_derive::{Deref, DerefMut}; use bevy_ecs::{ + entity::EntityHashMap, prelude::Entity, query::{QueryFilter, QueryItem, ReadOnlyQueryData}, system::{lifetimeless::Read, Query, ResMut, Resource}, }; -use bevy_utils::EntityHashMap; use crate::{prelude::ViewVisibility, Extract, ExtractSchedule, RenderApp}; @@ -53,7 +53,7 @@ where /// Stores all extract instances of a type in the render world. #[derive(Resource, Deref, DerefMut)] -pub struct ExtractedInstances(EntityHashMap) +pub struct ExtractedInstances(EntityHashMap) where EI: ExtractInstance; diff --git a/crates/bevy_render/src/primitives/mod.rs b/crates/bevy_render/src/primitives/mod.rs index b06511a9ba138..25fef4abd2c09 100644 --- a/crates/bevy_render/src/primitives/mod.rs +++ b/crates/bevy_render/src/primitives/mod.rs @@ -1,9 +1,8 @@ use std::borrow::Borrow; -use bevy_ecs::{component::Component, prelude::Entity, reflect::ReflectComponent}; +use bevy_ecs::{component::Component, entity::EntityHashMap, reflect::ReflectComponent}; use bevy_math::{Affine3A, Mat3A, Mat4, Vec3, Vec3A, Vec4, Vec4Swizzles}; use bevy_reflect::Reflect; -use bevy_utils::EntityHashMap; /// An axis-aligned bounding box, defined by: /// - a center, @@ -323,7 +322,7 @@ impl CubemapFrusta { #[reflect(Component)] pub struct CascadesFrusta { #[reflect(ignore)] - pub frusta: EntityHashMap>, + pub frusta: EntityHashMap>, } #[cfg(test)] diff --git a/crates/bevy_render/src/view/window/mod.rs b/crates/bevy_render/src/view/window/mod.rs index decaf22b27013..656d4ceaa881a 100644 --- a/crates/bevy_render/src/view/window/mod.rs +++ b/crates/bevy_render/src/view/window/mod.rs @@ -7,8 +7,8 @@ use crate::{ Extract, ExtractSchedule, Render, RenderApp, RenderSet, }; use bevy_app::{App, Plugin}; -use bevy_ecs::prelude::*; -use bevy_utils::{default, tracing::debug, EntityHashMap, HashSet}; +use bevy_ecs::{entity::EntityHashMap, prelude::*}; +use bevy_utils::{default, tracing::debug, HashSet}; use bevy_window::{ CompositeAlphaMode, PresentMode, PrimaryWindow, RawHandleWrapper, Window, WindowClosed, }; @@ -92,11 +92,11 @@ impl ExtractedWindow { #[derive(Default, Resource)] pub struct ExtractedWindows { pub primary: Option, - pub windows: EntityHashMap, + pub windows: EntityHashMap, } impl Deref for ExtractedWindows { - type Target = EntityHashMap; + type Target = EntityHashMap; fn deref(&self) -> &Self::Target { &self.windows @@ -203,7 +203,7 @@ struct SurfaceData { #[derive(Resource, Default)] pub struct WindowSurfaces { - surfaces: EntityHashMap, + surfaces: EntityHashMap, /// List of windows that we have already called the initial `configure_surface` for configured_windows: HashSet, } diff --git a/crates/bevy_render/src/view/window/screenshot.rs b/crates/bevy_render/src/view/window/screenshot.rs index a09dc423ff4e7..c13a60f88524c 100644 --- a/crates/bevy_render/src/view/window/screenshot.rs +++ b/crates/bevy_render/src/view/window/screenshot.rs @@ -2,10 +2,9 @@ use std::{borrow::Cow, path::Path, sync::PoisonError}; use bevy_app::Plugin; use bevy_asset::{load_internal_asset, Handle}; -use bevy_ecs::prelude::*; +use bevy_ecs::{entity::EntityHashMap, prelude::*}; use bevy_log::{error, info, info_span}; use bevy_tasks::AsyncComputeTaskPool; -use bevy_utils::EntityHashMap; use std::sync::Mutex; use thiserror::Error; use wgpu::{ @@ -33,7 +32,7 @@ pub type ScreenshotFn = Box; #[derive(Resource, Default)] pub struct ScreenshotManager { // this is in a mutex to enable extraction with only an immutable reference - pub(crate) callbacks: Mutex>, + pub(crate) callbacks: Mutex>, } #[derive(Error, Debug)] diff --git a/crates/bevy_scene/src/dynamic_scene.rs b/crates/bevy_scene/src/dynamic_scene.rs index 2d01a02cfdcdf..91254836570a2 100644 --- a/crates/bevy_scene/src/dynamic_scene.rs +++ b/crates/bevy_scene/src/dynamic_scene.rs @@ -1,11 +1,12 @@ use crate::{ron, DynamicSceneBuilder, Scene, SceneSpawnError}; +use bevy_ecs::entity::EntityHashMap; use bevy_ecs::{ entity::Entity, reflect::{AppTypeRegistry, ReflectComponent, ReflectMapEntities}, world::World, }; use bevy_reflect::{Reflect, TypePath, TypeRegistryArc}; -use bevy_utils::{EntityHashMap, TypeIdMap}; +use bevy_utils::TypeIdMap; #[cfg(feature = "serialize")] use crate::serde::SceneSerializer; @@ -65,7 +66,7 @@ impl DynamicScene { pub fn write_to_world_with( &self, world: &mut World, - entity_map: &mut EntityHashMap, + entity_map: &mut EntityHashMap, type_registry: &AppTypeRegistry, ) -> Result<(), SceneSpawnError> { let type_registry = type_registry.read(); @@ -163,7 +164,7 @@ impl DynamicScene { pub fn write_to_world( &self, world: &mut World, - entity_map: &mut EntityHashMap, + entity_map: &mut EntityHashMap, ) -> Result<(), SceneSpawnError> { let registry = world.resource::().clone(); self.write_to_world_with(world, entity_map, ®istry) @@ -191,9 +192,9 @@ where #[cfg(test)] mod tests { + use bevy_ecs::entity::EntityHashMap; use bevy_ecs::{reflect::AppTypeRegistry, system::Command, world::World}; use bevy_hierarchy::{Parent, PushChild}; - use bevy_utils::EntityHashMap; use crate::dynamic_scene_builder::DynamicSceneBuilder; diff --git a/crates/bevy_scene/src/scene.rs b/crates/bevy_scene/src/scene.rs index 28cf824aa061c..30d4d4743fcd3 100644 --- a/crates/bevy_scene/src/scene.rs +++ b/crates/bevy_scene/src/scene.rs @@ -1,11 +1,11 @@ use crate::{DynamicScene, InstanceInfo, SceneSpawnError}; use bevy_asset::Asset; +use bevy_ecs::entity::EntityHashMap; use bevy_ecs::{ reflect::{AppTypeRegistry, ReflectComponent, ReflectMapEntities, ReflectResource}, world::World, }; use bevy_reflect::TypePath; -use bevy_utils::EntityHashMap; /// To spawn a scene, you can use either: /// * [`SceneSpawner::spawn`](crate::SceneSpawner::spawn) diff --git a/crates/bevy_scene/src/scene_spawner.rs b/crates/bevy_scene/src/scene_spawner.rs index 5d9a72fbcbc05..d8e0ea63acb5a 100644 --- a/crates/bevy_scene/src/scene_spawner.rs +++ b/crates/bevy_scene/src/scene_spawner.rs @@ -1,5 +1,6 @@ use crate::{DynamicScene, Scene}; use bevy_asset::{AssetEvent, AssetId, Assets, Handle}; +use bevy_ecs::entity::EntityHashMap; use bevy_ecs::{ entity::Entity, event::{Event, Events, ManualEventReader}, @@ -8,7 +9,7 @@ use bevy_ecs::{ world::{Mut, World}, }; use bevy_hierarchy::{Parent, PushChild}; -use bevy_utils::{tracing::error, EntityHashMap, HashMap, HashSet}; +use bevy_utils::{tracing::error, HashMap, HashSet}; use thiserror::Error; use uuid::Uuid; @@ -25,7 +26,7 @@ pub struct SceneInstanceReady { #[derive(Debug)] pub struct InstanceInfo { /// Mapping of entities from the scene world to the instance world. - pub entity_map: EntityHashMap, + pub entity_map: EntityHashMap, } /// Unique id identifying a scene instance. @@ -213,7 +214,7 @@ impl SceneSpawner { fn spawn_dynamic_internal( world: &mut World, id: AssetId, - entity_map: &mut EntityHashMap, + entity_map: &mut EntityHashMap, ) -> Result<(), SceneSpawnError> { world.resource_scope(|world, scenes: Mut>| { let scene = scenes diff --git a/crates/bevy_scene/src/serde.rs b/crates/bevy_scene/src/serde.rs index 81f7692fbfe37..0904502f2d4e4 100644 --- a/crates/bevy_scene/src/serde.rs +++ b/crates/bevy_scene/src/serde.rs @@ -499,13 +499,13 @@ mod tests { use crate::ron; use crate::serde::{SceneDeserializer, SceneSerializer}; use crate::{DynamicScene, DynamicSceneBuilder}; + use bevy_ecs::entity::EntityHashMap; use bevy_ecs::entity::{Entity, EntityMapper, MapEntities}; use bevy_ecs::prelude::{Component, ReflectComponent, ReflectResource, Resource, World}; use bevy_ecs::query::{With, Without}; use bevy_ecs::reflect::{AppTypeRegistry, ReflectMapEntities}; use bevy_ecs::world::FromWorld; use bevy_reflect::{Reflect, ReflectSerialize}; - use bevy_utils::EntityHashMap; use bincode::Options; use serde::de::DeserializeSeed; use serde::Serialize; diff --git a/crates/bevy_sprite/src/mesh2d/material.rs b/crates/bevy_sprite/src/mesh2d/material.rs index 768ebf067cce4..0a6da78be7ecc 100644 --- a/crates/bevy_sprite/src/mesh2d/material.rs +++ b/crates/bevy_sprite/src/mesh2d/material.rs @@ -5,6 +5,7 @@ use bevy_core_pipeline::{ tonemapping::{DebandDither, Tonemapping}, }; use bevy_derive::{Deref, DerefMut}; +use bevy_ecs::entity::EntityHashMap; use bevy_ecs::{ prelude::*, system::{lifetimeless::SRes, SystemParamItem}, @@ -29,7 +30,7 @@ use bevy_render::{ Extract, ExtractSchedule, Render, RenderApp, RenderSet, }; use bevy_transform::components::{GlobalTransform, Transform}; -use bevy_utils::{EntityHashMap, FloatOrd, HashMap, HashSet}; +use bevy_utils::{FloatOrd, HashMap, HashSet}; use std::hash::Hash; use std::marker::PhantomData; @@ -180,7 +181,7 @@ where } #[derive(Resource, Deref, DerefMut)] -pub struct RenderMaterial2dInstances(EntityHashMap>); +pub struct RenderMaterial2dInstances(EntityHashMap>); impl Default for RenderMaterial2dInstances { fn default() -> Self { diff --git a/crates/bevy_sprite/src/mesh2d/mesh.rs b/crates/bevy_sprite/src/mesh2d/mesh.rs index cf66740f38acb..8bd12bc862f60 100644 --- a/crates/bevy_sprite/src/mesh2d/mesh.rs +++ b/crates/bevy_sprite/src/mesh2d/mesh.rs @@ -3,6 +3,7 @@ use bevy_asset::{load_internal_asset, AssetId, Handle}; use bevy_core_pipeline::core_2d::Transparent2d; use bevy_derive::{Deref, DerefMut}; +use bevy_ecs::entity::EntityHashMap; use bevy_ecs::{ prelude::*, query::ROQueryItem, @@ -30,7 +31,6 @@ use bevy_render::{ Extract, ExtractSchedule, Render, RenderApp, RenderSet, }; use bevy_transform::components::GlobalTransform; -use bevy_utils::EntityHashMap; use crate::Material2dBindGroupId; @@ -192,7 +192,7 @@ pub struct RenderMesh2dInstance { } #[derive(Default, Resource, Deref, DerefMut)] -pub struct RenderMesh2dInstances(EntityHashMap); +pub struct RenderMesh2dInstances(EntityHashMap); #[derive(Component)] pub struct Mesh2d; diff --git a/crates/bevy_sprite/src/render/mod.rs b/crates/bevy_sprite/src/render/mod.rs index 72177821f3d66..cb05f7c03cbdd 100644 --- a/crates/bevy_sprite/src/render/mod.rs +++ b/crates/bevy_sprite/src/render/mod.rs @@ -9,6 +9,7 @@ use bevy_core_pipeline::{ core_2d::Transparent2d, tonemapping::{DebandDither, Tonemapping}, }; +use bevy_ecs::entity::EntityHashMap; use bevy_ecs::{ prelude::*, system::{lifetimeless::*, SystemParamItem, SystemState}, @@ -36,7 +37,7 @@ use bevy_render::{ Extract, }; use bevy_transform::components::GlobalTransform; -use bevy_utils::{EntityHashMap, FloatOrd, HashMap}; +use bevy_utils::{FloatOrd, HashMap}; use bytemuck::{Pod, Zeroable}; use fixedbitset::FixedBitSet; @@ -312,7 +313,7 @@ pub struct ExtractedSprite { #[derive(Resource, Default)] pub struct ExtractedSprites { - pub sprites: EntityHashMap, + pub sprites: EntityHashMap, } #[derive(Resource, Default)] diff --git a/crates/bevy_ui/src/layout/mod.rs b/crates/bevy_ui/src/layout/mod.rs index 25df73d6af353..31f123ff6d3f5 100644 --- a/crates/bevy_ui/src/layout/mod.rs +++ b/crates/bevy_ui/src/layout/mod.rs @@ -2,6 +2,7 @@ mod convert; pub mod debug; use crate::{ContentSize, DefaultUiCamera, Node, Outline, Style, TargetCamera, UiScale}; +use bevy_ecs::entity::EntityHashMap; use bevy_ecs::{ change_detection::{DetectChanges, DetectChangesMut}, entity::Entity, @@ -16,7 +17,7 @@ use bevy_log::warn; use bevy_math::{UVec2, Vec2}; use bevy_render::camera::{Camera, NormalizedRenderTarget}; use bevy_transform::components::Transform; -use bevy_utils::{default, EntityHashMap, HashMap, HashSet}; +use bevy_utils::{default, HashMap, HashSet}; use bevy_window::{PrimaryWindow, Window, WindowScaleFactorChanged}; use std::fmt; use taffy::{tree::LayoutTree, Taffy}; @@ -51,14 +52,14 @@ struct RootNodePair { #[derive(Resource)] pub struct UiSurface { - entity_to_taffy: EntityHashMap, - camera_roots: EntityHashMap>, + entity_to_taffy: EntityHashMap, + camera_roots: EntityHashMap>, taffy: Taffy, } fn _assert_send_sync_ui_surface_impl_safe() { fn _assert_send_sync() {} - _assert_send_sync::>(); + _assert_send_sync::>(); _assert_send_sync::(); _assert_send_sync::(); } diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index cede7b2f1e5f2..dd2fe56385b26 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -23,6 +23,7 @@ use crate::{ use bevy_app::prelude::*; use bevy_asset::{load_internal_asset, AssetEvent, AssetId, Assets, Handle}; +use bevy_ecs::entity::EntityHashMap; use bevy_ecs::prelude::*; use bevy_math::{Mat4, Rect, URect, UVec4, Vec2, Vec3, Vec4Swizzles}; use bevy_render::{ @@ -41,7 +42,7 @@ use bevy_sprite::TextureAtlasLayout; #[cfg(feature = "bevy_text")] use bevy_text::{PositionedGlyph, Text, TextLayoutInfo}; use bevy_transform::components::GlobalTransform; -use bevy_utils::{EntityHashMap, FloatOrd, HashMap}; +use bevy_utils::{FloatOrd, HashMap}; use bytemuck::{Pod, Zeroable}; use std::ops::Range; @@ -147,7 +148,7 @@ pub struct ExtractedUiNode { #[derive(Resource, Default)] pub struct ExtractedUiNodes { - pub uinodes: EntityHashMap, + pub uinodes: EntityHashMap, } pub(crate) fn resolve_border_thickness(value: Val, parent_width: f32, viewport_size: Vec2) -> f32 { diff --git a/crates/bevy_utils/src/lib.rs b/crates/bevy_utils/src/lib.rs index c7381c25208ec..b0b76848a1937 100644 --- a/crates/bevy_utils/src/lib.rs +++ b/crates/bevy_utils/src/lib.rs @@ -265,124 +265,6 @@ impl PreHashMapExt for PreHashMap Self::Hasher { - EntityHasher::default() - } -} - -/// A very fast hash that is only designed to work on generational indices -/// like `Entity`. It will panic if attempting to hash a type containing -/// non-u64 fields. -/// -/// This is heavily optimized for typical cases, where you have mostly live -/// entities, and works particularly well for contiguous indices. -/// -/// If you have an unusual case -- say all your indices are multiples of 256 -/// or most of the entities are dead generations -- then you might want also to -/// try [`AHasher`] for a slower hash computation but fewer lookup conflicts. -#[derive(Debug, Default)] -pub struct EntityHasher { - hash: u64, -} - -impl Hasher for EntityHasher { - #[inline] - fn finish(&self) -> u64 { - self.hash - } - - fn write(&mut self, _bytes: &[u8]) { - panic!("can only hash u64 using EntityHasher"); - } - - #[inline] - fn write_u64(&mut self, bits: u64) { - // SwissTable (and thus `hashbrown`) cares about two things from the hash: - // - H1: low bits (masked by `2ⁿ-1`) to pick the slot in which to store the item - // - H2: high 7 bits are used to SIMD optimize hash collision probing - // For more see - - // This hash function assumes that the entity ids are still well-distributed, - // so for H1 leaves the entity id alone in the low bits so that id locality - // will also give memory locality for things spawned together. - // For H2, take advantage of the fact that while multiplication doesn't - // spread entropy to the low bits, it's incredibly good at spreading it - // upward, which is exactly where we need it the most. - - // While this does include the generation in the output, it doesn't do so - // *usefully*. H1 won't care until you have over 3 billion entities in - // the table, and H2 won't care until something hits generation 33 million. - // Thus the comment suggesting that this is best for live entities, - // where there won't be generation conflicts where it would matter. - - // The high 32 bits of this are ⅟φ for Fibonacci hashing. That works - // particularly well for hashing for the same reason as described in - // - // It loses no information because it has a modular inverse. - // (Specifically, `0x144c_bc89_u32 * 0x9e37_79b9_u32 == 1`.) - // - // The low 32 bits make that part of the just product a pass-through. - const UPPER_PHI: u64 = 0x9e37_79b9_0000_0001; - - // This is `(MAGIC * index + generation) << 32 + index`, in a single instruction. - self.hash = bits.wrapping_mul(UPPER_PHI); - } -} - -/// A [`HashMap`] pre-configured to use [`EntityHash`] hashing. -/// Iteration order only depends on the order of insertions and deletions. -pub type EntityHashMap = hashbrown::HashMap; - -/// A [`HashSet`] pre-configured to use [`EntityHash`] hashing. -/// Iteration order only depends on the order of insertions and deletions. -pub type EntityHashSet = hashbrown::HashSet; - -/// A specialized hashmap type with Key of [`TypeId`] -/// Iteration order only depends on the order of insertions and deletions. -pub type TypeIdMap = hashbrown::HashMap; - -/// [`BuildHasher`] for [`TypeId`]s. -#[derive(Default)] -pub struct NoOpTypeIdHash; - -impl BuildHasher for NoOpTypeIdHash { - type Hasher = NoOpTypeIdHasher; - - fn build_hasher(&self) -> Self::Hasher { - NoOpTypeIdHasher(0) - } -} - -#[doc(hidden)] -pub struct NoOpTypeIdHasher(u64); - -// TypeId already contains a high-quality hash, so skip re-hashing that hash. -impl std::hash::Hasher for NoOpTypeIdHasher { - fn finish(&self) -> u64 { - self.0 - } - - fn write(&mut self, bytes: &[u8]) { - // This will never be called: TypeId always just calls write_u64 once! - // This is a known trick and unlikely to change, but isn't officially guaranteed. - // Don't break applications (slower fallback, just check in test): - self.0 = bytes.iter().fold(self.0, |hash, b| { - hash.rotate_left(8).wrapping_add(*b as u64) - }); - } - - fn write_u64(&mut self, i: u64) { - self.0 = i; - } -} - /// A type which calls a function when dropped. /// This can be used to ensure that cleanup code is run even in case of a panic. /// @@ -438,6 +320,45 @@ impl Drop for OnDrop { } } +/// A specialized hashmap type with Key of [`TypeId`] +/// Iteration order only depends on the order of insertions and deletions. +pub type TypeIdMap = hashbrown::HashMap; + +/// [`BuildHasher`] for [`TypeId`]s. +#[derive(Default)] +pub struct NoOpTypeIdHash; + +impl BuildHasher for NoOpTypeIdHash { + type Hasher = NoOpTypeIdHasher; + + fn build_hasher(&self) -> Self::Hasher { + NoOpTypeIdHasher(0) + } +} +#[doc(hidden)] +#[derive(Default)] +pub struct NoOpTypeIdHasher(pub u64); + +// TypeId already contains a high-quality hash, so skip re-hashing that hash. +impl std::hash::Hasher for NoOpTypeIdHasher { + fn finish(&self) -> u64 { + self.0 + } + + fn write(&mut self, bytes: &[u8]) { + // This will never be called: TypeId always just calls write_u64 once! + // This is a known trick and unlikely to change, but isn't officially guaranteed. + // Don't break applications (slower fallback, just check in test): + self.0 = bytes.iter().fold(self.0, |hash, b| { + hash.rotate_left(8).wrapping_add(*b as u64) + }); + } + + fn write_u64(&mut self, i: u64) { + self.0 = i; + } +} + /// Calls the [`tracing::info!`] macro on a value. pub fn info(data: T) { tracing::info!("{:?}", data); @@ -478,7 +399,6 @@ mod tests { use static_assertions::assert_impl_all; // Check that the HashMaps are Clone if the key/values are Clone - assert_impl_all!(EntityHashMap::: Clone); assert_impl_all!(PreHashMap::: Clone); #[test] diff --git a/crates/bevy_winit/src/accessibility.rs b/crates/bevy_winit/src/accessibility.rs index 633cb151259a9..7836408677f61 100644 --- a/crates/bevy_winit/src/accessibility.rs +++ b/crates/bevy_winit/src/accessibility.rs @@ -15,6 +15,7 @@ use bevy_a11y::{ use bevy_a11y::{ActionRequest as ActionRequestWrapper, ManageAccessibilityUpdates}; use bevy_app::{App, Plugin, PostUpdate}; use bevy_derive::{Deref, DerefMut}; +use bevy_ecs::entity::EntityHashMap; use bevy_ecs::{ prelude::{DetectChanges, Entity, EventReader, EventWriter}, query::With, @@ -22,16 +23,15 @@ use bevy_ecs::{ system::{NonSend, NonSendMut, Query, Res, ResMut, Resource}, }; use bevy_hierarchy::{Children, Parent}; -use bevy_utils::EntityHashMap; use bevy_window::{PrimaryWindow, Window, WindowClosed}; /// Maps window entities to their `AccessKit` [`Adapter`]s. #[derive(Default, Deref, DerefMut)] -pub struct AccessKitAdapters(pub EntityHashMap); +pub struct AccessKitAdapters(pub EntityHashMap); /// Maps window entities to their respective [`WinitActionHandler`]s. #[derive(Resource, Default, Deref, DerefMut)] -pub struct WinitActionHandlers(pub EntityHashMap); +pub struct WinitActionHandlers(pub EntityHashMap); /// Forwards `AccessKit` [`ActionRequest`]s from winit to an event channel. #[derive(Clone, Default, Deref, DerefMut)] diff --git a/crates/bevy_winit/src/winit_windows.rs b/crates/bevy_winit/src/winit_windows.rs index 085897f21f001..3188ac2714fdf 100644 --- a/crates/bevy_winit/src/winit_windows.rs +++ b/crates/bevy_winit/src/winit_windows.rs @@ -5,7 +5,8 @@ use bevy_a11y::{ }; use bevy_ecs::entity::Entity; -use bevy_utils::{tracing::warn, EntityHashMap, HashMap}; +use bevy_ecs::entity::EntityHashMap; +use bevy_utils::{tracing::warn, HashMap}; use bevy_window::{CursorGrabMode, Window, WindowMode, WindowPosition, WindowResolution}; use winit::{ @@ -25,7 +26,7 @@ pub struct WinitWindows { /// Stores [`winit`] windows by window identifier. pub windows: HashMap, /// Maps entities to `winit` window identifiers. - pub entity_to_winit: EntityHashMap, + pub entity_to_winit: EntityHashMap, /// Maps `winit` window identifiers to entities. pub winit_to_entity: HashMap, // Many `winit` window functions (e.g. `set_window_icon`) can only be called on the main thread.