From be39a7d5d7b6eed7cfb8f613bfb93e9c3727b849 Mon Sep 17 00:00:00 2001 From: Clar Fon <15850505+clarfonthey@users.noreply.github.com> Date: Tue, 10 Dec 2024 14:45:50 -0500 Subject: [PATCH] Update hashbrown to 0.15 (#15801) Updating dependencies; adopted version of #15696. (Supercedes #15696.) Long answer: hashbrown is no longer using ahash by default, meaning that we can't use the default-hasher methods with ahasher. So, we have to use the longer-winded versions instead. This takes the opportunity to also switch our default hasher as well, but without actually enabling the default-hasher feature for hashbrown, meaning that we'll be able to change our hasher more easily at the cost of all of these method calls being obnoxious forever. One large change from 0.15 is that `insert_unique_unchecked` is now `unsafe`, and for cases where unsafe code was denied at the crate level, I replaced it with `insert`. ## Migration Guide `bevy_utils` has updated its version of `hashbrown` to 0.15 and now defaults to `foldhash` instead of `ahash`. This means that if you've hard-coded your hasher to `bevy_utils::AHasher` or separately used the `ahash` crate in your code, you may need to switch to `foldhash` to ensure that everything works like it does in Bevy. --- crates/bevy_animation/src/graph.rs | 8 +- crates/bevy_animation/src/lib.rs | 3 +- crates/bevy_app/src/app.rs | 2 +- crates/bevy_asset/src/handle.rs | 6 +- crates/bevy_asset/src/id.rs | 6 +- crates/bevy_asset/src/io/gated.rs | 2 +- crates/bevy_asset/src/io/source.rs | 2 +- crates/bevy_asset/src/loader.rs | 2 +- crates/bevy_asset/src/server/info.rs | 4 +- crates/bevy_asset/src/server/mod.rs | 2 +- crates/bevy_core/src/name.rs | 8 +- crates/bevy_core_pipeline/src/core_2d/mod.rs | 10 +- crates/bevy_core_pipeline/src/core_3d/mod.rs | 29 +++--- crates/bevy_core_pipeline/src/oit/mod.rs | 2 +- .../bevy_core_pipeline/src/upscaling/mod.rs | 2 +- .../src/ui_debug_overlay/inset.rs | 2 +- crates/bevy_diagnostic/src/diagnostic.rs | 2 +- crates/bevy_ecs/src/archetype.rs | 4 +- crates/bevy_ecs/src/bundle.rs | 9 +- crates/bevy_ecs/src/entity/hash.rs | 3 +- crates/bevy_ecs/src/entity/visit_entities.rs | 2 +- crates/bevy_ecs/src/intern.rs | 13 +-- crates/bevy_ecs/src/lib.rs | 90 +++++++++++------ .../bevy_ecs/src/schedule/graph/graph_map.rs | 24 ++--- crates/bevy_ecs/src/schedule/graph/mod.rs | 31 +++--- crates/bevy_ecs/src/schedule/schedule.rs | 31 +++--- crates/bevy_ecs/src/world/entity_ref.rs | 6 +- crates/bevy_ecs/src/world/mod.rs | 31 +++--- crates/bevy_gltf/src/loader.rs | 36 +++---- crates/bevy_mesh/src/primitives/dim2.rs | 2 +- crates/bevy_pbr/src/cluster/mod.rs | 2 +- crates/bevy_pbr/src/light_probe/mod.rs | 2 +- crates/bevy_pbr/src/material_bind_groups.rs | 7 +- crates/bevy_pbr/src/meshlet/from_mesh.rs | 2 +- .../bevy_pbr/src/meshlet/instance_manager.rs | 4 +- .../src/meshlet/meshlet_mesh_manager.rs | 2 +- crates/bevy_pbr/src/render/mesh.rs | 14 +-- crates/bevy_picking/src/focus.rs | 2 +- crates/bevy_reflect/Cargo.toml | 3 + .../bevy_reflect/derive/src/serialization.rs | 2 +- .../bevy_reflect/src/func/dynamic_function.rs | 6 +- .../src/func/dynamic_function_internal.rs | 8 +- crates/bevy_reflect/src/impls/foldhash.rs | 8 ++ crates/bevy_reflect/src/impls/std.rs | 16 ++- crates/bevy_reflect/src/kind.rs | 2 +- crates/bevy_reflect/src/lib.rs | 22 +++-- crates/bevy_reflect/src/map.rs | 11 +-- crates/bevy_reflect/src/serde/de/mod.rs | 18 ++-- crates/bevy_reflect/src/serde/ser/mod.rs | 7 +- crates/bevy_reflect/src/set.rs | 11 +-- crates/bevy_reflect/src/utility.rs | 6 +- crates/bevy_remote/src/builtin_methods.rs | 6 +- crates/bevy_remote/src/http.rs | 12 ++- crates/bevy_render/src/camera/camera.rs | 10 +- .../src/camera/camera_driver_node.rs | 2 +- crates/bevy_render/src/mesh/allocator.rs | 20 ++-- crates/bevy_render/src/render_asset.rs | 6 +- .../render_resource/pipeline_specializer.rs | 8 +- crates/bevy_render/src/view/mod.rs | 2 +- crates/bevy_scene/src/scene_filter.rs | 10 +- crates/bevy_scene/src/scene_spawner.rs | 4 +- crates/bevy_scene/src/serde.rs | 2 +- .../bevy_sprite/src/texture_atlas_builder.rs | 2 +- crates/bevy_ui/src/layout/mod.rs | 2 +- crates/bevy_ui/src/picking_backend.rs | 6 +- crates/bevy_ui/src/stack.rs | 2 +- crates/bevy_ui/src/update.rs | 2 +- crates/bevy_utils/Cargo.toml | 20 ++-- crates/bevy_utils/src/lib.rs | 99 +++++++++++-------- examples/3d/tonemapping.rs | 2 +- examples/animation/animation_masks.rs | 2 +- examples/ecs/dynamic.rs | 3 +- examples/games/contributors.rs | 3 +- examples/reflection/dynamic_types.rs | 4 +- examples/reflection/reflection_types.rs | 2 +- tests/ecs/ambiguity_detection.rs | 2 +- tools/build-templated-pages/Cargo.toml | 2 +- .../remove-desktop-app-mode.patch | 2 +- 78 files changed, 416 insertions(+), 350 deletions(-) create mode 100644 crates/bevy_reflect/src/impls/foldhash.rs diff --git a/crates/bevy_animation/src/graph.rs b/crates/bevy_animation/src/graph.rs index 2507895bf04d5..e570d25ab15e3 100644 --- a/crates/bevy_animation/src/graph.rs +++ b/crates/bevy_animation/src/graph.rs @@ -1,7 +1,9 @@ //! The animation graph, which allows animations to be blended together. -use core::iter; -use core::ops::{Index, IndexMut, Range}; +use core::{ + iter, + ops::{Index, IndexMut, Range}, +}; use std::io::{self, Write}; use bevy_asset::{ @@ -420,7 +422,7 @@ impl AnimationGraph { Self { graph, root, - mask_groups: HashMap::new(), + mask_groups: HashMap::default(), } } diff --git a/crates/bevy_animation/src/lib.rs b/crates/bevy_animation/src/lib.rs index b782c8d709d1a..e03ad9a449982 100644 --- a/crates/bevy_animation/src/lib.rs +++ b/crates/bevy_animation/src/lib.rs @@ -45,9 +45,8 @@ use bevy_reflect::{prelude::ReflectDefault, Reflect, TypePath}; use bevy_time::Time; use bevy_transform::TransformSystem; use bevy_utils::{ - hashbrown::HashMap, tracing::{trace, warn}, - NoOpHash, PreHashMap, PreHashMapExt, TypeIdMap, + HashMap, NoOpHash, PreHashMap, PreHashMapExt, TypeIdMap, }; use petgraph::graph::NodeIndex; use serde::{Deserialize, Serialize}; diff --git a/crates/bevy_app/src/app.rs b/crates/bevy_app/src/app.rs index 4aad33c9d6cde..4ff12abd74a5b 100644 --- a/crates/bevy_app/src/app.rs +++ b/crates/bevy_app/src/app.rs @@ -124,7 +124,7 @@ impl App { Self { sub_apps: SubApps { main: SubApp::new(), - sub_apps: HashMap::new(), + sub_apps: HashMap::default(), }, runner: Box::new(run_once), } diff --git a/crates/bevy_asset/src/handle.rs b/crates/bevy_asset/src/handle.rs index 977a50b98be83..9c61ff0f88c7b 100644 --- a/crates/bevy_asset/src/handle.rs +++ b/crates/bevy_asset/src/handle.rs @@ -515,6 +515,8 @@ pub enum UntypedAssetConversionError { #[cfg(test)] mod tests { use bevy_reflect::PartialReflect; + use bevy_utils::FixedHasher; + use core::hash::BuildHasher; use super::*; @@ -525,9 +527,7 @@ mod tests { /// Simple utility to directly hash a value using a fixed hasher fn hash(data: &T) -> u64 { - let mut hasher = bevy_utils::AHasher::default(); - data.hash(&mut hasher); - hasher.finish() + FixedHasher.hash_one(data) } /// Typed and Untyped `Handles` should be equivalent to each other and themselves diff --git a/crates/bevy_asset/src/id.rs b/crates/bevy_asset/src/id.rs index 7e2abc50e330c..07a6d3db1209e 100644 --- a/crates/bevy_asset/src/id.rs +++ b/crates/bevy_asset/src/id.rs @@ -418,11 +418,9 @@ mod tests { /// Simple utility to directly hash a value using a fixed hasher fn hash(data: &T) -> u64 { - use core::hash::Hasher; + use core::hash::BuildHasher; - let mut hasher = bevy_utils::AHasher::default(); - data.hash(&mut hasher); - hasher.finish() + bevy_utils::FixedHasher.hash_one(data) } /// Typed and Untyped `AssetIds` should be equivalent to each other and themselves diff --git a/crates/bevy_asset/src/io/gated.rs b/crates/bevy_asset/src/io/gated.rs index cb205f12a81bd..388145a4686b0 100644 --- a/crates/bevy_asset/src/io/gated.rs +++ b/crates/bevy_asset/src/io/gated.rs @@ -44,7 +44,7 @@ impl GatedReader { /// Creates a new [`GatedReader`], which wraps the given `reader`. Also returns a [`GateOpener`] which /// can be used to open "path gates" for this [`GatedReader`]. pub fn new(reader: R) -> (Self, GateOpener) { - let gates = Arc::new(RwLock::new(HashMap::new())); + let gates = Arc::new(RwLock::new(HashMap::default())); ( Self { reader, diff --git a/crates/bevy_asset/src/io/source.rs b/crates/bevy_asset/src/io/source.rs index fe0d8df17f289..c0bab2037f8e3 100644 --- a/crates/bevy_asset/src/io/source.rs +++ b/crates/bevy_asset/src/io/source.rs @@ -343,7 +343,7 @@ impl AssetSourceBuilders { /// Builds a new [`AssetSources`] collection. If `watch` is true, the unprocessed sources will watch for changes. /// If `watch_processed` is true, the processed sources will watch for changes. pub fn build_sources(&mut self, watch: bool, watch_processed: bool) -> AssetSources { - let mut sources = HashMap::new(); + let mut sources = >::default(); for (id, source) in &mut self.sources { if let Some(data) = source.build( AssetSourceId::Name(id.clone_owned()), diff --git a/crates/bevy_asset/src/loader.rs b/crates/bevy_asset/src/loader.rs index 4cab51634f151..cbc5aac3c110c 100644 --- a/crates/bevy_asset/src/loader.rs +++ b/crates/bevy_asset/src/loader.rs @@ -153,7 +153,7 @@ pub struct LoadedAsset { impl LoadedAsset { /// Create a new loaded asset. This will use [`VisitAssetDependencies`](crate::VisitAssetDependencies) to populate `dependencies`. pub fn new_with_dependencies(value: A, meta: Option>) -> Self { - let mut dependencies = HashSet::new(); + let mut dependencies = >::default(); value.visit_dependencies(&mut |id| { dependencies.insert(id); }); diff --git a/crates/bevy_asset/src/server/info.rs b/crates/bevy_asset/src/server/info.rs index 3a38797fc83ce..898b3a76ec46f 100644 --- a/crates/bevy_asset/src/server/info.rs +++ b/crates/bevy_asset/src/server/info.rs @@ -395,10 +395,10 @@ impl AssetInfos { loaded_asset.value.insert(loaded_asset_id, world); let mut loading_deps = loaded_asset.dependencies; - let mut failed_deps = HashSet::new(); + let mut failed_deps = >::default(); let mut dep_error = None; let mut loading_rec_deps = loading_deps.clone(); - let mut failed_rec_deps = HashSet::new(); + let mut failed_rec_deps = >::default(); let mut rec_dep_error = None; loading_deps.retain(|dep_id| { if let Some(dep_info) = self.get_mut(*dep_id) { diff --git a/crates/bevy_asset/src/server/mod.rs b/crates/bevy_asset/src/server/mod.rs index 4365eeb1b30aa..6a2e475219041 100644 --- a/crates/bevy_asset/src/server/mod.rs +++ b/crates/bevy_asset/src/server/mod.rs @@ -1544,7 +1544,7 @@ pub fn handle_internal_asset_events(world: &mut World) { } }; - let mut paths_to_reload = HashSet::new(); + let mut paths_to_reload = >::default(); let mut handle_event = |source: AssetSourceId<'static>, event: AssetSourceEvent| { match event { // TODO: if the asset was processed and the processed file was changed, the first modified event diff --git a/crates/bevy_core/src/name.rs b/crates/bevy_core/src/name.rs index 8c00762199dfa..70e7a81cef4f0 100644 --- a/crates/bevy_core/src/name.rs +++ b/crates/bevy_core/src/name.rs @@ -7,9 +7,9 @@ use alloc::borrow::Cow; use bevy_reflect::std_traits::ReflectDefault; #[cfg(feature = "bevy_reflect")] use bevy_reflect::Reflect; -use bevy_utils::AHasher; +use bevy_utils::FixedHasher; use core::{ - hash::{Hash, Hasher}, + hash::{BuildHasher, Hash, Hasher}, ops::Deref, }; @@ -80,9 +80,7 @@ impl Name { } fn update_hash(&mut self) { - let mut hasher = AHasher::default(); - self.name.hash(&mut hasher); - self.hash = hasher.finish(); + self.hash = FixedHasher.hash_one(&self.name); } } diff --git a/crates/bevy_core_pipeline/src/core_2d/mod.rs b/crates/bevy_core_pipeline/src/core_2d/mod.rs index 0e9c064af68a9..d57134aa3ec07 100644 --- a/crates/bevy_core_pipeline/src/core_2d/mod.rs +++ b/crates/bevy_core_pipeline/src/core_2d/mod.rs @@ -33,8 +33,9 @@ pub mod graph { use core::ops::Range; use bevy_asset::UntypedAssetId; -use bevy_render::batching::gpu_preprocessing::GpuPreprocessingMode; -use bevy_render::render_phase::PhaseItemBinKey; +use bevy_render::{ + batching::gpu_preprocessing::GpuPreprocessingMode, render_phase::PhaseItemBinKey, +}; use bevy_utils::HashMap; pub use camera_2d::*; pub use main_opaque_pass_2d_node::*; @@ -44,7 +45,6 @@ use crate::{tonemapping::TonemappingNode, upscaling::UpscalingNode}; use bevy_app::{App, Plugin}; use bevy_ecs::{entity::EntityHashSet, prelude::*}; use bevy_math::FloatOrd; -use bevy_render::sync_world::MainEntity; use bevy_render::{ camera::{Camera, ExtractedCamera}, extract_component::ExtractComponentPlugin, @@ -59,7 +59,7 @@ use bevy_render::{ TextureFormat, TextureUsages, }, renderer::RenderDevice, - sync_world::RenderEntity, + sync_world::{MainEntity, RenderEntity}, texture::TextureCache, view::{Msaa, ViewDepthTexture}, Extract, ExtractSchedule, Render, RenderApp, RenderSet, @@ -423,7 +423,7 @@ pub fn prepare_core_2d_depth_textures( opaque_2d_phases: Res>, views_2d: Query<(Entity, &ExtractedCamera, &Msaa), (With,)>, ) { - let mut textures = HashMap::default(); + let mut textures = >::default(); for (view, camera, msaa) in &views_2d { if !opaque_2d_phases.contains_key(&view) || !transparent_2d_phases.contains_key(&view) { continue; diff --git a/crates/bevy_core_pipeline/src/core_3d/mod.rs b/crates/bevy_core_pipeline/src/core_3d/mod.rs index 909306dd4259c..d7e9b446e5fb3 100644 --- a/crates/bevy_core_pipeline/src/core_3d/mod.rs +++ b/crates/bevy_core_pipeline/src/core_3d/mod.rs @@ -65,10 +65,12 @@ pub const DEPTH_TEXTURE_SAMPLING_SUPPORTED: bool = true; use core::ops::Range; -use bevy_render::batching::gpu_preprocessing::{GpuPreprocessingMode, GpuPreprocessingSupport}; -use bevy_render::mesh::allocator::SlabId; -use bevy_render::render_phase::PhaseItemBinKey; -use bevy_render::view::GpuCulling; +use bevy_render::{ + batching::gpu_preprocessing::{GpuPreprocessingMode, GpuPreprocessingSupport}, + mesh::allocator::SlabId, + render_phase::PhaseItemBinKey, + view::GpuCulling, +}; pub use camera_3d::*; pub use main_opaque_pass_3d_node::*; pub use main_transparent_pass_3d_node::*; @@ -79,7 +81,6 @@ use bevy_color::LinearRgba; use bevy_ecs::{entity::EntityHashSet, prelude::*}; use bevy_image::{BevyDefault, Image}; use bevy_math::FloatOrd; -use bevy_render::sync_world::MainEntity; use bevy_render::{ camera::{Camera, ExtractedCamera}, extract_component::ExtractComponentPlugin, @@ -95,7 +96,7 @@ use bevy_render::{ TextureDescriptor, TextureDimension, TextureFormat, TextureUsages, TextureView, }, renderer::RenderDevice, - sync_world::RenderEntity, + sync_world::{MainEntity, RenderEntity}, texture::{ColorAttachment, TextureCache}, view::{ExtractedView, ViewDepthTexture, ViewTarget}, Extract, ExtractSchedule, Render, RenderApp, RenderSet, @@ -700,7 +701,7 @@ pub fn prepare_core_3d_depth_textures( &Msaa, )>, ) { - let mut render_target_usage = HashMap::default(); + let mut render_target_usage = >::default(); for (view, camera, depth_prepass, camera_3d, _msaa) in &views_3d { if !opaque_3d_phases.contains_key(&view) || !alpha_mask_3d_phases.contains_key(&view) @@ -722,7 +723,7 @@ pub fn prepare_core_3d_depth_textures( .or_insert_with(|| usage); } - let mut textures = HashMap::default(); + let mut textures = >::default(); for (entity, camera, _, camera_3d, msaa) in &views_3d { let Some(physical_target_size) = camera.physical_target_size else { continue; @@ -785,7 +786,7 @@ pub fn prepare_core_3d_transmission_textures( transparent_3d_phases: Res>, views_3d: Query<(Entity, &ExtractedCamera, &Camera3d, &ExtractedView)>, ) { - let mut textures = HashMap::default(); + let mut textures = >::default(); for (entity, camera, camera_3d, view) in &views_3d { if !opaque_3d_phases.contains_key(&entity) || !alpha_mask_3d_phases.contains_key(&entity) @@ -893,11 +894,11 @@ pub fn prepare_prepass_textures( Has, )>, ) { - let mut depth_textures = HashMap::default(); - let mut normal_textures = HashMap::default(); - let mut deferred_textures = HashMap::default(); - let mut deferred_lighting_id_textures = HashMap::default(); - let mut motion_vectors_textures = HashMap::default(); + let mut depth_textures = >::default(); + let mut normal_textures = >::default(); + let mut deferred_textures = >::default(); + let mut deferred_lighting_id_textures = >::default(); + let mut motion_vectors_textures = >::default(); for ( entity, camera, diff --git a/crates/bevy_core_pipeline/src/oit/mod.rs b/crates/bevy_core_pipeline/src/oit/mod.rs index c01b2a286e547..14e8b8d4e36e3 100644 --- a/crates/bevy_core_pipeline/src/oit/mod.rs +++ b/crates/bevy_core_pipeline/src/oit/mod.rs @@ -160,7 +160,7 @@ fn configure_depth_texture_usages( // Find all the render target that potentially uses OIT let primary_window = p.get_single().ok(); - let mut render_target_has_oit = HashSet::new(); + let mut render_target_has_oit = >::default(); for (camera, has_oit) in &cameras { if has_oit { render_target_has_oit.insert(camera.target.normalize(primary_window)); diff --git a/crates/bevy_core_pipeline/src/upscaling/mod.rs b/crates/bevy_core_pipeline/src/upscaling/mod.rs index b686d4484931c..52369fca59abc 100644 --- a/crates/bevy_core_pipeline/src/upscaling/mod.rs +++ b/crates/bevy_core_pipeline/src/upscaling/mod.rs @@ -43,7 +43,7 @@ fn prepare_view_upscaling_pipelines( blit_pipeline: Res, view_targets: Query<(Entity, &ViewTarget, Option<&ExtractedCamera>)>, ) { - let mut output_textures = HashSet::new(); + let mut output_textures = >::default(); for (entity, view_target, camera) in view_targets.iter() { let out_texture_id = view_target.out_texture().id(); let blend_state = if let Some(extracted_camera) = camera { diff --git a/crates/bevy_dev_tools/src/ui_debug_overlay/inset.rs b/crates/bevy_dev_tools/src/ui_debug_overlay/inset.rs index 1e52723d20d22..7c076a2c8aee7 100644 --- a/crates/bevy_dev_tools/src/ui_debug_overlay/inset.rs +++ b/crates/bevy_dev_tools/src/ui_debug_overlay/inset.rs @@ -52,7 +52,7 @@ struct DrawnLines { impl DrawnLines { fn new(width: f32) -> Self { DrawnLines { - lines: HashMap::new(), + lines: HashMap::default(), width, } } diff --git a/crates/bevy_diagnostic/src/diagnostic.rs b/crates/bevy_diagnostic/src/diagnostic.rs index ccd6e17df175d..c9fbe5d600eea 100644 --- a/crates/bevy_diagnostic/src/diagnostic.rs +++ b/crates/bevy_diagnostic/src/diagnostic.rs @@ -3,7 +3,7 @@ use core::hash::{Hash, Hasher}; use bevy_app::{App, SubApp}; use bevy_ecs::system::{Deferred, Res, Resource, SystemBuffer, SystemParam}; -use bevy_utils::{hashbrown::HashMap, Duration, Instant, PassHash}; +use bevy_utils::{Duration, HashMap, Instant, PassHash}; use const_fnv1a_hash::fnv1a_hash_str_64; use crate::DEFAULT_MAX_HISTORY_LENGTH; diff --git a/crates/bevy_ecs/src/archetype.rs b/crates/bevy_ecs/src/archetype.rs index 2c2241e29ec6d..022e550948d66 100644 --- a/crates/bevy_ecs/src/archetype.rs +++ b/crates/bevy_ecs/src/archetype.rs @@ -402,7 +402,7 @@ impl Archetype { // component in the `table_components` vector component_index .entry(component_id) - .or_insert_with(HashMap::new) + .or_default() .insert(id, ArchetypeRecord { column: Some(idx) }); } @@ -420,7 +420,7 @@ impl Archetype { ); component_index .entry(component_id) - .or_insert_with(HashMap::new) + .or_default() .insert(id, ArchetypeRecord { column: None }); } Self { diff --git a/crates/bevy_ecs/src/bundle.rs b/crates/bevy_ecs/src/bundle.rs index 333358240c23b..97833a1d7de59 100644 --- a/crates/bevy_ecs/src/bundle.rs +++ b/crates/bevy_ecs/src/bundle.rs @@ -381,7 +381,7 @@ impl BundleInfo { if deduped.len() != component_ids.len() { // TODO: Replace with `Vec::partition_dedup` once https://github.com/rust-lang/rust/issues/54279 is stabilized - let mut seen = HashSet::new(); + let mut seen = >::default(); let mut dups = Vec::new(); for id in component_ids { if !seen.insert(id) { @@ -1422,8 +1422,11 @@ impl Bundles { .or_insert_with(|| { let (id, storages) = initialize_dynamic_bundle(bundle_infos, components, Vec::from(component_ids)); - self.dynamic_bundle_storages - .insert_unique_unchecked(id, storages); + // SAFETY: The ID always increases when new bundles are added, and so, the ID is unique. + unsafe { + self.dynamic_bundle_storages + .insert_unique_unchecked(id, storages); + } (component_ids.into(), id) }); *bundle_id diff --git a/crates/bevy_ecs/src/entity/hash.rs b/crates/bevy_ecs/src/entity/hash.rs index 1b1ff531ffeb4..2e7c8ff2a3fc6 100644 --- a/crates/bevy_ecs/src/entity/hash.rs +++ b/crates/bevy_ecs/src/entity/hash.rs @@ -28,7 +28,8 @@ impl BuildHasher for EntityHash { /// /// 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. +/// try [`DefaultHasher`](bevy_utils::DefaultHasher) for a slower hash +/// computation but fewer lookup conflicts. #[derive(Debug, Default)] pub struct EntityHasher { hash: u64, diff --git a/crates/bevy_ecs/src/entity/visit_entities.rs b/crates/bevy_ecs/src/entity/visit_entities.rs index 79b5197d2ea79..abce76853d403 100644 --- a/crates/bevy_ecs/src/entity/visit_entities.rs +++ b/crates/bevy_ecs/src/entity/visit_entities.rs @@ -113,7 +113,7 @@ mod tests { let mut entity_map = EntityHashMap::::default(); let mut remapped = Foo { ordered: vec![], - unordered: HashSet::new(), + unordered: HashSet::default(), single: Entity::PLACEHOLDER, not_an_entity: foo.not_an_entity.clone(), }; diff --git a/crates/bevy_ecs/src/intern.rs b/crates/bevy_ecs/src/intern.rs index 179fdc8b82ad9..6668a2a9a6aed 100644 --- a/crates/bevy_ecs/src/intern.rs +++ b/crates/bevy_ecs/src/intern.rs @@ -164,8 +164,8 @@ impl Default for Interner { #[cfg(test)] mod tests { - use core::hash::{Hash, Hasher}; - use std::collections::hash_map::DefaultHasher; + use bevy_utils::FixedHasher; + use core::hash::{BuildHasher, Hash, Hasher}; use crate::intern::{Internable, Interned, Interner}; @@ -250,13 +250,8 @@ mod tests { assert_eq!(a, b); - let mut hasher = DefaultHasher::default(); - a.hash(&mut hasher); - let hash_a = hasher.finish(); - - let mut hasher = DefaultHasher::default(); - b.hash(&mut hasher); - let hash_b = hasher.finish(); + let hash_a = FixedHasher.hash_one(a); + let hash_b = FixedHasher.hash_one(b); assert_eq!(hash_a, hash_b); } diff --git a/crates/bevy_ecs/src/lib.rs b/crates/bevy_ecs/src/lib.rs index 85ff83c0aade0..c7def12de35d4 100644 --- a/crates/bevy_ecs/src/lib.rs +++ b/crates/bevy_ecs/src/lib.rs @@ -421,7 +421,7 @@ mod tests { let mut world = World::new(); let e = world.spawn((TableStored("abc"), A(123))).id(); let f = world.spawn((TableStored("def"), A(456), B(1))).id(); - let mut results = HashSet::new(); + let mut results = >::default(); world .query::<(Entity, &A)>() .iter(&world) @@ -598,7 +598,9 @@ mod tests { .collect::>(); assert_eq!( ents, - HashSet::from([(e, None, A(123)), (f, Some(SparseStored(1)), A(456))]) + [(e, None, A(123)), (f, Some(SparseStored(1)), A(456))] + .into_iter() + .collect::>() ); } @@ -630,7 +632,9 @@ mod tests { .iter(&world) .map(|(e, &i, &b)| (e, i, b)) .collect::>(), - HashSet::from([(e1, A(1), B(3)), (e2, A(2), B(4))]) + [(e1, A(1), B(3)), (e2, A(2), B(4))] + .into_iter() + .collect::>() ); assert_eq!(world.entity_mut(e1).take::(), Some(A(1))); assert_eq!( @@ -647,7 +651,9 @@ mod tests { .iter(&world) .map(|(e, &B(b), &TableStored(s))| (e, b, s)) .collect::>(), - HashSet::from([(e2, 4, "xyz"), (e1, 3, "abc")]) + [(e2, 4, "xyz"), (e1, 3, "abc")] + .into_iter() + .collect::>() ); world.entity_mut(e1).insert(A(43)); assert_eq!( @@ -656,7 +662,9 @@ mod tests { .iter(&world) .map(|(e, &i, &b)| (e, i, b)) .collect::>(), - HashSet::from([(e2, A(2), B(4)), (e1, A(43), B(3))]) + [(e2, A(2), B(4)), (e1, A(43), B(3))] + .into_iter() + .collect::>() ); world.entity_mut(e1).insert(C); assert_eq!( @@ -954,7 +962,7 @@ mod tests { assert_eq!( get_filtered::>(&mut world), - HashSet::from([e1, e3]) + [e1, e3].into_iter().collect::>() ); // ensure changing an entity's archetypes also moves its changed state @@ -962,7 +970,7 @@ mod tests { assert_eq!( get_filtered::>(&mut world), - HashSet::from([e3, e1]), + [e3, e1].into_iter().collect::>(), "changed entities list should not change" ); @@ -971,7 +979,7 @@ mod tests { assert_eq!( get_filtered::>(&mut world), - HashSet::from([e3, e1]), + [e3, e1].into_iter().collect::>(), "changed entities list should not change" ); @@ -979,7 +987,7 @@ mod tests { assert!(world.despawn(e2)); assert_eq!( get_filtered::>(&mut world), - HashSet::from([e3, e1]), + [e3, e1].into_iter().collect::>(), "changed entities list should not change" ); @@ -987,7 +995,7 @@ mod tests { assert!(world.despawn(e1)); assert_eq!( get_filtered::>(&mut world), - HashSet::from([e3]), + [e3].into_iter().collect::>(), "e1 should no longer be returned" ); @@ -998,11 +1006,20 @@ mod tests { let e4 = world.spawn_empty().id(); world.entity_mut(e4).insert(A(0)); - assert_eq!(get_filtered::>(&mut world), HashSet::from([e4])); - assert_eq!(get_filtered::>(&mut world), HashSet::from([e4])); + assert_eq!( + get_filtered::>(&mut world), + [e4].into_iter().collect::>() + ); + assert_eq!( + get_filtered::>(&mut world), + [e4].into_iter().collect::>() + ); world.entity_mut(e4).insert(A(1)); - assert_eq!(get_filtered::>(&mut world), HashSet::from([e4])); + assert_eq!( + get_filtered::>(&mut world), + [e4].into_iter().collect::>() + ); world.clear_trackers(); @@ -1011,9 +1028,18 @@ mod tests { world.entity_mut(e4).insert((A(0), B(0))); assert!(get_filtered::>(&mut world).is_empty()); - assert_eq!(get_filtered::>(&mut world), HashSet::from([e4])); - assert_eq!(get_filtered::>(&mut world), HashSet::from([e4])); - assert_eq!(get_filtered::>(&mut world), HashSet::from([e4])); + assert_eq!( + get_filtered::>(&mut world), + [e4].into_iter().collect::>() + ); + assert_eq!( + get_filtered::>(&mut world), + [e4].into_iter().collect::>() + ); + assert_eq!( + get_filtered::>(&mut world), + [e4].into_iter().collect::>() + ); } #[test] @@ -1045,19 +1071,19 @@ mod tests { assert_eq!( get_filtered::>(&mut world), - HashSet::from([e1, e3]) + [e1, e3].into_iter().collect::>() ); // ensure changing an entity's archetypes also moves its changed state world.entity_mut(e1).insert(C); - assert_eq!(get_filtered::>(&mut world), HashSet::from([e3, e1]), "changed entities list should not change (although the order will due to archetype moves)"); + assert_eq!(get_filtered::>(&mut world), [e3, e1].into_iter().collect::>(), "changed entities list should not change (although the order will due to archetype moves)"); // spawning a new SparseStored entity should not change existing changed state world.entity_mut(e1).insert(SparseStored(0)); assert_eq!( get_filtered::>(&mut world), - HashSet::from([e3, e1]), + [e3, e1].into_iter().collect::>(), "changed entities list should not change" ); @@ -1065,7 +1091,7 @@ mod tests { assert!(world.despawn(e2)); assert_eq!( get_filtered::>(&mut world), - HashSet::from([e3, e1]), + [e3, e1].into_iter().collect::>(), "changed entities list should not change" ); @@ -1073,7 +1099,7 @@ mod tests { assert!(world.despawn(e1)); assert_eq!( get_filtered::>(&mut world), - HashSet::from([e3]), + [e3].into_iter().collect::>(), "e1 should no longer be returned" ); @@ -1086,17 +1112,17 @@ mod tests { world.entity_mut(e4).insert(SparseStored(0)); assert_eq!( get_filtered::>(&mut world), - HashSet::from([e4]) + [e4].into_iter().collect::>() ); assert_eq!( get_filtered::>(&mut world), - HashSet::from([e4]) + [e4].into_iter().collect::>() ); world.entity_mut(e4).insert(A(1)); assert_eq!( get_filtered::>(&mut world), - HashSet::from([e4]) + [e4].into_iter().collect::>() ); world.clear_trackers(); @@ -1108,7 +1134,7 @@ mod tests { assert!(get_filtered::>(&mut world).is_empty()); assert_eq!( get_filtered::>(&mut world), - HashSet::from([e4]) + [e4].into_iter().collect::>() ); } @@ -1292,7 +1318,12 @@ mod tests { .iter(&world) .map(|(a, b)| (a.0, b.0)) .collect::>(); - assert_eq!(results, HashSet::from([(1, "1"), (2, "2"), (3, "3"),])); + assert_eq!( + results, + [(1, "1"), (2, "2"), (3, "3"),] + .into_iter() + .collect::>() + ); let removed_bundle = world.entity_mut(e2).take::<(B, TableStored)>().unwrap(); assert_eq!(removed_bundle, (B(2), TableStored("2"))); @@ -1301,11 +1332,14 @@ mod tests { .iter(&world) .map(|(a, b)| (a.0, b.0)) .collect::>(); - assert_eq!(results, HashSet::from([(1, "1"), (3, "3"),])); + assert_eq!( + results, + [(1, "1"), (3, "3"),].into_iter().collect::>() + ); let mut a_query = world.query::<&A>(); let results = a_query.iter(&world).map(|a| a.0).collect::>(); - assert_eq!(results, HashSet::from([1, 3, 2])); + assert_eq!(results, [1, 3, 2].into_iter().collect::>()); let entity_ref = world.entity(e2); assert_eq!( diff --git a/crates/bevy_ecs/src/schedule/graph/graph_map.rs b/crates/bevy_ecs/src/schedule/graph/graph_map.rs index 680774bce5f4d..1b00698fc192a 100644 --- a/crates/bevy_ecs/src/schedule/graph/graph_map.rs +++ b/crates/bevy_ecs/src/schedule/graph/graph_map.rs @@ -4,10 +4,10 @@ //! //! [`petgraph`]: https://docs.rs/petgraph/0.6.5/petgraph/ -use bevy_utils::{hashbrown::HashSet, AHasher}; +use bevy_utils::{hashbrown::HashSet, FixedHasher}; use core::{ fmt, - hash::{BuildHasher, BuildHasherDefault, Hash}, + hash::{BuildHasher, Hash}, }; use indexmap::IndexMap; use smallvec::SmallVec; @@ -20,13 +20,13 @@ use Direction::{Incoming, Outgoing}; /// /// For example, an edge between *1* and *2* is equivalent to an edge between /// *2* and *1*. -pub type UnGraph> = Graph; +pub type UnGraph = Graph; /// A `Graph` with directed edges. /// /// For example, an edge from *1* to *2* is distinct from an edge from *2* to /// *1*. -pub type DiGraph> = Graph; +pub type DiGraph = Graph; /// `Graph` is a graph datastructure using an associative array /// of its node weights `NodeId`. @@ -45,7 +45,7 @@ pub type DiGraph> = Graph; /// /// `Graph` does not allow parallel edges, but self loops are allowed. #[derive(Clone)] -pub struct Graph> +pub struct Graph where S: BuildHasher, { @@ -63,14 +63,6 @@ impl Graph where S: BuildHasher, { - /// Create a new `Graph` - pub(crate) fn new() -> Self - where - S: Default, - { - Self::default() - } - /// Create a new `Graph` with estimated capacity. pub(crate) fn with_capacity(nodes: usize, edges: usize) -> Self where @@ -274,7 +266,7 @@ where } } -impl Graph { +impl DiGraph { /// Iterate over all *Strongly Connected Components* in this graph. pub(crate) fn iter_sccs(&self) -> impl Iterator> + '_ { super::tarjan_scc::new_tarjan_scc(self) @@ -408,7 +400,7 @@ mod tests { fn node_order_preservation() { use NodeId::System; - let mut graph = Graph::::new(); + let mut graph = ::default(); graph.add_node(System(1)); graph.add_node(System(2)); @@ -450,7 +442,7 @@ mod tests { fn strongly_connected_components() { use NodeId::System; - let mut graph = Graph::::new(); + let mut graph = ::default(); graph.add_edge(System(1), System(2)); graph.add_edge(System(2), System(1)); diff --git a/crates/bevy_ecs/src/schedule/graph/mod.rs b/crates/bevy_ecs/src/schedule/graph/mod.rs index 553be0bc195a3..1532184f1761e 100644 --- a/crates/bevy_ecs/src/schedule/graph/mod.rs +++ b/crates/bevy_ecs/src/schedule/graph/mod.rs @@ -1,10 +1,8 @@ -use alloc::vec; -use alloc::vec::Vec; +use alloc::{vec, vec::Vec}; use core::fmt::Debug; -use core::hash::BuildHasherDefault; use smallvec::SmallVec; -use bevy_utils::{AHasher, HashMap, HashSet}; +use bevy_utils::{HashMap, HashSet}; use fixedbitset::FixedBitSet; use crate::schedule::set::*; @@ -96,11 +94,11 @@ impl Default for CheckGraphResults { fn default() -> Self { Self { reachable: FixedBitSet::new(), - connected: HashSet::new(), + connected: HashSet::default(), disconnected: Vec::new(), transitive_edges: Vec::new(), - transitive_reduction: DiGraph::new(), - transitive_closure: DiGraph::new(), + transitive_reduction: DiGraph::default(), + transitive_closure: DiGraph::default(), } } } @@ -124,8 +122,8 @@ pub(crate) fn check_graph(graph: &DiGraph, topological_order: &[NodeId]) -> Chec let n = graph.node_count(); // build a copy of the graph where the nodes and edges appear in topsorted order - let mut map = HashMap::with_capacity(n); - let mut topsorted = DiGraph::>::new(); + let mut map = >::with_capacity_and_hasher(n, Default::default()); + let mut topsorted = ::default(); // iterate nodes in topological order for (i, &node) in topological_order.iter().enumerate() { map.insert(node, i); @@ -137,12 +135,12 @@ pub(crate) fn check_graph(graph: &DiGraph, topological_order: &[NodeId]) -> Chec } let mut reachable = FixedBitSet::with_capacity(n * n); - let mut connected = HashSet::new(); + let mut connected = >::default(); let mut disconnected = Vec::new(); let mut transitive_edges = Vec::new(); - let mut transitive_reduction = DiGraph::new(); - let mut transitive_closure = DiGraph::new(); + let mut transitive_reduction = DiGraph::default(); + let mut transitive_closure = DiGraph::default(); let mut visited = FixedBitSet::with_capacity(n); @@ -227,7 +225,7 @@ pub fn simple_cycles_in_component(graph: &DiGraph, scc: &[NodeId]) -> Vec>::new(); + let mut subgraph = ::default(); for &node in &scc { subgraph.add_node(node); } @@ -243,16 +241,17 @@ pub fn simple_cycles_in_component(graph: &DiGraph, scc: &[NodeId]) -> Vec = + HashSet::with_capacity_and_hasher(subgraph.node_count(), Default::default()); // connects nodes along path segments that can't be part of a cycle (given current root) // those nodes can be unblocked at the same time let mut unblock_together: HashMap> = - HashMap::with_capacity(subgraph.node_count()); + HashMap::with_capacity_and_hasher(subgraph.node_count(), Default::default()); // stack for unblocking nodes let mut unblock_stack = Vec::with_capacity(subgraph.node_count()); // nodes can be involved in multiple cycles let mut maybe_in_more_cycles: HashSet = - HashSet::with_capacity(subgraph.node_count()); + HashSet::with_capacity_and_hasher(subgraph.node_count(), Default::default()); // stack for DFS let mut stack = Vec::with_capacity(subgraph.node_count()); diff --git a/crates/bevy_ecs/src/schedule/schedule.rs b/crates/bevy_ecs/src/schedule/schedule.rs index 449b609a28ff0..e9781cec568da 100644 --- a/crates/bevy_ecs/src/schedule/schedule.rs +++ b/crates/bevy_ecs/src/schedule/schedule.rs @@ -1,13 +1,12 @@ use alloc::collections::BTreeSet; use core::fmt::{Debug, Write}; -use core::hash::BuildHasherDefault; #[cfg(feature = "trace")] use bevy_utils::tracing::info_span; use bevy_utils::{ default, tracing::{error, info, warn}, - AHasher, HashMap, HashSet, + HashMap, HashSet, }; use disqualified::ShortName; use fixedbitset::FixedBitSet; @@ -39,7 +38,7 @@ impl Schedules { /// Constructs an empty `Schedules` with zero initial capacity. pub fn new() -> Self { Self { - inner: HashMap::new(), + inner: HashMap::default(), ignored_scheduling_ambiguities: BTreeSet::new(), } } @@ -516,7 +515,7 @@ impl Schedule { #[derive(Default)] pub struct Dag { /// A directed graph. - graph: DiGraph>, + graph: DiGraph, /// A cached topological ordering of the graph. topsort: Vec, } @@ -524,7 +523,7 @@ pub struct Dag { impl Dag { fn new() -> Self { Self { - graph: DiGraph::new(), + graph: DiGraph::default(), topsort: Vec::new(), } } @@ -609,7 +608,7 @@ pub struct ScheduleGraph { hierarchy: Dag, /// Directed acyclic graph of the dependency (which systems/sets have to run before which other systems/sets) dependency: Dag, - ambiguous_with: UnGraph>, + ambiguous_with: UnGraph, ambiguous_with_all: HashSet, conflicting_systems: Vec<(NodeId, NodeId, Vec)>, anonymous_sets: usize, @@ -628,18 +627,18 @@ impl ScheduleGraph { system_conditions: Vec::new(), system_sets: Vec::new(), system_set_conditions: Vec::new(), - system_set_ids: HashMap::new(), + system_set_ids: HashMap::default(), uninit: Vec::new(), hierarchy: Dag::new(), dependency: Dag::new(), - ambiguous_with: UnGraph::new(), - ambiguous_with_all: HashSet::new(), + ambiguous_with: UnGraph::default(), + ambiguous_with_all: HashSet::default(), conflicting_systems: Vec::new(), anonymous_sets: 0, changed: false, settings: default(), no_sync_edges: BTreeSet::new(), - auto_sync_node_ids: HashMap::new(), + auto_sync_node_ids: HashMap::default(), } } @@ -1154,7 +1153,8 @@ impl ScheduleGraph { // calculate the number of sync points each sync point is from the beginning of the graph // use the same sync point if the distance is the same - let mut distances: HashMap> = HashMap::with_capacity(topo.len()); + let mut distances: HashMap> = + HashMap::with_capacity_and_hasher(topo.len(), Default::default()); for node in &topo { let add_sync_after = self.systems[node.index()].get().unwrap().has_deferred(); @@ -1231,8 +1231,9 @@ impl ScheduleGraph { hierarchy_graph: &DiGraph, ) -> (HashMap>, HashMap) { let mut set_systems: HashMap> = - HashMap::with_capacity(self.system_sets.len()); - let mut set_system_bitsets = HashMap::with_capacity(self.system_sets.len()); + HashMap::with_capacity_and_hasher(self.system_sets.len(), Default::default()); + let mut set_system_bitsets = + HashMap::with_capacity_and_hasher(self.system_sets.len(), Default::default()); for &id in hierarchy_topsort.iter().rev() { if id.is_system() { continue; @@ -1311,7 +1312,7 @@ impl ScheduleGraph { } fn get_ambiguous_with_flattened(&self, set_systems: &HashMap>) -> UnGraph { - let mut ambiguous_with_flattened = UnGraph::new(); + let mut ambiguous_with_flattened = UnGraph::default(); for (lhs, rhs) in self.ambiguous_with.all_edges() { match (lhs, rhs) { (NodeId::System(_), NodeId::System(_)) => { @@ -1919,7 +1920,7 @@ impl ScheduleGraph { } fn names_of_sets_containing_node(&self, id: &NodeId) -> Vec { - let mut sets = HashSet::new(); + let mut sets = >::default(); self.traverse_sets_containing_node(*id, &mut |set_id| { !self.system_sets[set_id.index()].is_system_type() && sets.insert(set_id) }); diff --git a/crates/bevy_ecs/src/world/entity_ref.rs b/crates/bevy_ecs/src/world/entity_ref.rs index 0ac19e312b878..22a84f69f9134 100644 --- a/crates/bevy_ecs/src/world/entity_ref.rs +++ b/crates/bevy_ecs/src/world/entity_ref.rs @@ -728,7 +728,7 @@ impl<'w> EntityMut<'w> { /// let mut entity_mut = world.entity_mut(entity); /// let mut ptrs = entity_mut.get_mut_by_id(&HashSet::from_iter([x_id, y_id])) /// # .unwrap(); - /// # let [mut x_ptr, mut y_ptr] = ptrs.get_many_mut([&x_id, &y_id]).unwrap(); + /// # let [Some(mut x_ptr), Some(mut y_ptr)] = ptrs.get_many_mut([&x_id, &y_id]) else { unreachable!() }; /// # assert_eq!((unsafe { x_ptr.as_mut().deref_mut::() }, unsafe { y_ptr.as_mut().deref_mut::() }), (&mut X(42), &mut Y(10))); /// ``` #[inline] @@ -3656,7 +3656,7 @@ unsafe impl DynamicComponentFetch for &'_ HashSet { self, cell: UnsafeEntityCell<'_>, ) -> Result, EntityComponentError> { - let mut ptrs = HashMap::with_capacity(self.len()); + let mut ptrs = HashMap::with_capacity_and_hasher(self.len(), Default::default()); for &id in self { ptrs.insert( id, @@ -3671,7 +3671,7 @@ unsafe impl DynamicComponentFetch for &'_ HashSet { self, cell: UnsafeEntityCell<'_>, ) -> Result, EntityComponentError> { - let mut ptrs = HashMap::with_capacity(self.len()); + let mut ptrs = HashMap::with_capacity_and_hasher(self.len(), Default::default()); for &id in self { ptrs.insert( id, diff --git a/crates/bevy_ecs/src/world/mod.rs b/crates/bevy_ecs/src/world/mod.rs index 5152e549a8ee4..c2a5199f86281 100644 --- a/crates/bevy_ecs/src/world/mod.rs +++ b/crates/bevy_ecs/src/world/mod.rs @@ -1235,8 +1235,7 @@ impl World { /// # use bevy_ecs::prelude::*; /// # use bevy_ecs::entity::EntityHash; /// # use bevy_ecs::entity::EntityHashSet; - /// # use bevy_utils::hashbrown::HashSet; - /// # use bevy_utils::hashbrown::hash_map::DefaultHashBuilder; + /// # use bevy_utils::HashSet; /// # let mut world = World::new(); /// # let id1 = world.spawn_empty().id(); /// # let id2 = world.spawn_empty().id(); @@ -3462,7 +3461,7 @@ impl World { /// // probably use something like `ReflectFromPtr` in a real-world scenario. /// /// // Create the hash map that will store the closures for each resource type - /// let mut closures: HashMap)>> = HashMap::new(); + /// let mut closures: HashMap)>> = HashMap::default(); /// /// // Add closure for `A` /// closures.insert(TypeId::of::(), Box::new(|ptr| { @@ -3539,7 +3538,7 @@ impl World { /// // probably use something like `ReflectFromPtr` in a real-world scenario. /// /// // Create the hash map that will store the mutator closures for each resource type - /// let mut mutators: HashMap)>> = HashMap::new(); + /// let mut mutators: HashMap)>> = HashMap::default(); /// /// // Add mutator closure for `A` /// mutators.insert(TypeId::of::(), Box::new(|mut_untyped| { @@ -4299,38 +4298,46 @@ mod tests { let baz_id = TypeId::of::(); assert_eq!( to_type_ids(world.inspect_entity(ent0).collect()), - [Some(foo_id), Some(bar_id), Some(baz_id)].into() + [Some(foo_id), Some(bar_id), Some(baz_id)] + .into_iter() + .collect::>() ); assert_eq!( to_type_ids(world.inspect_entity(ent1).collect()), - [Some(foo_id), Some(bar_id)].into() + [Some(foo_id), Some(bar_id)] + .into_iter() + .collect::>() ); assert_eq!( to_type_ids(world.inspect_entity(ent2).collect()), - [Some(bar_id), Some(baz_id)].into() + [Some(bar_id), Some(baz_id)] + .into_iter() + .collect::>() ); assert_eq!( to_type_ids(world.inspect_entity(ent3).collect()), - [Some(foo_id), Some(baz_id)].into() + [Some(foo_id), Some(baz_id)] + .into_iter() + .collect::>() ); assert_eq!( to_type_ids(world.inspect_entity(ent4).collect()), - [Some(foo_id)].into() + [Some(foo_id)].into_iter().collect::>() ); assert_eq!( to_type_ids(world.inspect_entity(ent5).collect()), - [Some(bar_id)].into() + [Some(bar_id)].into_iter().collect::>() ); assert_eq!( to_type_ids(world.inspect_entity(ent6).collect()), - [Some(baz_id)].into() + [Some(baz_id)].into_iter().collect::>() ); } #[test] fn iterate_entities() { let mut world = World::new(); - let mut entity_counters = HashMap::new(); + let mut entity_counters = >::default(); let iterate_and_count_entities = |world: &World, entity_counters: &mut HashMap<_, _>| { entity_counters.clear(); diff --git a/crates/bevy_gltf/src/loader.rs b/crates/bevy_gltf/src/loader.rs index f3c0a4d9fb470..319bfa7590e72 100644 --- a/crates/bevy_gltf/src/loader.rs +++ b/crates/bevy_gltf/src/loader.rs @@ -217,7 +217,7 @@ async fn load_gltf<'a, 'b, 'c>( .to_string(); let buffer_data = load_buffers(&gltf, load_context).await?; - let mut linear_textures = HashSet::default(); + let mut linear_textures = >::default(); for material in gltf.materials() { if let Some(texture) = material.normal_texture() { @@ -259,11 +259,11 @@ async fn load_gltf<'a, 'b, 'c>( #[cfg(feature = "bevy_animation")] let paths = { - let mut paths = HashMap::)>::new(); + let mut paths = HashMap::)>::default(); for scene in gltf.scenes() { for node in scene.nodes() { let root_index = node.index(); - paths_recur(node, &[], &mut paths, root_index, &mut HashSet::new()); + paths_recur(node, &[], &mut paths, root_index, &mut HashSet::default()); } } paths @@ -272,12 +272,14 @@ async fn load_gltf<'a, 'b, 'c>( #[cfg(feature = "bevy_animation")] let (animations, named_animations, animation_roots) = { use bevy_animation::{animated_field, animation_curves::*, gltf_curves::*, VariableCurve}; - use bevy_math::curve::{ConstantCurve, Interval, UnevenSampleAutoCurve}; - use bevy_math::{Quat, Vec4}; + use bevy_math::{ + curve::{ConstantCurve, Interval, UnevenSampleAutoCurve}, + Quat, Vec4, + }; use gltf::animation::util::ReadOutputs; let mut animations = vec![]; - let mut named_animations = HashMap::default(); - let mut animation_roots = HashSet::default(); + let mut named_animations = >::default(); + let mut animation_roots = >::default(); for animation in gltf.animations() { let mut animation_clip = AnimationClip::default(); for channel in animation.channels() { @@ -603,7 +605,7 @@ async fn load_gltf<'a, 'b, 'c>( } let mut materials = vec![]; - let mut named_materials = HashMap::default(); + let mut named_materials = >::default(); // Only include materials in the output if they're set to be retained in the MAIN_WORLD and/or RENDER_WORLD by the load_materials flag if !settings.load_materials.is_empty() { // NOTE: materials must be loaded after textures because image load() calls will happen before load_with_settings, preventing is_srgb from being set properly @@ -616,9 +618,9 @@ async fn load_gltf<'a, 'b, 'c>( } } let mut meshes = vec![]; - let mut named_meshes = HashMap::default(); - let mut meshes_on_skinned_nodes = HashSet::default(); - let mut meshes_on_non_skinned_nodes = HashSet::default(); + let mut named_meshes = >::default(); + let mut meshes_on_skinned_nodes = >::default(); + let mut meshes_on_non_skinned_nodes = >::default(); for gltf_node in gltf.nodes() { if gltf_node.skin().is_some() { if let Some(mesh) = gltf_node.mesh() { @@ -783,10 +785,10 @@ async fn load_gltf<'a, 'b, 'c>( }) .collect(); - let mut nodes = HashMap::>::new(); - let mut named_nodes = HashMap::new(); + let mut nodes = HashMap::>::default(); + let mut named_nodes = >::default(); let mut skins = vec![]; - let mut named_skins = HashMap::default(); + let mut named_skins = >::default(); for node in GltfTreeIterator::try_new(&gltf)? { let skin = node.skin().map(|skin| { let joints = skin @@ -848,12 +850,12 @@ async fn load_gltf<'a, 'b, 'c>( .collect(); let mut scenes = vec![]; - let mut named_scenes = HashMap::default(); + let mut named_scenes = >::default(); let mut active_camera_found = false; for scene in gltf.scenes() { let mut err = None; let mut world = World::default(); - let mut node_index_to_entity_map = HashMap::new(); + let mut node_index_to_entity_map = >::default(); let mut entity_to_skin_index_map = EntityHashMap::default(); let mut scene_load_context = load_context.begin_labeled_asset(); @@ -1904,7 +1906,7 @@ impl<'a> GltfTreeIterator<'a> { .collect::>(); let mut nodes = Vec::new(); - let mut warned_about_max_joints = HashSet::new(); + let mut warned_about_max_joints = >::default(); while let Some(index) = empty_children.pop_front() { if let Some(skin) = unprocessed_nodes.get(&index).unwrap().0.skin() { if skin.joints().len() > MAX_JOINTS && warned_about_max_joints.insert(skin.index()) diff --git a/crates/bevy_mesh/src/primitives/dim2.rs b/crates/bevy_mesh/src/primitives/dim2.rs index 72a304c6994a3..3eda19eed9037 100644 --- a/crates/bevy_mesh/src/primitives/dim2.rs +++ b/crates/bevy_mesh/src/primitives/dim2.rs @@ -1059,7 +1059,7 @@ mod tests { use crate::{Mesh, MeshBuilder, Meshable, VertexAttributeValues}; fn count_distinct_positions(points: &[[f32; 3]]) -> usize { - let mut map = HashSet::new(); + let mut map = >::default(); for point in points { map.insert(point.map(FloatOrd)); } diff --git a/crates/bevy_pbr/src/cluster/mod.rs b/crates/bevy_pbr/src/cluster/mod.rs index bbab0dff08b55..41932a2aaadc1 100644 --- a/crates/bevy_pbr/src/cluster/mod.rs +++ b/crates/bevy_pbr/src/cluster/mod.rs @@ -24,7 +24,7 @@ use bevy_render::{ sync_world::RenderEntity, Extract, }; -use bevy_utils::{hashbrown::HashSet, tracing::warn}; +use bevy_utils::{tracing::warn, HashSet}; pub(crate) use crate::cluster::assign::assign_objects_to_clusters; use crate::MeshPipeline; diff --git a/crates/bevy_pbr/src/light_probe/mod.rs b/crates/bevy_pbr/src/light_probe/mod.rs index 5391d75c862d3..f5516e413bab0 100644 --- a/crates/bevy_pbr/src/light_probe/mod.rs +++ b/crates/bevy_pbr/src/light_probe/mod.rs @@ -631,7 +631,7 @@ where fn new() -> RenderViewLightProbes { RenderViewLightProbes { binding_index_to_textures: vec![], - cubemap_to_binding_index: HashMap::new(), + cubemap_to_binding_index: HashMap::default(), render_light_probes: vec![], view_light_probe_info: C::ViewLightProbeInfo::default(), } diff --git a/crates/bevy_pbr/src/material_bind_groups.rs b/crates/bevy_pbr/src/material_bind_groups.rs index 4122068229a9e..ab3f4b464f81e 100644 --- a/crates/bevy_pbr/src/material_bind_groups.rs +++ b/crates/bevy_pbr/src/material_bind_groups.rs @@ -23,10 +23,7 @@ use bevy_render::{ texture::FallbackImage, }; use bevy_utils::{default, tracing::error, HashMap}; -use core::any; -use core::iter; -use core::marker::PhantomData; -use core::num::NonZero; +use core::{any, iter, marker::PhantomData, num::NonZero}; /// An object that creates and stores bind groups for a single material type. /// @@ -818,7 +815,7 @@ impl MaterialFallbackBuffers { render_device: &RenderDevice, bind_group_layout_entries: &[BindGroupLayoutEntry], ) -> MaterialFallbackBuffers { - let mut fallback_buffers = HashMap::new(); + let mut fallback_buffers = HashMap::default(); for bind_group_layout_entry in bind_group_layout_entries { // Create a dummy buffer of the appropriate size. let BindingType::Buffer { diff --git a/crates/bevy_pbr/src/meshlet/from_mesh.rs b/crates/bevy_pbr/src/meshlet/from_mesh.rs index 7a5365296759d..14b46e55ba46e 100644 --- a/crates/bevy_pbr/src/meshlet/from_mesh.rs +++ b/crates/bevy_pbr/src/meshlet/from_mesh.rs @@ -273,7 +273,7 @@ fn find_connected_meshlets( } // For each meshlet pair, count how many vertices they share - let mut meshlet_pair_to_shared_vertex_count = HashMap::new(); + let mut meshlet_pair_to_shared_vertex_count = >::default(); for vertex_meshlet_ids in vertices_to_meshlets { for (meshlet_queue_id1, meshlet_queue_id2) in vertex_meshlet_ids.into_iter().tuple_combinations() diff --git a/crates/bevy_pbr/src/meshlet/instance_manager.rs b/crates/bevy_pbr/src/meshlet/instance_manager.rs index fcc06c72f5140..c190d7ea367b0 100644 --- a/crates/bevy_pbr/src/meshlet/instance_manager.rs +++ b/crates/bevy_pbr/src/meshlet/instance_manager.rs @@ -76,8 +76,8 @@ impl InstanceManager { view_instance_visibility: EntityHashMap::default(), next_material_id: 0, - material_id_lookup: HashMap::new(), - material_ids_present_in_scene: HashSet::new(), + material_id_lookup: HashMap::default(), + material_ids_present_in_scene: HashSet::default(), } } diff --git a/crates/bevy_pbr/src/meshlet/meshlet_mesh_manager.rs b/crates/bevy_pbr/src/meshlet/meshlet_mesh_manager.rs index 4170ac6279446..4cae0d50d19f5 100644 --- a/crates/bevy_pbr/src/meshlet/meshlet_mesh_manager.rs +++ b/crates/bevy_pbr/src/meshlet/meshlet_mesh_manager.rs @@ -47,7 +47,7 @@ impl FromWorld for MeshletMeshManager { "meshlet_simplification_errors", render_device, ), - meshlet_mesh_slices: HashMap::new(), + meshlet_mesh_slices: HashMap::default(), } } } diff --git a/crates/bevy_pbr/src/render/mesh.rs b/crates/bevy_pbr/src/render/mesh.rs index 29f878522e3a3..c0f3db33d5f3e 100644 --- a/crates/bevy_pbr/src/render/mesh.rs +++ b/crates/bevy_pbr/src/render/mesh.rs @@ -932,11 +932,13 @@ impl RenderMeshInstanceGpuBuilder { // Write in the new mesh input uniform. current_input_buffer.set(current_uniform_index, mesh_input_uniform); - occupied_entry.replace_entry(RenderMeshInstanceGpu { - translation: self.world_from_local.translation, - shared: self.shared, - current_uniform_index: NonMaxU32::new(current_uniform_index) - .unwrap_or_default(), + occupied_entry.replace_entry_with(|_, _| { + Some(RenderMeshInstanceGpu { + translation: self.world_from_local.translation, + shared: self.shared, + current_uniform_index: NonMaxU32::new(current_uniform_index) + .unwrap_or_default(), + }) }); } @@ -1124,7 +1126,7 @@ pub fn extract_meshes_for_cpu_building( render_mesh_instances.clear(); for queue in render_mesh_instance_queues.iter_mut() { for (entity, render_mesh_instance) in queue.drain(..) { - render_mesh_instances.insert_unique_unchecked(entity.into(), render_mesh_instance); + render_mesh_instances.insert(entity.into(), render_mesh_instance); } } } diff --git a/crates/bevy_picking/src/focus.rs b/crates/bevy_picking/src/focus.rs index d07c0c095f4bc..8c3246d96ea9a 100644 --- a/crates/bevy_picking/src/focus.rs +++ b/crates/bevy_picking/src/focus.rs @@ -226,7 +226,7 @@ pub fn update_interactions( // need to be able to insert the interaction component on entities if they do not exist. To do // so we need to know the final aggregated interaction state to avoid the scenario where we set // an entity to `Pressed`, then overwrite that with a lower precedent like `Hovered`. - let mut new_interaction_state = HashMap::::new(); + let mut new_interaction_state = HashMap::::default(); for (pointer, pointer_press, mut pointer_interaction) in &mut pointers { if let Some(pointers_hovered_entities) = hover_map.get(pointer) { // Insert a sorted list of hit entities into the pointer's interaction component. diff --git a/crates/bevy_reflect/Cargo.toml b/crates/bevy_reflect/Cargo.toml index 010b5a7298855..5879c1cac7de8 100644 --- a/crates/bevy_reflect/Cargo.toml +++ b/crates/bevy_reflect/Cargo.toml @@ -45,6 +45,9 @@ bevy_utils = { path = "../bevy_utils", version = "0.15.0-dev", default-features ] } bevy_ptr = { path = "../bevy_ptr", version = "0.15.0-dev" } +# used by bevy-utils, but it also needs reflect impls +foldhash = { version = "0.1.3", default-features = false } + # other erased-serde = { version = "0.4", default-features = false, features = [ "alloc", diff --git a/crates/bevy_reflect/derive/src/serialization.rs b/crates/bevy_reflect/derive/src/serialization.rs index 3cfe0adc74451..75df7b7b930b2 100644 --- a/crates/bevy_reflect/derive/src/serialization.rs +++ b/crates/bevy_reflect/derive/src/serialization.rs @@ -24,7 +24,7 @@ impl SerializationDataDef { fields: &[StructField<'_>], bevy_reflect_path: &Path, ) -> Result, syn::Error> { - let mut skipped = HashMap::default(); + let mut skipped = >::default(); for field in fields { match field.attrs.ignore { diff --git a/crates/bevy_reflect/src/func/dynamic_function.rs b/crates/bevy_reflect/src/func/dynamic_function.rs index 863bffce77bfc..e135d23f57cd9 100644 --- a/crates/bevy_reflect/src/func/dynamic_function.rs +++ b/crates/bevy_reflect/src/func/dynamic_function.rs @@ -755,10 +755,12 @@ mod tests { assert_eq!( result.unwrap_err(), FunctionError::NoOverload { - expected: HashSet::from([ + expected: [ ArgumentSignature::from_iter(vec![Type::of::(), Type::of::()]), ArgumentSignature::from_iter(vec![Type::of::(), Type::of::()]) - ]), + ] + .into_iter() + .collect::>(), received: ArgumentSignature::from_iter(vec![Type::of::(), Type::of::()]), } ); diff --git a/crates/bevy_reflect/src/func/dynamic_function_internal.rs b/crates/bevy_reflect/src/func/dynamic_function_internal.rs index 33907ad799ccd..427de1263d14a 100644 --- a/crates/bevy_reflect/src/func/dynamic_function_internal.rs +++ b/crates/bevy_reflect/src/func/dynamic_function_internal.rs @@ -2,7 +2,7 @@ use crate::func::args::ArgCount; use crate::func::signature::{ArgListSignature, ArgumentSignature}; use crate::func::{ArgList, FunctionError, FunctionInfo, FunctionOverloadError}; use alloc::borrow::Cow; -use bevy_utils::hashbrown::HashMap; +use bevy_utils::HashMap; use core::fmt::{Debug, Formatter}; /// An internal structure for storing a function and its corresponding [function information]. @@ -141,19 +141,19 @@ impl DynamicFunctionInternal { pub fn merge(&mut self, mut other: Self) -> Result<(), FunctionOverloadError> { // Keep a separate map of the new indices to avoid mutating the existing one // until we can be sure the merge will be successful. - let mut new_signatures = HashMap::new(); + let mut new_signatures = >::default(); for (sig, index) in other.arg_map { if self.arg_map.contains_key(&sig) { return Err(FunctionOverloadError::DuplicateSignature(sig)); } - new_signatures.insert_unique_unchecked(sig, self.functions.len() + index); + new_signatures.insert(sig, self.functions.len() + index); } self.arg_map.reserve(new_signatures.len()); for (sig, index) in new_signatures { - self.arg_map.insert_unique_unchecked(sig, index); + self.arg_map.insert(sig, index); } self.functions.append(&mut other.functions); diff --git a/crates/bevy_reflect/src/impls/foldhash.rs b/crates/bevy_reflect/src/impls/foldhash.rs new file mode 100644 index 0000000000000..a4f1df44efefc --- /dev/null +++ b/crates/bevy_reflect/src/impls/foldhash.rs @@ -0,0 +1,8 @@ +use crate::{self as bevy_reflect, impl_type_path}; + +impl_type_path!(::foldhash::fast::FoldHasher); +impl_type_path!(::foldhash::fast::FixedState); +impl_type_path!(::foldhash::fast::RandomState); +impl_type_path!(::foldhash::quality::FoldHasher); +impl_type_path!(::foldhash::quality::FixedState); +impl_type_path!(::foldhash::quality::RandomState); diff --git a/crates/bevy_reflect/src/impls/std.rs b/crates/bevy_reflect/src/impls/std.rs index baeb2999e3632..19fa4eb2b4c18 100644 --- a/crates/bevy_reflect/src/impls/std.rs +++ b/crates/bevy_reflect/src/impls/std.rs @@ -13,7 +13,13 @@ use crate::{ ReflectFromReflect, ReflectKind, ReflectMut, ReflectOwned, ReflectRef, ReflectSerialize, Set, SetInfo, TypeInfo, TypeParamInfo, TypePath, TypeRegistration, TypeRegistry, Typed, }; -use alloc::{borrow::Cow, borrow::ToOwned, boxed::Box, collections::VecDeque, format, vec::Vec}; +use alloc::{ + borrow::{Cow, ToOwned}, + boxed::Box, + collections::VecDeque, + format, + vec::Vec, +}; use bevy_reflect_derive::{impl_reflect, impl_reflect_opaque}; use core::{ any::Any, @@ -832,6 +838,7 @@ macro_rules! impl_reflect_for_hashmap { #[cfg(feature = "std")] impl_reflect_for_hashmap!(::std::collections::HashMap); +impl_type_path!(::core::hash::BuildHasherDefault); #[cfg(feature = "std")] impl_type_path!(::std::collections::hash_map::RandomState); #[cfg(feature = "std")] @@ -846,7 +853,6 @@ crate::func::macros::impl_function_traits!(::std::collections::HashMap; ); impl_reflect_for_hashmap!(bevy_utils::hashbrown::HashMap); -impl_type_path!(::bevy_utils::hashbrown::hash_map::DefaultHashBuilder); impl_type_path!(::bevy_utils::hashbrown::HashMap); #[cfg(feature = "functions")] crate::func::macros::impl_function_traits!(::bevy_utils::hashbrown::HashMap; @@ -1060,7 +1066,7 @@ macro_rules! impl_reflect_for_hashset { } impl_type_path!(::bevy_utils::NoOpHash); -impl_type_path!(::bevy_utils::FixedState); +impl_type_path!(::bevy_utils::FixedHasher); #[cfg(feature = "std")] impl_reflect_for_hashset!(::std::collections::HashSet); @@ -2342,10 +2348,10 @@ mod tests { #[test] fn should_partial_eq_hash_map() { - let mut a = HashMap::new(); + let mut a = >::default(); a.insert(0usize, 1.23_f64); let b = a.clone(); - let mut c = HashMap::new(); + let mut c = >::default(); c.insert(0usize, 3.21_f64); let a: &dyn PartialReflect = &a; diff --git a/crates/bevy_reflect/src/kind.rs b/crates/bevy_reflect/src/kind.rs index 1120ae5d1f7bb..d5d16715c09c4 100644 --- a/crates/bevy_reflect/src/kind.rs +++ b/crates/bevy_reflect/src/kind.rs @@ -297,7 +297,7 @@ mod tests { #[test] fn should_cast_mut() { - let mut value: HashSet = HashSet::new(); + let mut value: HashSet = HashSet::default(); let result = value.reflect_mut().as_set(); assert!(result.is_ok()); diff --git a/crates/bevy_reflect/src/lib.rs b/crates/bevy_reflect/src/lib.rs index 07a3c43c12a6e..46253e13d144e 100644 --- a/crates/bevy_reflect/src/lib.rs +++ b/crates/bevy_reflect/src/lib.rs @@ -578,6 +578,7 @@ mod type_path; mod type_registry; mod impls { + mod foldhash; mod std; #[cfg(feature = "glam")] @@ -1158,11 +1159,11 @@ mod tests { #[derive(Reflect, Eq, PartialEq, Debug)] struct Baz(String); - let mut hash_map = HashMap::default(); + let mut hash_map = >::default(); hash_map.insert(1, 1); hash_map.insert(2, 2); - let mut hash_map_baz = HashMap::default(); + let mut hash_map_baz = >::default(); hash_map_baz.insert(1, Bar { x: 0 }); let mut foo = Foo { @@ -1227,12 +1228,12 @@ mod tests { foo.apply(&foo_patch); - let mut hash_map = HashMap::default(); + let mut hash_map = >::default(); hash_map.insert(1, 1); hash_map.insert(2, 3); hash_map.insert(3, 4); - let mut hash_map_baz = HashMap::default(); + let mut hash_map_baz = >::default(); hash_map_baz.insert(1, Bar { x: 7 }); let expected_foo = Foo { @@ -1251,7 +1252,7 @@ mod tests { let new_foo = Foo::from_reflect(&foo_patch) .expect("error while creating a concrete type from a dynamic type"); - let mut hash_map = HashMap::default(); + let mut hash_map = >::default(); hash_map.insert(2, 3); hash_map.insert(3, 4); @@ -1408,7 +1409,7 @@ mod tests { x: u32, } - let mut hash_map = HashMap::default(); + let mut hash_map = >::default(); hash_map.insert(1, 1); hash_map.insert(2, 2); let foo = Foo { @@ -1497,7 +1498,8 @@ mod tests { assert!(fields[0].reflect_partial_eq(&123_i32).unwrap_or_default()); assert!(fields[1].reflect_partial_eq(&321_i32).unwrap_or_default()); - let mut map_value: Box = Box::new(HashMap::from([(123_i32, 321_i32)])); + let mut map_value: Box = + Box::new([(123_i32, 321_i32)].into_iter().collect::>()); let fields = map_value.drain(); assert!(fields[0].0.reflect_partial_eq(&123_i32).unwrap_or_default()); assert!(fields[0].1.reflect_partial_eq(&321_i32).unwrap_or_default()); @@ -1861,7 +1863,7 @@ mod tests { assert_eq!(usize::type_path(), info.key_ty().path()); assert_eq!(f32::type_path(), info.value_ty().path()); - let value: &dyn Reflect = &MyMap::new(); + let value: &dyn Reflect = &MyMap::default(); let info = value.reflect_type_info(); assert!(info.is::()); @@ -2160,7 +2162,7 @@ mod tests { } } - let mut map = HashMap::new(); + let mut map = >::default(); map.insert(123, 1.23); let test = Test { @@ -2474,7 +2476,7 @@ bevy_reflect::tests::Test { // test reflected value value: u32, } - let mut map = HashMap::new(); + let mut map = >::default(); map.insert(9, 10); let mut test_struct: DynamicStruct = TestStruct { tuple: (0, 1), diff --git a/crates/bevy_reflect/src/map.rs b/crates/bevy_reflect/src/map.rs index bafcaf528faec..e5205e90afa38 100644 --- a/crates/bevy_reflect/src/map.rs +++ b/crates/bevy_reflect/src/map.rs @@ -3,11 +3,10 @@ use core::fmt::{Debug, Formatter}; use bevy_reflect_derive::impl_type_path; use bevy_utils::hashbrown::HashTable; -use crate::generics::impl_generic_info_methods; use crate::{ - self as bevy_reflect, type_info::impl_type_methods, ApplyError, Generics, MaybeTyped, - PartialReflect, Reflect, ReflectKind, ReflectMut, ReflectOwned, ReflectRef, Type, TypeInfo, - TypePath, + self as bevy_reflect, generics::impl_generic_info_methods, type_info::impl_type_methods, + ApplyError, Generics, MaybeTyped, PartialReflect, Reflect, ReflectKind, ReflectMut, + ReflectOwned, ReflectRef, Type, TypeInfo, TypePath, }; use alloc::{boxed::Box, format, vec::Vec}; @@ -31,7 +30,7 @@ use alloc::{boxed::Box, format, vec::Vec}; /// /// ``` /// use bevy_reflect::{PartialReflect, Reflect, Map}; -/// use bevy_utils::HashMap; +/// use std::collections::HashMap; /// /// /// let foo: &mut dyn Map = &mut HashMap::::new(); @@ -569,7 +568,7 @@ pub fn map_partial_eq(a: &M, b: &dyn PartialReflect) -> Option< /// /// # Example /// ``` -/// # use bevy_utils::HashMap; +/// # use std::collections::HashMap; /// use bevy_reflect::Reflect; /// /// let mut my_map = HashMap::new(); diff --git a/crates/bevy_reflect/src/serde/de/mod.rs b/crates/bevy_reflect/src/serde/de/mod.rs index b1ada1835e961..e55897166e926 100644 --- a/crates/bevy_reflect/src/serde/de/mod.rs +++ b/crates/bevy_reflect/src/serde/de/mod.rs @@ -26,18 +26,20 @@ mod tuples; mod tests { use bincode::Options; use core::{any::TypeId, f32::consts::PI, ops::RangeInclusive}; - use serde::de::IgnoredAny; - use serde::Deserializer; + use serde::{de::IgnoredAny, Deserializer}; use serde::{de::DeserializeSeed, Deserialize}; use bevy_utils::{HashMap, HashSet}; - use crate::serde::ReflectDeserializerProcessor; - use crate::{self as bevy_reflect, TypeRegistration}; use crate::{ - serde::{ReflectDeserializer, ReflectSerializer, TypedReflectDeserializer}, - DynamicEnum, FromReflect, PartialReflect, Reflect, ReflectDeserialize, TypeRegistry, + self as bevy_reflect, + serde::{ + ReflectDeserializer, ReflectDeserializerProcessor, ReflectSerializer, + TypedReflectDeserializer, + }, + DynamicEnum, FromReflect, PartialReflect, Reflect, ReflectDeserialize, TypeRegistration, + TypeRegistry, }; #[derive(Reflect, Debug, PartialEq)] @@ -148,10 +150,10 @@ mod tests { } fn get_my_struct() -> MyStruct { - let mut map = HashMap::new(); + let mut map = >::default(); map.insert(64, 32); - let mut set = HashSet::new(); + let mut set = >::default(); set.insert(64); MyStruct { diff --git a/crates/bevy_reflect/src/serde/ser/mod.rs b/crates/bevy_reflect/src/serde/ser/mod.rs index ba12b7fb4fc39..53afacde37430 100644 --- a/crates/bevy_reflect/src/serde/ser/mod.rs +++ b/crates/bevy_reflect/src/serde/ser/mod.rs @@ -26,8 +26,7 @@ mod tests { PartialReflect, Reflect, ReflectSerialize, Struct, TypeRegistry, }; use bevy_utils::{HashMap, HashSet}; - use core::any::TypeId; - use core::{f32::consts::PI, ops::RangeInclusive}; + use core::{any::TypeId, f32::consts::PI, ops::RangeInclusive}; use ron::{extensions::Extensions, ser::PrettyConfig}; use serde::{Serialize, Serializer}; @@ -128,10 +127,10 @@ mod tests { } fn get_my_struct() -> MyStruct { - let mut map = HashMap::new(); + let mut map = >::default(); map.insert(64, 32); - let mut set = HashSet::new(); + let mut set = >::default(); set.insert(64); MyStruct { diff --git a/crates/bevy_reflect/src/set.rs b/crates/bevy_reflect/src/set.rs index be66c53318438..0d46d9f9df771 100644 --- a/crates/bevy_reflect/src/set.rs +++ b/crates/bevy_reflect/src/set.rs @@ -4,11 +4,10 @@ use core::fmt::{Debug, Formatter}; use bevy_reflect_derive::impl_type_path; use bevy_utils::hashbrown::{hash_table::OccupiedEntry as HashTableOccupiedEntry, HashTable}; -use crate::generics::impl_generic_info_methods; use crate::{ - self as bevy_reflect, hash_error, type_info::impl_type_methods, ApplyError, Generics, - PartialReflect, Reflect, ReflectKind, ReflectMut, ReflectOwned, ReflectRef, Type, TypeInfo, - TypePath, + self as bevy_reflect, generics::impl_generic_info_methods, hash_error, + type_info::impl_type_methods, ApplyError, Generics, PartialReflect, Reflect, ReflectKind, + ReflectMut, ReflectOwned, ReflectRef, Type, TypeInfo, TypePath, }; /// A trait used to power [set-like] operations via [reflection]. @@ -31,7 +30,7 @@ use crate::{ /// /// ``` /// use bevy_reflect::{PartialReflect, Set}; -/// use bevy_utils::HashSet; +/// use std::collections::HashSet; /// /// /// let foo: &mut dyn Set = &mut HashSet::::new(); @@ -432,7 +431,7 @@ pub fn set_partial_eq(a: &M, b: &dyn PartialReflect) -> Option { /// /// # Example /// ``` -/// # use bevy_utils::HashSet; +/// # use std::collections::HashSet; /// use bevy_reflect::Reflect; /// /// let mut my_set = HashSet::new(); diff --git a/crates/bevy_reflect/src/utility.rs b/crates/bevy_reflect/src/utility.rs index 5395b2b28ae64..f106baf622135 100644 --- a/crates/bevy_reflect/src/utility.rs +++ b/crates/bevy_reflect/src/utility.rs @@ -2,7 +2,7 @@ use crate::TypeInfo; use alloc::boxed::Box; -use bevy_utils::{FixedState, NoOpHash, TypeIdMap}; +use bevy_utils::{DefaultHasher, FixedHasher, NoOpHash, TypeIdMap}; use core::{ any::{Any, TypeId}, hash::BuildHasher, @@ -315,6 +315,6 @@ impl Default for GenericTypeCell { /// /// [`Reflect::reflect_hash`]: crate::Reflect #[inline] -pub fn reflect_hasher() -> bevy_utils::AHasher { - FixedState.build_hasher() +pub fn reflect_hasher() -> DefaultHasher { + FixedHasher.build_hasher() } diff --git a/crates/bevy_remote/src/builtin_methods.rs b/crates/bevy_remote/src/builtin_methods.rs index a149717c54bea..7cf59c825b194 100644 --- a/crates/bevy_remote/src/builtin_methods.rs +++ b/crates/bevy_remote/src/builtin_methods.rs @@ -364,7 +364,7 @@ pub fn process_remote_get_watching_request( let mut changed = Vec::new(); let mut removed = Vec::new(); - let mut errors = HashMap::new(); + let mut errors = >::default(); 'component_loop: for component_path in components { let Ok(type_registration) = @@ -847,7 +847,7 @@ fn build_components_map<'a>( paths_and_reflect_components: impl Iterator, type_registry: &TypeRegistry, ) -> AnyhowResult> { - let mut serialized_components_map = HashMap::new(); + let mut serialized_components_map = >::default(); for (type_path, reflect_component) in paths_and_reflect_components { let Some(reflected) = reflect_component.reflect(entity_ref.clone()) else { @@ -873,7 +873,7 @@ fn build_has_map<'a>( entity_ref: FilteredEntityRef, paths_and_reflect_components: impl Iterator, ) -> HashMap { - let mut has_map = HashMap::new(); + let mut has_map = >::default(); for (type_path, reflect_component) in paths_and_reflect_components { let has = reflect_component.contains(entity_ref.clone()); diff --git a/crates/bevy_remote/src/http.rs b/crates/bevy_remote/src/http.rs index 321f6aa6bf497..04c99ea21010f 100644 --- a/crates/bevy_remote/src/http.rs +++ b/crates/bevy_remote/src/http.rs @@ -17,23 +17,25 @@ use async_io::Async; use bevy_app::{App, Plugin, Startup}; use bevy_ecs::system::{Res, Resource}; use bevy_tasks::{futures_lite::StreamExt, IoTaskPool}; -use core::net::{IpAddr, Ipv4Addr}; use core::{ convert::Infallible, + net::{IpAddr, Ipv4Addr}, pin::Pin, task::{Context, Poll}, }; use http_body_util::{BodyExt as _, Full}; -use hyper::header::{HeaderName, HeaderValue}; use hyper::{ body::{Body, Bytes, Frame, Incoming}, + header::{HeaderName, HeaderValue}, server::conn::http1, service, Request, Response, }; use serde_json::Value; use smol_hyper::rt::{FuturesIo, SmolTimer}; -use std::collections::HashMap; -use std::net::{TcpListener, TcpStream}; +use std::{ + collections::HashMap, + net::{TcpListener, TcpStream}, +}; /// The default port that Bevy will listen on. /// @@ -57,7 +59,7 @@ impl Headers { /// Create a new instance of `Headers`. pub fn new() -> Self { Self { - headers: HashMap::new(), + headers: HashMap::default(), } } diff --git a/crates/bevy_render/src/camera/camera.rs b/crates/bevy_render/src/camera/camera.rs index 1221c66a79c7e..3c375d935cd72 100644 --- a/crates/bevy_render/src/camera/camera.rs +++ b/crates/bevy_render/src/camera/camera.rs @@ -887,7 +887,7 @@ pub fn camera_system>( ) { let primary_window = primary_window.iter().next(); - let mut changed_window_ids = HashSet::new(); + let mut changed_window_ids = >::default(); changed_window_ids.extend(window_created_events.read().map(|event| event.window)); changed_window_ids.extend(window_resized_events.read().map(|event| event.window)); let scale_factor_changed_window_ids: HashSet<_> = window_scale_factor_changed_events @@ -926,7 +926,9 @@ pub fn camera_system>( // This can happen when the window is moved between monitors with different DPIs. // Without this, the viewport will take a smaller portion of the window moved to // a higher DPI monitor. - if normalized_target.is_changed(&scale_factor_changed_window_ids, &HashSet::new()) { + if normalized_target + .is_changed(&scale_factor_changed_window_ids, &HashSet::default()) + { if let (Some(new_scale_factor), Some(old_scale_factor)) = ( new_computed_target_info .as_ref() @@ -1199,8 +1201,8 @@ pub fn sort_cameras( ord => ord, }); let mut previous_order_target = None; - let mut ambiguities = HashSet::new(); - let mut target_counts = HashMap::new(); + let mut ambiguities = >::default(); + let mut target_counts = >::default(); for sorted_camera in &mut sorted_cameras.0 { let new_order_target = (sorted_camera.order, sorted_camera.target.clone()); if let Some(previous_order_target) = previous_order_target { diff --git a/crates/bevy_render/src/camera/camera_driver_node.rs b/crates/bevy_render/src/camera/camera_driver_node.rs index f01d781478783..274b12bca84fa 100644 --- a/crates/bevy_render/src/camera/camera_driver_node.rs +++ b/crates/bevy_render/src/camera/camera_driver_node.rs @@ -32,7 +32,7 @@ impl Node for CameraDriverNode { ) -> Result<(), NodeRunError> { let sorted_cameras = world.resource::(); let windows = world.resource::(); - let mut camera_windows = HashSet::new(); + let mut camera_windows = >::default(); for sorted_camera in &sorted_cameras.0 { let Ok(camera) = self.cameras.get_manual(world, sorted_camera.entity) else { continue; diff --git a/crates/bevy_render/src/mesh/allocator.rs b/crates/bevy_render/src/mesh/allocator.rs index 4e96078464ed3..6e7afaa4d7cde 100644 --- a/crates/bevy_render/src/mesh/allocator.rs +++ b/crates/bevy_render/src/mesh/allocator.rs @@ -15,11 +15,7 @@ use bevy_ecs::{ system::{Res, ResMut, Resource}, world::{FromWorld, World}, }; -use bevy_utils::{ - default, - hashbrown::{HashMap, HashSet}, - tracing::error, -}; +use bevy_utils::{default, tracing::error, HashMap, HashSet}; use offset_allocator::{Allocation, Allocator}; use wgpu::{ BufferDescriptor, BufferSize, BufferUsages, CommandEncoderDescriptor, DownlevelFlags, @@ -329,10 +325,10 @@ impl FromWorld for MeshAllocator { .contains(DownlevelFlags::BASE_VERTEX); Self { - slabs: HashMap::new(), - slab_layouts: HashMap::new(), - mesh_id_to_vertex_slab: HashMap::new(), - mesh_id_to_index_slab: HashMap::new(), + slabs: HashMap::default(), + slab_layouts: HashMap::default(), + mesh_id_to_vertex_slab: HashMap::default(), + mesh_id_to_index_slab: HashMap::default(), next_slab_id: default(), general_vertex_slabs_supported, } @@ -600,7 +596,7 @@ impl MeshAllocator { } fn free_meshes(&mut self, extracted_meshes: &ExtractedAssets) { - let mut empty_slabs = HashSet::new(); + let mut empty_slabs = >::default(); for mesh_id in &extracted_meshes.removed { if let Some(slab_id) = self.mesh_id_to_vertex_slab.remove(mesh_id) { self.free_allocation_in_slab(mesh_id, slab_id, &mut empty_slabs); @@ -881,8 +877,8 @@ impl GeneralSlab { let mut new_slab = GeneralSlab { allocator: Allocator::new(slab_slot_capacity), buffer: None, - resident_allocations: HashMap::new(), - pending_allocations: HashMap::new(), + resident_allocations: HashMap::default(), + pending_allocations: HashMap::default(), element_layout: layout, slot_capacity: slab_slot_capacity, }; diff --git a/crates/bevy_render/src/render_asset.rs b/crates/bevy_render/src/render_asset.rs index 047c2604b2321..2757dceb9fa81 100644 --- a/crates/bevy_render/src/render_asset.rs +++ b/crates/bevy_render/src/render_asset.rs @@ -233,8 +233,8 @@ pub(crate) fn extract_render_asset( |world, mut cached_state: Mut>| { let (mut events, mut assets) = cached_state.state.get_mut(world); - let mut changed_assets = HashSet::default(); - let mut removed = HashSet::default(); + let mut changed_assets = >::default(); + let mut removed = >::default(); for event in events.read() { #[allow(clippy::match_same_arms)] @@ -254,7 +254,7 @@ pub(crate) fn extract_render_asset( } let mut extracted_assets = Vec::new(); - let mut added = HashSet::new(); + let mut added = >::default(); for id in changed_assets.drain() { if let Some(asset) = assets.get(id) { let asset_usage = A::asset_usage(asset); diff --git a/crates/bevy_render/src/render_resource/pipeline_specializer.rs b/crates/bevy_render/src/render_resource/pipeline_specializer.rs index 55c13b3ab154c..3ee7a78ed7793 100644 --- a/crates/bevy_render/src/render_resource/pipeline_specializer.rs +++ b/crates/bevy_render/src/render_resource/pipeline_specializer.rs @@ -10,7 +10,7 @@ use bevy_utils::{ default, hashbrown::hash_map::{RawEntryMut, VacantEntry}, tracing::error, - Entry, HashMap, + Entry, FixedHasher, HashMap, }; use core::{fmt::Debug, hash::Hash}; use thiserror::Error; @@ -132,7 +132,11 @@ impl SpecializedMeshPipelines { specialize_pipeline: &S, key: S::Key, layout: &MeshVertexBufferLayoutRef, - entry: VacantEntry<(MeshVertexBufferLayoutRef, S::Key), CachedRenderPipelineId>, + entry: VacantEntry< + (MeshVertexBufferLayoutRef, S::Key), + CachedRenderPipelineId, + FixedHasher, + >, ) -> Result where S: SpecializedMeshPipeline, diff --git a/crates/bevy_render/src/view/mod.rs b/crates/bevy_render/src/view/mod.rs index 22af7ffb44b21..a626a17d1d592 100644 --- a/crates/bevy_render/src/view/mod.rs +++ b/crates/bevy_render/src/view/mod.rs @@ -923,7 +923,7 @@ pub fn prepare_view_targets( )>, view_target_attachments: Res, ) { - let mut textures = HashMap::default(); + let mut textures = >::default(); for (entity, camera, view, texture_usage, msaa) in cameras.iter() { let (Some(target_size), Some(target)) = (camera.physical_target_size, &camera.target) else { diff --git a/crates/bevy_scene/src/scene_filter.rs b/crates/bevy_scene/src/scene_filter.rs index eb86984903c79..062b218165c0c 100644 --- a/crates/bevy_scene/src/scene_filter.rs +++ b/crates/bevy_scene/src/scene_filter.rs @@ -47,7 +47,7 @@ impl SceneFilter { /// /// [`Denylist`]: SceneFilter::Denylist pub fn allow_all() -> Self { - Self::Denylist(HashSet::new()) + Self::Denylist(HashSet::default()) } /// Creates a filter where all types are denied. @@ -56,7 +56,7 @@ impl SceneFilter { /// /// [`Allowlist`]: SceneFilter::Allowlist pub fn deny_all() -> Self { - Self::Allowlist(HashSet::new()) + Self::Allowlist(HashSet::default()) } /// Allow the given type, `T`. @@ -88,7 +88,7 @@ impl SceneFilter { pub fn allow_by_id(mut self, type_id: TypeId) -> Self { match &mut self { Self::Unset => { - self = Self::Allowlist(HashSet::from([type_id])); + self = Self::Allowlist([type_id].into_iter().collect()); } Self::Allowlist(list) => { list.insert(type_id); @@ -128,7 +128,7 @@ impl SceneFilter { #[must_use] pub fn deny_by_id(mut self, type_id: TypeId) -> Self { match &mut self { - Self::Unset => self = Self::Denylist(HashSet::from([type_id])), + Self::Unset => self = Self::Denylist([type_id].into_iter().collect()), Self::Allowlist(list) => { list.remove(&type_id); } @@ -222,7 +222,7 @@ impl IntoIterator for SceneFilter { fn into_iter(self) -> Self::IntoIter { match self { - Self::Unset => HashSet::new().into_iter(), + Self::Unset => Default::default(), Self::Allowlist(list) | Self::Denylist(list) => list.into_iter(), } } diff --git a/crates/bevy_scene/src/scene_spawner.rs b/crates/bevy_scene/src/scene_spawner.rs index 2f660c9903750..32d829b8c726a 100644 --- a/crates/bevy_scene/src/scene_spawner.rs +++ b/crates/bevy_scene/src/scene_spawner.rs @@ -319,7 +319,7 @@ impl SceneSpawner { let spawned = self .spawned_dynamic_scenes .entry(handle.id()) - .or_insert_with(HashSet::new); + .or_insert_with(HashSet::default); spawned.insert(instance_id); // Scenes with parents need more setup before they are ready. @@ -426,7 +426,7 @@ impl SceneSpawner { pub fn scene_spawner_system(world: &mut World) { world.resource_scope(|world, mut scene_spawner: Mut| { // remove any loading instances where parent is deleted - let mut dead_instances = HashSet::default(); + let mut dead_instances = >::default(); scene_spawner .scenes_with_parent .retain(|(instance, parent)| { diff --git a/crates/bevy_scene/src/serde.rs b/crates/bevy_scene/src/serde.rs index e1498ccc1c978..0c74b8e7ee894 100644 --- a/crates/bevy_scene/src/serde.rs +++ b/crates/bevy_scene/src/serde.rs @@ -476,7 +476,7 @@ impl<'a, 'de> Visitor<'de> for SceneMapVisitor<'a> { where A: MapAccess<'de>, { - let mut added = HashSet::new(); + let mut added = >::default(); let mut entries = Vec::new(); while let Some(registration) = map.next_key_seed(TypeRegistrationDeserializer::new(self.registry))? diff --git a/crates/bevy_sprite/src/texture_atlas_builder.rs b/crates/bevy_sprite/src/texture_atlas_builder.rs index 92d62b619d85d..695e00f437e0d 100644 --- a/crates/bevy_sprite/src/texture_atlas_builder.rs +++ b/crates/bevy_sprite/src/texture_atlas_builder.rs @@ -271,7 +271,7 @@ impl<'a> TextureAtlasBuilder<'a> { let rect_placements = rect_placements.ok_or(TextureAtlasBuilderError::NotEnoughSpace)?; let mut texture_rects = Vec::with_capacity(rect_placements.packed_locations().len()); - let mut texture_ids = HashMap::default(); + let mut texture_ids = >::default(); // We iterate through the textures to place to respect the insertion order for the texture indices for (index, (image_id, texture)) in self.textures_to_place.iter().enumerate() { let (_, packed_location) = rect_placements.packed_locations().get(&index).unwrap(); diff --git a/crates/bevy_ui/src/layout/mod.rs b/crates/bevy_ui/src/layout/mod.rs index a9d9a768a36c7..315340244eda3 100644 --- a/crates/bevy_ui/src/layout/mod.rs +++ b/crates/bevy_ui/src/layout/mod.rs @@ -710,7 +710,7 @@ mod tests { ui_child_entities.len() ); - let child_node_map = HashMap::from_iter( + let child_node_map = >::from_iter( ui_child_entities .iter() .map(|child_entity| (*child_entity, ui_surface.entity_to_taffy[child_entity])), diff --git a/crates/bevy_ui/src/picking_backend.rs b/crates/bevy_ui/src/picking_backend.rs index fb43cd08c4088..279acdb880241 100644 --- a/crates/bevy_ui/src/picking_backend.rs +++ b/crates/bevy_ui/src/picking_backend.rs @@ -29,7 +29,7 @@ use bevy_ecs::{prelude::*, query::QueryData}; use bevy_math::{Rect, Vec2}; use bevy_render::prelude::*; use bevy_transform::prelude::*; -use bevy_utils::hashbrown::HashMap; +use bevy_utils::HashMap; use bevy_window::PrimaryWindow; use bevy_picking::backend::prelude::*; @@ -70,7 +70,7 @@ pub fn ui_picking( mut output: EventWriter, ) { // For each camera, the pointer and its position - let mut pointer_pos_by_camera = HashMap::>::new(); + let mut pointer_pos_by_camera = HashMap::>::default(); for (pointer_id, pointer_location) in pointers.iter().filter_map(|(pointer, pointer_location)| { @@ -107,7 +107,7 @@ pub fn ui_picking( } // The list of node entities hovered for each (camera, pointer) combo - let mut hit_nodes = HashMap::<(Entity, PointerId), Vec>::new(); + let mut hit_nodes = HashMap::<(Entity, PointerId), Vec>::default(); // prepare an iterator that contains all the nodes that have the cursor in their rect, // from the top node to the bottom one. this will also reset the interaction to `None` diff --git a/crates/bevy_ui/src/stack.rs b/crates/bevy_ui/src/stack.rs index 83ccc9a23c0d5..a8283e0938ea7 100644 --- a/crates/bevy_ui/src/stack.rs +++ b/crates/bevy_ui/src/stack.rs @@ -62,7 +62,7 @@ pub fn ui_stack_system( maybe_zindex.map(|zindex| zindex.0).unwrap_or(0), ), )); - visited_root_nodes.insert_unique_unchecked(id); + visited_root_nodes.insert(id); } for (id, global_zindex, maybe_zindex) in zindex_global_node_query.iter() { diff --git a/crates/bevy_ui/src/update.rs b/crates/bevy_ui/src/update.rs index 049c797ea103c..9d8883d81ddbe 100644 --- a/crates/bevy_ui/src/update.rs +++ b/crates/bevy_ui/src/update.rs @@ -146,7 +146,7 @@ pub fn update_target_camera_system( ) { // Track updated entities to prevent redundant updates, as `Commands` changes are deferred, // and updates done for changed_children_query can overlap with itself or with root_node_query - let mut updated_entities = HashSet::new(); + let mut updated_entities = >::default(); // Assuming that TargetCamera is manually set on the root node only, // update root nodes first, since it implies the biggest change diff --git a/crates/bevy_utils/Cargo.toml b/crates/bevy_utils/Cargo.toml index 91bf2710e0aee..8121bbce4f16c 100644 --- a/crates/bevy_utils/Cargo.toml +++ b/crates/bevy_utils/Cargo.toml @@ -10,22 +10,18 @@ keywords = ["bevy"] [features] default = ["std", "serde"] -std = [ - "alloc", - "tracing/std", - "ahash/std", - "dep:thread_local", - "ahash/runtime-rng", -] -alloc = ["hashbrown/default"] +std = ["alloc", "tracing/std", "foldhash/std", "dep:thread_local"] +alloc = ["hashbrown"] +detailed_trace = [] serde = ["hashbrown/serde"] [dependencies] -ahash = { version = "0.8.7", default-features = false, features = [ - "compile-time-rng", -] } +foldhash = { version = "0.1.3", default-features = false } tracing = { version = "0.1", default-features = false } -hashbrown = { version = "0.14.2", default-features = false } +hashbrown = { version = "0.15.1", features = [ + "equivalent", + "raw-entry", +], optional = true, default-features = false } thread_local = { version = "1.0", optional = true } [dev-dependencies] diff --git a/crates/bevy_utils/src/lib.rs b/crates/bevy_utils/src/lib.rs index 00329f652b02f..19d122ad849f3 100644 --- a/crates/bevy_utils/src/lib.rs +++ b/crates/bevy_utils/src/lib.rs @@ -35,8 +35,28 @@ mod once; mod parallel_queue; mod time; -pub use ahash::{AHasher, RandomState}; +/// For when you want a deterministic hasher. +/// +/// Seed was randomly generated with a fair dice roll. Guaranteed to be random: +/// +const FIXED_HASHER: FixedState = + FixedState::with_seed(0b1001010111101110000001001100010000000011001001101011001001111000); + +/// Deterministic hasher based upon a random but fixed state. +#[derive(Copy, Clone, Default, Debug)] +pub struct FixedHasher; +impl BuildHasher for FixedHasher { + type Hasher = DefaultHasher; + + #[inline] + fn build_hasher(&self) -> Self::Hasher { + FIXED_HASHER.build_hasher() + } +} + pub use default::default; +pub use foldhash::fast::{FixedState, FoldHasher as DefaultHasher, RandomState}; +#[cfg(feature = "alloc")] pub use hashbrown; #[cfg(feature = "std")] pub use parallel_queue::*; @@ -46,15 +66,15 @@ pub use tracing; #[cfg(feature = "alloc")] use alloc::boxed::Box; +#[cfg(feature = "alloc")] +use core::any::TypeId; use core::{ - any::TypeId, fmt::Debug, - hash::{BuildHasher, BuildHasherDefault, Hash, Hasher}, + hash::{BuildHasher, Hash, Hasher}, marker::PhantomData, mem::ManuallyDrop, ops::Deref, }; -use hashbrown::hash_map::RawEntryMut; #[cfg(not(target_arch = "wasm32"))] mod conditional_send { @@ -83,70 +103,60 @@ impl ConditionalSendFuture for T {} pub type BoxedFuture<'a, T> = core::pin::Pin + 'a>>; /// A shortcut alias for [`hashbrown::hash_map::Entry`]. -pub type Entry<'a, K, V, S = BuildHasherDefault> = hashbrown::hash_map::Entry<'a, K, V, S>; - -/// A hasher builder that will create a fixed hasher. -#[derive(Debug, Clone, Default)] -pub struct FixedState; - -impl BuildHasher for FixedState { - type Hasher = AHasher; - - #[inline] - fn build_hasher(&self) -> AHasher { - RandomState::with_seeds( - 0b10010101111011100000010011000100, - 0b00000011001001101011001001111000, - 0b11001111011010110111100010110101, - 0b00000100001111100011010011010101, - ) - .build_hasher() - } -} +#[cfg(feature = "alloc")] +pub type Entry<'a, K, V, S = FixedHasher> = hashbrown::hash_map::Entry<'a, K, V, S>; -/// A [`HashMap`][hashbrown::HashMap] implementing aHash, a high +/// A [`HashMap`][hashbrown::HashMap] implementing a high /// speed keyed hashing algorithm intended for use in in-memory hashmaps. /// -/// aHash is designed for performance and is NOT cryptographically secure. +/// The hashing algorithm is designed for performance +/// and is NOT cryptographically secure. /// /// Within the same execution of the program iteration order of different /// `HashMap`s only depends on the order of insertions and deletions, /// but it will not be stable between multiple executions of the program. -pub type HashMap = hashbrown::HashMap>; +#[cfg(feature = "alloc")] +pub type HashMap = hashbrown::HashMap; -/// A stable hash map implementing aHash, a high speed keyed hashing algorithm +/// A stable hash map implementing a high speed keyed hashing algorithm /// intended for use in in-memory hashmaps. /// /// Unlike [`HashMap`] the iteration order stability extends between executions /// using the same Bevy version on the same device. /// -/// aHash is designed for performance and is NOT cryptographically secure. +/// The hashing algorithm is designed for performance +/// and is NOT cryptographically secure. #[deprecated( - note = "Will be required to use the hash library of your choice. Alias for: hashbrown::HashMap" + note = "Will be required to use the hash library of your choice. Alias for: hashbrown::HashMap" )] -pub type StableHashMap = hashbrown::HashMap; +#[cfg(feature = "alloc")] +pub type StableHashMap = hashbrown::HashMap; -/// A [`HashSet`][hashbrown::HashSet] implementing aHash, a high +/// A [`HashSet`][hashbrown::HashSet] implementing a high /// speed keyed hashing algorithm intended for use in in-memory hashmaps. /// -/// aHash is designed for performance and is NOT cryptographically secure. +/// The hashing algorithm is designed for performance +/// and is NOT cryptographically secure. /// /// Within the same execution of the program iteration order of different /// `HashSet`s only depends on the order of insertions and deletions, /// but it will not be stable between multiple executions of the program. -pub type HashSet = hashbrown::HashSet>; +#[cfg(feature = "alloc")] +pub type HashSet = hashbrown::HashSet; -/// A stable hash set implementing aHash, a high speed keyed hashing algorithm +/// A stable hash set using a high speed keyed hashing algorithm /// intended for use in in-memory hashmaps. /// /// Unlike [`HashMap`] the iteration order stability extends between executions /// using the same Bevy version on the same device. /// -/// aHash is designed for performance and is NOT cryptographically secure. +/// The hashing algorithm is designed for performance +/// and is NOT cryptographically secure. #[deprecated( - note = "Will be required to use the hash library of your choice. Alias for: hashbrown::HashSet" + note = "Will be required to use the hash library of your choice. Alias for: hashbrown::HashSet" )] -pub type StableHashSet = hashbrown::HashSet; +#[cfg(feature = "alloc")] +pub type StableHashSet = hashbrown::HashSet; /// A pre-hashed value of a specific type. Pre-hashing enables memoization of hashes that are expensive to compute. /// @@ -154,10 +164,10 @@ pub type StableHashSet = hashbrown::HashSet; /// See [`PassHash`] and [`PassHasher`] for a "pass through" [`BuildHasher`] and [`Hasher`] implementation /// designed to work with [`Hashed`] /// See [`PreHashMap`] for a hashmap pre-configured to use [`Hashed`] keys. -pub struct Hashed { +pub struct Hashed { hash: u64, value: V, - marker: PhantomData, + marker: PhantomData, } impl Hashed { @@ -263,9 +273,11 @@ impl Hasher for PassHasher { /// A [`HashMap`] pre-configured to use [`Hashed`] keys and [`PassHash`] passthrough hashing. /// Iteration order only depends on the order of insertions and deletions. +#[cfg(feature = "alloc")] pub type PreHashMap = hashbrown::HashMap, V, PassHash>; /// Extension methods intended to add functionality to [`PreHashMap`]. +#[cfg(feature = "alloc")] pub trait PreHashMapExt { /// Tries to get or insert the value for the given `key` using the pre-computed hash first. /// If the [`PreHashMap`] does not already contain the `key`, it will clone it and insert @@ -273,9 +285,11 @@ pub trait PreHashMapExt { fn get_or_insert_with V>(&mut self, key: &Hashed, func: F) -> &mut V; } +#[cfg(feature = "alloc")] impl PreHashMapExt for PreHashMap { #[inline] fn get_or_insert_with V>(&mut self, key: &Hashed, func: F) -> &mut V { + use hashbrown::hash_map::RawEntryMut; let entry = self .raw_entry_mut() .from_key_hashed_nocheck(key.hash(), key); @@ -291,6 +305,7 @@ impl PreHashMapExt for PreHashMap = hashbrown::HashMap; /// [`BuildHasher`] for types that already contain a high-quality hash. @@ -448,8 +463,8 @@ mod tests { fn stable_hash_within_same_program_execution() { use alloc::vec::Vec; - let mut map_1 = HashMap::new(); - let mut map_2 = HashMap::new(); + let mut map_1 = >::default(); + let mut map_2 = >::default(); for i in 1..10 { map_1.insert(i, i); map_2.insert(i, i); diff --git a/examples/3d/tonemapping.rs b/examples/3d/tonemapping.rs index f802154cb390e..875198e7fed3f 100644 --- a/examples/3d/tonemapping.rs +++ b/examples/3d/tonemapping.rs @@ -572,7 +572,7 @@ impl PerMethodSettings { impl Default for PerMethodSettings { fn default() -> Self { - let mut settings = HashMap::new(); + let mut settings = >::default(); for method in [ Tonemapping::None, diff --git a/examples/animation/animation_masks.rs b/examples/animation/animation_masks.rs index 734b4c1c06346..7a27d6acd0347 100644 --- a/examples/animation/animation_masks.rs +++ b/examples/animation/animation_masks.rs @@ -4,8 +4,8 @@ use bevy::{ animation::{AnimationTarget, AnimationTargetId}, color::palettes::css::{LIGHT_GRAY, WHITE}, prelude::*, - utils::hashbrown::HashSet, }; +use std::collections::HashSet; // IDs of the mask groups we define for the running fox model. // diff --git a/examples/ecs/dynamic.rs b/examples/ecs/dynamic.rs index 1e9b8c57a32ad..7de684d350d14 100644 --- a/examples/ecs/dynamic.rs +++ b/examples/ecs/dynamic.rs @@ -3,7 +3,7 @@ //! This example show how you can create components dynamically, spawn entities with those components //! as well as query for entities with those components. -use std::{alloc::Layout, io::Write, ptr::NonNull}; +use std::{alloc::Layout, collections::HashMap, io::Write, ptr::NonNull}; use bevy::{ ecs::{ @@ -13,7 +13,6 @@ use bevy::{ }, prelude::*, ptr::{Aligned, OwningPtr}, - utils::HashMap, }; const PROMPT: &str = " diff --git a/examples/games/contributors.rs b/examples/games/contributors.rs index bbaf58fb3539b..8d977fd21d8ac 100644 --- a/examples/games/contributors.rs +++ b/examples/games/contributors.rs @@ -1,9 +1,10 @@ //! This example displays each contributor to the bevy source code as a bouncing bevy-ball. -use bevy::{math::bounding::Aabb2d, prelude::*, utils::HashMap}; +use bevy::{math::bounding::Aabb2d, prelude::*}; use rand::{Rng, SeedableRng}; use rand_chacha::ChaCha8Rng; use std::{ + collections::HashMap, env::VarError, hash::{DefaultHasher, Hash, Hasher}, io::{self, BufRead, BufReader}, diff --git a/examples/reflection/dynamic_types.rs b/examples/reflection/dynamic_types.rs index c892bc83de4a7..387fe7d0ed34d 100644 --- a/examples/reflection/dynamic_types.rs +++ b/examples/reflection/dynamic_types.rs @@ -195,7 +195,7 @@ fn main() { dynamic_set.remove(&"y"); - let mut my_set: HashSet<&str> = HashSet::new(); + let mut my_set: HashSet<&str> = HashSet::default(); my_set.apply(&dynamic_set); assert_eq!(my_set, HashSet::from_iter(["x", "z"])); } @@ -204,7 +204,7 @@ fn main() { { let dynamic_map = DynamicMap::from_iter([("x", 1u32), ("y", 2u32), ("z", 3u32)]); - let mut my_map: HashMap<&str, u32> = HashMap::new(); + let mut my_map: HashMap<&str, u32> = HashMap::default(); my_map.apply(&dynamic_map); assert_eq!(my_map.get("x"), Some(&1)); assert_eq!(my_map.get("y"), Some(&2)); diff --git a/examples/reflection/reflection_types.rs b/examples/reflection/reflection_types.rs index 8f9e9a73d7621..265e5f8adce60 100644 --- a/examples/reflection/reflection_types.rs +++ b/examples/reflection/reflection_types.rs @@ -68,7 +68,7 @@ enum F { } fn setup() { - let mut z = HashMap::default(); + let mut z = >::default(); z.insert("Hello".to_string(), 1.0); let value: Box = Box::new(A { x: 1, diff --git a/tests/ecs/ambiguity_detection.rs b/tests/ecs/ambiguity_detection.rs index f6971b1ca2b23..b53450ba22bbf 100644 --- a/tests/ecs/ambiguity_detection.rs +++ b/tests/ecs/ambiguity_detection.rs @@ -71,7 +71,7 @@ fn configure_ambiguity_detection(sub_app: &mut SubApp) { /// Returns the number of conflicting systems per schedule. fn count_ambiguities(sub_app: &SubApp) -> AmbiguitiesCount { let schedules = sub_app.world().resource::(); - let mut ambiguities = HashMap::new(); + let mut ambiguities = >::default(); for (_, schedule) in schedules.iter() { let ambiguities_in_schedule = schedule.graph().conflicting_systems().len(); ambiguities.insert(schedule.label(), ambiguities_in_schedule); diff --git a/tools/build-templated-pages/Cargo.toml b/tools/build-templated-pages/Cargo.toml index b65f1bd358ac4..d19e553dd3781 100644 --- a/tools/build-templated-pages/Cargo.toml +++ b/tools/build-templated-pages/Cargo.toml @@ -12,7 +12,7 @@ toml_edit = { version = "0.22.7", default-features = false, features = [ tera = "1.15" serde = { version = "1.0", features = ["derive"] } bitflags = "2.3" -hashbrown = { version = "0.14", features = ["serde"] } +hashbrown = { version = "0.15", features = ["serde"] } [lints] workspace = true diff --git a/tools/example-showcase/remove-desktop-app-mode.patch b/tools/example-showcase/remove-desktop-app-mode.patch index 2d21e07902b89..b43cfce515d80 100644 --- a/tools/example-showcase/remove-desktop-app-mode.patch +++ b/tools/example-showcase/remove-desktop-app-mode.patch @@ -13,4 +13,4 @@ index 104384086..6e3c8dd83 100644 + Self::default() } - /// Returns the current [`UpdateMode`]. + /// Default settings for mobile.