From 711246aa34753bd019e35533923e4ab83fe1fe84 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 2507895bf0..e570d25ab1 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 b782c8d709..e03ad9a449 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 4aad33c9d6..4ff12abd74 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 977a50b98b..9c61ff0f88 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 7e2abc50e3..07a6d3db12 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 cb205f12a8..388145a468 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 fe0d8df17f..c0bab2037f 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 4cab51634f..cbc5aac3c1 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 3a38797fc8..898b3a76ec 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 4365eeb1b3..6a2e475219 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 8c00762199..70e7a81cef 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 0e9c064af6..d57134aa3e 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 909306dd42..d7e9b446e5 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 c01b2a286e..14e8b8d4e3 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 b686d44849..52369fca59 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 1e52723d20..7c076a2c8a 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 ccd6e17df1..c9fbe5d600 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 2c2241e29e..022e550948 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 333358240c..97833a1d7d 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 1b1ff531ff..2e7c8ff2a3 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 79b5197d2e..abce76853d 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 179fdc8b82..6668a2a9a6 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 85ff83c0aa..c7def12de3 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 680774bce5..1b00698fc1 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 553be0bc19..1532184f17 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 449b609a28..e9781cec56 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 0ac19e312b..22a84f69f9 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 5152e549a8..c2a5199f86 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 f3c0a4d9fb..319bfa7590 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 72a304c699..3eda19eed9 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 bbab0dff08..41932a2aaa 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 5391d75c86..f5516e413b 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 4122068229..ab3f4b464f 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 7a53652967..14b46e55ba 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 fcc06c72f5..c190d7ea36 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 4170ac6279..4cae0d50d1 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 29f878522e..c0f3db33d5 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 d07c0c095f..8c3246d96e 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 010b5a7298..5879c1cac7 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 3cfe0adc74..75df7b7b93 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 863bffce77..e135d23f57 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 33907ad799..427de1263d 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 0000000000..a4f1df44ef --- /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 baeb2999e3..19fa4eb2b4 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 1120ae5d1f..d5d16715c0 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 07a3c43c12..46253e13d1 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 bafcaf528f..e5205e90af 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 b1ada1835e..e55897166e 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 ba12b7fb4f..53afacde37 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 be66c53318..0d46d9f9df 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 5395b2b28a..f106baf622 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 a149717c54..7cf59c825b 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 321f6aa6bf..04c99ea210 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 1221c66a79..3c375d935c 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 f01d781478..274b12bca8 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 4e96078464..6e7afaa4d7 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 047c2604b2..2757dceb9f 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 55c13b3ab1..3ee7a78ed7 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 22af7ffb44..a626a17d1d 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 eb86984903..062b218165 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 2f660c9903..32d829b8c7 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 e1498ccc1c..0c74b8e7ee 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 92d62b619d..695e00f437 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 a9d9a768a3..315340244e 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 fb43cd08c4..279acdb880 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 83ccc9a23c..a8283e0938 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 049c797ea1..9d8883d81d 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 91bf2710e0..8121bbce4f 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 00329f652b..19d122ad84 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>; +#[cfg(feature = "alloc")] +pub type Entry<'a, K, V, S = FixedHasher> = 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() - } -} - -/// 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 f802154cb3..875198e7fe 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 734b4c1c06..7a27d6acd0 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 1e9b8c57a3..7de684d350 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 bbaf58fb35..8d977fd21d 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 c892bc83de..387fe7d0ed 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 8f9e9a73d7..265e5f8adc 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 f6971b1ca2..b53450ba22 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 b65f1bd358..d19e553dd3 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 2d21e07902..b43cfce515 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.