diff --git a/_release-content/migration-guides/type_id_map.md b/_release-content/migration-guides/type_id_map.md new file mode 100644 index 0000000000000..552a6130aff7c --- /dev/null +++ b/_release-content/migration-guides/type_id_map.md @@ -0,0 +1,14 @@ +--- +title: Explicit TypeId map aliases +pull_requests: [25053] +--- + +`TypeIdHashMap` and `TypeIdIndexMap` have been added for code that maps +[`TypeId`](https://doc.rust-lang.org/std/any/struct.TypeId.html) values. Use `TypeIdHashMap` when +iteration order is unimportant and average O(1) removal is desired. Use `TypeIdIndexMap` when +insertion-order iteration is required. + +`TypeIdMap` remains an alias for the ordered `TypeIdIndexMap`, but is deprecated so users can +choose the appropriate behavior explicitly. `TypeIdMapEntry` is likewise deprecated in favor of +`TypeIdHashMapEntry` or `TypeIdIndexMapEntry`. Use `TypeIdHashMapExt` for the generic convenience +methods on `TypeIdHashMap`; the existing `TypeIdMapExt` continues to work with ordered maps. diff --git a/crates/bevy_animation/src/lib.rs b/crates/bevy_animation/src/lib.rs index 4b5337d5d80cd..a1379224fa944 100644 --- a/crates/bevy_animation/src/lib.rs +++ b/crates/bevy_animation/src/lib.rs @@ -45,7 +45,7 @@ use bevy_platform::{collections::HashMap, hash::NoOpHash}; use bevy_reflect::{prelude::ReflectDefault, Reflect, TypePath}; use bevy_time::Time; use bevy_transform::TransformSystems; -use bevy_utils::{PreHashMap, PreHashMapExt, TypeIdMap}; +use bevy_utils::{PreHashMap, PreHashMapExt, TypeIdHashMap}; use serde::{Deserialize, Serialize}; use thread_local::ThreadLocal; use tracing::{trace, warn}; @@ -778,7 +778,7 @@ pub struct AnimationEvaluationState { struct AnimationCurveEvaluators { component_property_curve_evaluators: PreHashMap<(TypeId, usize), Box>, - type_id_curve_evaluators: TypeIdMap>, + type_id_curve_evaluators: TypeIdHashMap>, } impl AnimationCurveEvaluators { @@ -804,10 +804,10 @@ impl AnimationCurveEvaluators { .component_property_curve_evaluators .get_or_insert_with(component_property, func), EvaluatorId::Type(type_id) => match self.type_id_curve_evaluators.entry(type_id) { - bevy_utils::TypeIdMapEntry::Occupied(occupied_entry) => { + bevy_utils::TypeIdHashMapEntry::Occupied(occupied_entry) => { &mut **occupied_entry.into_mut() } - bevy_utils::TypeIdMapEntry::Vacant(vacant_entry) => { + bevy_utils::TypeIdHashMapEntry::Vacant(vacant_entry) => { &mut **vacant_entry.insert(func()) } }, @@ -818,7 +818,7 @@ impl AnimationCurveEvaluators { #[derive(Default)] struct CurrentEvaluators { component_properties: PreHashMap<(TypeId, usize), ()>, - type_ids: TypeIdMap<()>, + type_ids: TypeIdHashMap<()>, } impl CurrentEvaluators { @@ -837,7 +837,7 @@ impl CurrentEvaluators { (visit)(EvaluatorId::ComponentField(&key))?; } - for (key, _) in self.type_ids.drain(..) { + for (key, _) in self.type_ids.drain() { (visit)(EvaluatorId::Type(key))?; } diff --git a/crates/bevy_app/src/plugin_group.rs b/crates/bevy_app/src/plugin_group.rs index c20798f1c9a6e..0fd64c8448185 100644 --- a/crates/bevy_app/src/plugin_group.rs +++ b/crates/bevy_app/src/plugin_group.rs @@ -4,7 +4,7 @@ use alloc::{ string::{String, ToString}, vec::Vec, }; -use bevy_utils::{TypeIdMap, TypeIdMapEntry as Entry}; +use bevy_utils::{TypeIdHashMap, TypeIdHashMapEntry as Entry}; use core::any::TypeId; use log::{debug, warn}; @@ -281,7 +281,7 @@ impl PluginGroup for PluginGroupBuilder { /// can be disabled, enabled or reordered. pub struct PluginGroupBuilder { group_name: String, - plugins: TypeIdMap, + plugins: TypeIdHashMap, order: Vec, } @@ -417,7 +417,7 @@ impl PluginGroupBuilder { for plugin_id in order { self.upsert_plugin_entry_state( plugin_id, - plugins.shift_remove(&plugin_id).unwrap(), + plugins.remove(&plugin_id).unwrap(), self.order.len(), ); @@ -566,7 +566,7 @@ impl PluginGroupBuilder { #[track_caller] pub fn finish(mut self, app: &mut App) { for ty in &self.order { - if let Some(entry) = self.plugins.shift_remove(ty) + if let Some(entry) = self.plugins.remove(ty) && entry.enabled { debug!("added plugin: {}", entry.plugin.name()); diff --git a/crates/bevy_asset/src/server/info.rs b/crates/bevy_asset/src/server/info.rs index 2d7db08bd6a88..c3b41cd98fba7 100644 --- a/crates/bevy_asset/src/server/info.rs +++ b/crates/bevy_asset/src/server/info.rs @@ -13,7 +13,7 @@ use alloc::{ use bevy_ecs::world::World; use bevy_platform::collections::{hash_map::Entry, HashMap, HashSet}; use bevy_tasks::Task; -use bevy_utils::{TypeIdMap, TypeIdMapEntry}; +use bevy_utils::{TypeIdHashMap, TypeIdHashMapEntry}; use core::{ any::{type_name, TypeId}, task::Waker, @@ -79,7 +79,7 @@ pub(crate) struct AssetServerStats { #[derive(Default)] pub(crate) struct AssetInfos { - path_to_index: HashMap, TypeIdMap>, + path_to_index: HashMap, TypeIdHashMap>, infos: HashMap, /// If set to `true`, this informs [`AssetInfos`] to track data relevant to watching for changes (such as `load_dependents`) /// This should only be set at startup. @@ -90,10 +90,10 @@ pub(crate) struct AssetInfos { /// Tracks living labeled assets for a given source asset. /// This should only be set when watching for changes to avoid unnecessary work. pub(crate) living_labeled_assets: HashMap, HashSet>>, - pub(crate) handle_providers: TypeIdMap, - pub(crate) dependency_loaded_event_sender: TypeIdMap, + pub(crate) handle_providers: TypeIdHashMap, + pub(crate) dependency_loaded_event_sender: TypeIdHashMap, pub(crate) dependency_failed_event_sender: - TypeIdMap, AssetLoadError)>, + TypeIdHashMap, AssetLoadError)>, pub(crate) pending_tasks: HashMap>, /// The stats that have collected during usage of the asset server. pub(crate) stats: AssetServerStats, @@ -133,7 +133,7 @@ impl AssetInfos { fn create_handle_internal( infos: &mut HashMap, - handle_providers: &TypeIdMap, + handle_providers: &TypeIdHashMap, living_labeled_assets: &mut HashMap, HashSet>>, watching_for_changes: bool, type_id: TypeId, @@ -222,7 +222,7 @@ impl AssetInfos { .ok_or(GetOrCreateHandleInternalError::HandleMissingButTypeIdNotSpecified)?; match handles.entry(type_id) { - TypeIdMapEntry::Occupied(entry) => { + TypeIdHashMapEntry::Occupied(entry) => { let index = *entry.get(); // if there is a path_to_id entry, info always exists let info = self @@ -264,7 +264,7 @@ impl AssetInfos { } } // The entry does not exist, so this is a "fresh" asset load. We must create a new handle - TypeIdMapEntry::Vacant(entry) => { + TypeIdHashMapEntry::Vacant(entry) => { let should_load = match loading_mode { HandleLoadingMode::NotLoading => false, HandleLoadingMode::Request | HandleLoadingMode::Force => true, @@ -709,7 +709,7 @@ impl AssetInfos { fn process_handle_drop_internal( infos: &mut HashMap, - path_to_id: &mut HashMap, TypeIdMap>, + path_to_id: &mut HashMap, TypeIdHashMap>, loader_dependents: &mut HashMap, HashSet>>, living_labeled_assets: &mut HashMap, HashSet>>, pending_tasks: &mut HashMap>, @@ -746,7 +746,7 @@ impl AssetInfos { } if let Some(map) = path_to_id.get_mut(path) { - map.shift_remove(&type_id); + map.remove(&type_id); if map.is_empty() { path_to_id.remove(path); diff --git a/crates/bevy_asset/src/server/loaders.rs b/crates/bevy_asset/src/server/loaders.rs index adc24d9a5a486..892521b37a271 100644 --- a/crates/bevy_asset/src/server/loaders.rs +++ b/crates/bevy_asset/src/server/loaders.rs @@ -6,7 +6,7 @@ use alloc::{boxed::Box, sync::Arc, vec::Vec}; use async_broadcast::RecvError; use bevy_platform::collections::HashMap; use bevy_tasks::IoTaskPool; -use bevy_utils::TypeIdMap; +use bevy_utils::TypeIdHashMap; use core::any::TypeId; use thiserror::Error; use tracing::warn; @@ -14,7 +14,7 @@ use tracing::warn; #[derive(Default)] pub(crate) struct AssetLoaders { loaders: Vec, - type_id_to_loaders: TypeIdMap>, + type_id_to_loaders: TypeIdHashMap>, extension_to_loaders: HashMap, Vec>, type_path_to_loader: HashMap<&'static str, usize>, type_path_to_preregistered_loader: HashMap<&'static str, usize>, diff --git a/crates/bevy_camera/src/visibility/mod.rs b/crates/bevy_camera/src/visibility/mod.rs index 2bd1da2da4f7e..f64fc718c84e1 100644 --- a/crates/bevy_camera/src/visibility/mod.rs +++ b/crates/bevy_camera/src/visibility/mod.rs @@ -48,7 +48,7 @@ use bevy_asset::{AssetEventSystems, Assets}; use bevy_ecs::{prelude::*, VariantDefaults}; use bevy_reflect::{std_traits::ReflectDefault, Reflect}; use bevy_transform::{components::GlobalTransform, TransformSystems}; -use bevy_utils::{Parallel, TypeIdMap}; +use bevy_utils::{Parallel, TypeIdHashMap}; use smallvec::SmallVec; use crate::{ @@ -343,7 +343,7 @@ pub struct DynamicSkinnedMeshBounds; #[reflect(Component, Default, Debug, Clone)] pub struct VisibleEntities { #[reflect(ignore, clone)] - pub entities: TypeIdMap>, + pub entities: TypeIdHashMap>, } impl Default for VisibleEntities { @@ -355,7 +355,7 @@ impl Default for VisibleEntities { // We could handle this case in the `DirtySpecializations` methods // instead, but that would complicate what are already some very // complicated method signatures. So it's simpler to just do this. - let mut entities = TypeIdMap::default(); + let mut entities = TypeIdHashMap::default(); entities.insert(TypeId::of::(), vec![]); VisibleEntities { entities } } @@ -746,7 +746,7 @@ fn reset_view_visibility(mut reset_query: Query<&mut ViewVisibility, Without>>>, + mut thread_queues: Local>>>, mut view_query: Query<( Entity, &mut VisibleEntities, diff --git a/crates/bevy_ecs/src/bundle/info.rs b/crates/bevy_ecs/src/bundle/info.rs index c48832439d4eb..0bb89f458bc23 100644 --- a/crates/bevy_ecs/src/bundle/info.rs +++ b/crates/bevy_ecs/src/bundle/info.rs @@ -4,7 +4,7 @@ use bevy_platform::{ hash::FixedHasher, }; use bevy_ptr::{MovingPtr, OwningPtr}; -use bevy_utils::TypeIdMap; +use bevy_utils::TypeIdHashMap; use core::{any::TypeId, ptr::NonNull}; use indexmap::{IndexMap, IndexSet}; @@ -393,9 +393,9 @@ pub(crate) enum ArchetypeMoveType { pub struct Bundles { bundle_infos: Vec, /// Cache static [`BundleId`] - bundle_ids: TypeIdMap, + bundle_ids: TypeIdHashMap, /// Cache bundles, which contains both explicit and required components of [`Bundle`] - contributed_bundle_ids: TypeIdMap, + contributed_bundle_ids: TypeIdHashMap, /// Cache dynamic [`BundleId`] with multiple components dynamic_bundle_ids: HashMap, BundleId>, dynamic_bundle_storages: HashMap>, diff --git a/crates/bevy_ecs/src/component/info.rs b/crates/bevy_ecs/src/component/info.rs index 76b39eccd52a2..f3ff4a19a03f6 100644 --- a/crates/bevy_ecs/src/component/info.rs +++ b/crates/bevy_ecs/src/component/info.rs @@ -3,7 +3,7 @@ use bevy_platform::{hash::FixedHasher, sync::PoisonError}; use bevy_ptr::OwningPtr; #[cfg(feature = "bevy_reflect")] use bevy_reflect::Reflect; -use bevy_utils::{prelude::DebugName, TypeIdMap}; +use bevy_utils::{prelude::DebugName, TypeIdHashMap}; use core::{ alloc::Layout, any::{Any, TypeId}, @@ -360,7 +360,7 @@ impl ComponentDescriptor { #[derive(Debug, Default)] pub struct Components { pub(super) components: Vec>, - pub(super) indices: TypeIdMap, + pub(super) indices: TypeIdHashMap, // This is kept internal and local to verify that no deadlocks can occur. pub(super) queued: bevy_platform::sync::RwLock, } diff --git a/crates/bevy_ecs/src/component/register.rs b/crates/bevy_ecs/src/component/register.rs index e06eddf021e0a..a13a1bb29889f 100644 --- a/crates/bevy_ecs/src/component/register.rs +++ b/crates/bevy_ecs/src/component/register.rs @@ -1,6 +1,6 @@ use alloc::vec::Vec; use bevy_platform::sync::PoisonError; -use bevy_utils::TypeIdMap; +use bevy_utils::TypeIdHashMap; use core::any::Any; use core::{any::TypeId, fmt::Debug, ops::Deref}; @@ -132,12 +132,7 @@ impl<'w> ComponentsRegistrator<'w> { .unwrap_or_else(PoisonError::into_inner); queued.components.keys().next().copied().map(|type_id| { // SAFETY: the id just came from a valid iterator. - unsafe { - queued - .components - .shift_remove(&type_id) - .debug_checked_unwrap() - } + unsafe { queued.components.remove(&type_id).debug_checked_unwrap() } }) } { registrator.register(self); @@ -193,7 +188,7 @@ impl<'w> ComponentsRegistrator<'w> { .get_mut() .unwrap_or_else(PoisonError::into_inner) .components - .shift_remove(&type_id) + .remove(&type_id) { // If we are trying to register something that has already been queued, we respect the queue. // Just like if we are trying to register something that already is, we respect the first registration. @@ -329,7 +324,7 @@ impl<'w> ComponentsRegistrator<'w> { .get_mut() .unwrap_or_else(PoisonError::into_inner) .components - .shift_remove(&type_id) + .remove(&type_id) { // If we are trying to register something that has already been queued, we respect the queue. // Just like if we are trying to register something that already is, we respect the first registration. @@ -391,7 +386,7 @@ impl QueuedRegistration { /// Allows queuing components to be registered. #[derive(Default)] pub struct QueuedComponents { - pub(super) components: TypeIdMap, + pub(super) components: TypeIdHashMap, pub(super) dynamic_registrations: Vec, } diff --git a/crates/bevy_ecs/src/schedule/graph/mod.rs b/crates/bevy_ecs/src/schedule/graph/mod.rs index f0da67d88b3bd..911ab6626ef66 100644 --- a/crates/bevy_ecs/src/schedule/graph/mod.rs +++ b/crates/bevy_ecs/src/schedule/graph/mod.rs @@ -4,7 +4,7 @@ use core::{ fmt::Debug, }; -use bevy_utils::TypeIdMap; +use bevy_utils::TypeIdHashMap; use crate::schedule::InternedSystemSet; @@ -28,7 +28,7 @@ pub(crate) enum DependencyKind { pub(crate) struct Dependency { pub(crate) kind: DependencyKind, pub(crate) set: InternedSystemSet, - pub(crate) options: TypeIdMap>, + pub(crate) options: TypeIdHashMap>, } impl Dependency { diff --git a/crates/bevy_ecs/src/schedule/pass.rs b/crates/bevy_ecs/src/schedule/pass.rs index d0d42e0e98b4a..7f4bd402b62ef 100644 --- a/crates/bevy_ecs/src/schedule/pass.rs +++ b/crates/bevy_ecs/src/schedule/pass.rs @@ -6,7 +6,7 @@ use core::{ }; use bevy_platform::{collections::HashSet, hash::FixedHasher}; -use bevy_utils::TypeIdMap; +use bevy_utils::TypeIdHashMap; use indexmap::IndexSet; use super::{DiGraph, NodeId, ScheduleBuildError, ScheduleGraph}; @@ -127,7 +127,12 @@ pub(super) trait ScheduleBuildPassObj: Send + Sync + Debug { dependency_flattening: &DiGraph, dependencies_to_add: &mut Vec<(NodeId, NodeId)>, ); - fn add_dependency(&mut self, from: NodeId, to: NodeId, all_options: &TypeIdMap>); + fn add_dependency( + &mut self, + from: NodeId, + to: NodeId, + all_options: &TypeIdHashMap>, + ); } impl ScheduleBuildPassObj for T { @@ -149,7 +154,12 @@ impl ScheduleBuildPassObj for T { let iter = self.collapse_set(set, systems, dependency_flattening); dependencies_to_add.extend(iter); } - fn add_dependency(&mut self, from: NodeId, to: NodeId, all_options: &TypeIdMap>) { + fn add_dependency( + &mut self, + from: NodeId, + to: NodeId, + all_options: &TypeIdHashMap>, + ) { let option = all_options .get(&TypeId::of::()) .and_then(|x| x.downcast_ref::()); diff --git a/crates/bevy_ecs/src/schedule/schedule.rs b/crates/bevy_ecs/src/schedule/schedule.rs index 1f9f4fc1d0bff..518d79bc485b1 100644 --- a/crates/bevy_ecs/src/schedule/schedule.rs +++ b/crates/bevy_ecs/src/schedule/schedule.rs @@ -15,7 +15,7 @@ use bevy_platform::{ collections::{HashMap, HashSet}, hash::FixedHasher, }; -use bevy_utils::{default, TypeIdMap}; +use bevy_utils::{default, TypeIdHashMap}; use core::{ any::{Any, TypeId}, fmt::{Debug, Write}, @@ -285,7 +285,7 @@ pub enum Chain { Unchained, /// Systems are chained. `before -> after` ordering constraints /// will be added between the successive elements. - Chained(TypeIdMap>), + Chained(TypeIdHashMap>), } impl Chain { diff --git a/crates/bevy_ecs/src/schedule/stepping.rs b/crates/bevy_ecs/src/schedule/stepping.rs index d1aee648c1a27..98e1160448531 100644 --- a/crates/bevy_ecs/src/schedule/stepping.rs +++ b/crates/bevy_ecs/src/schedule/stepping.rs @@ -5,7 +5,7 @@ use crate::{ }; use alloc::vec::Vec; use bevy_platform::collections::HashMap; -use bevy_utils::TypeIdMap; +use bevy_utils::TypeIdHashMap; use core::any::TypeId; use fixedbitset::FixedBitSet; use log::{info, warn}; @@ -608,7 +608,7 @@ struct ScheduleState { /// changes to system behavior that should be applied the next time /// [`ScheduleState::skipped_systems()`] is called - behavior_updates: TypeIdMap>, + behavior_updates: TypeIdHashMap>, /// This field contains the first steppable system in the schedule. first: Option, diff --git a/crates/bevy_gizmos/src/config.rs b/crates/bevy_gizmos/src/config.rs index 9d3fc9510089f..597e504da3459 100644 --- a/crates/bevy_gizmos/src/config.rs +++ b/crates/bevy_gizmos/src/config.rs @@ -7,7 +7,7 @@ use {crate::GizmoAsset, bevy_asset::Handle, bevy_ecs::component::Component}; use bevy_ecs::{reflect::ReflectResource, resource::Resource, template::FromTemplate}; use bevy_reflect::{std_traits::ReflectDefault, Reflect, TypePath}; -use bevy_utils::TypeIdMap; +use bevy_utils::TypeIdHashMap; use core::{ any::TypeId, hash::Hash, @@ -99,7 +99,7 @@ pub struct ErasedGizmoConfigGroup; pub struct GizmoConfigStore { // INVARIANT: must map TypeId::of::() to correct type T #[reflect(ignore)] - store: TypeIdMap<(GizmoConfig, Box)>, + store: TypeIdHashMap<(GizmoConfig, Box)>, } impl GizmoConfigStore { diff --git a/crates/bevy_gizmos/src/lib.rs b/crates/bevy_gizmos/src/lib.rs index 212f04a13a780..462412d6f68e2 100755 --- a/crates/bevy_gizmos/src/lib.rs +++ b/crates/bevy_gizmos/src/lib.rs @@ -92,7 +92,7 @@ use bevy_reflect::TypePath; use crate::{config::ErasedGizmoConfigGroup, gizmos::GizmoBuffer}; use bevy_time::Fixed; -use bevy_utils::TypeIdMap; +use bevy_utils::TypeIdIndexMap; use config::{DefaultGizmoConfigGroup, GizmoConfig, GizmoConfigGroup, GizmoConfigStore}; use core::{any::TypeId, marker::PhantomData, mem}; use gizmos::{GizmoStorage, Swap}; @@ -198,18 +198,18 @@ impl AppGizmoBuilder for App { } /// Holds handles to the line gizmos for each gizmo configuration group -// As `TypeIdMap` iteration order depends on the order of insertions and deletions, this uses +// As `TypeIdIndexMap` iteration order depends on the order of insertions and deletions, this uses // `Option` to be able to reserve the slot when creating the gizmo configuration group. // That way iteration order is stable across executions and depends on the order of configuration // group creation. #[derive(Resource, Default)] pub struct GizmoHandles { - handles: TypeIdMap>>, + handles: TypeIdIndexMap>>, } impl GizmoHandles { /// The handles to the gizmo assets of each gizmo configuration group. - pub fn handles(&self) -> &TypeIdMap>> { + pub fn handles(&self) -> &TypeIdIndexMap>> { &self.handles } } diff --git a/crates/bevy_pbr/src/render/gpu_preprocess.rs b/crates/bevy_pbr/src/render/gpu_preprocess.rs index 18263965b116c..faf883422cfd7 100644 --- a/crates/bevy_pbr/src/render/gpu_preprocess.rs +++ b/crates/bevy_pbr/src/render/gpu_preprocess.rs @@ -68,7 +68,7 @@ use bevy_render::{ GpuResourceAppExt, Render, RenderApp, RenderSystems, }; use bevy_shader::Shader; -use bevy_utils::{default, TypeIdMap}; +use bevy_utils::{default, TypeIdHashMap}; use bitflags::bitflags; use smallvec::{smallvec, SmallVec}; use tracing::warn; @@ -328,7 +328,7 @@ bitflags! { /// (e.g. [`bevy_core_pipeline::core_3d::Opaque3d`]) to the /// [`PhasePreprocessBindGroups`] for that phase. #[derive(Component, Clone, Deref, DerefMut)] -pub struct PreprocessBindGroups(pub TypeIdMap); +pub struct PreprocessBindGroups(pub TypeIdHashMap); /// The compute shader bind group for the mesh preprocessing step for a single /// render phase on a single view. @@ -382,7 +382,9 @@ pub enum PhasePreprocessBindGroups { /// There's one set of bind group for each phase. Phases are keyed off their /// [`core::any::TypeId`]. #[derive(Resource, Default, Deref, DerefMut)] -pub struct BuildIndirectParametersBindGroups(pub TypeIdMap); +pub struct BuildIndirectParametersBindGroups( + pub TypeIdHashMap, +); impl BuildIndirectParametersBindGroups { /// Creates a new, empty [`BuildIndirectParametersBindGroups`] table. @@ -2166,7 +2168,7 @@ pub fn prepare_preprocess_bind_groups( // Loop over each view. for (view_entity, view) in &views { - let mut bind_groups = TypeIdMap::default(); + let mut bind_groups = TypeIdHashMap::default(); // Loop over each phase. for (phase_type_id, phase_instance_buffers) in phase_instance_buffers { @@ -3235,7 +3237,7 @@ fn create_bin_unpacking_bind_groups( pipeline_cache: &PipelineCache, preprocess_pipelines: &PreprocessPipelines, indirect_parameters_buffers: &IndirectParametersBuffers, - phase_instance_buffers: &TypeIdMap>, + phase_instance_buffers: &TypeIdHashMap>, scene_unpacking_buffers: &SceneUnpackingBuffers, view_entity: &RetainedViewEntity, ) { diff --git a/crates/bevy_pbr/src/render/mesh.rs b/crates/bevy_pbr/src/render/mesh.rs index 5b085f48e5a56..ecaf4b9da11d4 100644 --- a/crates/bevy_pbr/src/render/mesh.rs +++ b/crates/bevy_pbr/src/render/mesh.rs @@ -72,7 +72,7 @@ use bevy_render::{ }; use bevy_shader::{load_shader_library, Shader, ShaderDefVal, ShaderSettings}; use bevy_transform::components::GlobalTransform; -use bevy_utils::{default, Parallel, TypeIdMap}; +use bevy_utils::{default, Parallel, TypeIdHashMap}; use core::any::TypeId; use core::iter; use core::mem::size_of; @@ -3822,7 +3822,7 @@ pub enum MeshBindGroups { CpuPreprocessing(MeshPhaseBindGroups), /// A mapping from the type ID of a phase (e.g. [`Opaque3d`]) to the mesh /// bind groups for that phase. - GpuPreprocessing(TypeIdMap), + GpuPreprocessing(TypeIdHashMap), } impl MeshPhaseBindGroups { @@ -4007,7 +4007,7 @@ pub fn prepare_mesh_bind_groups( if let Some(gpu_batched_instance_buffers) = gpu_batched_instance_buffers { // Reuse allocations let mut gpu_preprocessing_mesh_bind_groups = match mesh_bind_groups.as_deref_mut() { - None | Some(MeshBindGroups::CpuPreprocessing(_)) => TypeIdMap::default(), + None | Some(MeshBindGroups::CpuPreprocessing(_)) => TypeIdHashMap::default(), Some(MeshBindGroups::GpuPreprocessing(gpu_preprocessing_mesh_bind_groups)) => { core::mem::take(gpu_preprocessing_mesh_bind_groups) } diff --git a/crates/bevy_reflect/src/attributes.rs b/crates/bevy_reflect/src/attributes.rs index 17c6298a8ab64..f10c1edaa087a 100644 --- a/crates/bevy_reflect/src/attributes.rs +++ b/crates/bevy_reflect/src/attributes.rs @@ -3,7 +3,7 @@ use crate::Reflect; use alloc::boxed::Box; use bevy_platform::sync::Arc; -use bevy_utils::TypeIdMap; +use bevy_utils::TypeIdIndexMap; use core::{ any::TypeId, fmt::{Debug, Formatter}, @@ -39,11 +39,11 @@ use core::{ /// [`Reflect` derive macro]: derive@crate::Reflect #[derive(Default, Clone)] pub struct CustomAttributes { - attributes: Option>>, + attributes: Option>>, } impl CustomAttributes { - fn new(attributes: TypeIdMap) -> Self { + fn new(attributes: TypeIdIndexMap) -> Self { Self { attributes: if attributes.is_empty() { None @@ -206,7 +206,7 @@ macro_rules! impl_custom_attribute_methods { /// ``` #[derive(Default)] pub struct CustomAttributesBuilder { - attributes: TypeIdMap, + attributes: TypeIdIndexMap, } impl CustomAttributesBuilder { diff --git a/crates/bevy_reflect/src/convert.rs b/crates/bevy_reflect/src/convert.rs index 4bc03ec616390..216259b242871 100644 --- a/crates/bevy_reflect/src/convert.rs +++ b/crates/bevy_reflect/src/convert.rs @@ -4,7 +4,7 @@ use alloc::boxed::Box; use core::{any::TypeId, marker::PhantomData}; -use bevy_utils::TypeIdMap; +use bevy_utils::TypeIdHashMap; use crate::{Reflect, TypePath}; @@ -36,7 +36,7 @@ use crate::{Reflect, TypePath}; pub struct ReflectConvert { /// A mapping from the type to be converted *from* to its associated /// [`Converter`]. - conversions: TypeIdMap>, + conversions: TypeIdHashMap>, } /// An internal trait that wraps a conversion function in an untyped interface. diff --git a/crates/bevy_reflect/src/type_registry.rs b/crates/bevy_reflect/src/type_registry.rs index 45be0f653af4d..91da21e08500e 100644 --- a/crates/bevy_reflect/src/type_registry.rs +++ b/crates/bevy_reflect/src/type_registry.rs @@ -9,7 +9,7 @@ use bevy_platform::{ }; use bevy_ptr::{Ptr, PtrMut}; use bevy_reflect::CreateTypeData; -use bevy_utils::TypeIdMap; +use bevy_utils::TypeIdHashMap; use core::{ any::TypeId, fmt::Debug, @@ -30,7 +30,7 @@ use serde::{Deserialize, Serialize}; /// [Registering]: TypeRegistry::register /// [crate-level documentation]: crate pub struct TypeRegistry { - registrations: TypeIdMap, + registrations: TypeIdHashMap, short_path_to_id: HashMap<&'static str, TypeId>, type_path_to_id: HashMap<&'static str, TypeId>, ambiguous_names: HashSet<&'static str>, @@ -629,7 +629,7 @@ impl TypeRegistryArc { /// /// [crate-level documentation]: crate pub struct TypeRegistration { - data: TypeIdMap>, + data: TypeIdHashMap>, type_info: &'static TypeInfo, } @@ -821,7 +821,7 @@ impl TypeRegistration { impl Clone for TypeRegistration { fn clone(&self) -> Self { - let mut data = TypeIdMap::default(); + let mut data = TypeIdHashMap::default(); for (id, type_data) in &self.data { data.insert(*id, (*type_data).clone_type_data()); } diff --git a/crates/bevy_reflect/src/utility.rs b/crates/bevy_reflect/src/utility.rs index 580432e5cdda4..fbe1d6f8072f9 100644 --- a/crates/bevy_reflect/src/utility.rs +++ b/crates/bevy_reflect/src/utility.rs @@ -6,7 +6,7 @@ use bevy_platform::{ hash::{DefaultHasher, FixedHasher, NoOpHash}, sync::{OnceLock, PoisonError, RwLock}, }; -use bevy_utils::TypeIdMap; +use bevy_utils::TypeIdHashMap; use core::{ any::{Any, TypeId}, hash::BuildHasher, @@ -223,7 +223,7 @@ impl Default for NonGenericTypeCell { /// ``` /// [`impl_type_path`]: crate::impl_type_path /// [`TypePath`]: crate::TypePath -pub struct GenericTypeCell(RwLock>); +pub struct GenericTypeCell(RwLock>); /// See [`GenericTypeCell`]. pub type GenericTypeInfoCell = GenericTypeCell; @@ -233,7 +233,7 @@ pub type GenericTypePathCell = GenericTypeCell; impl GenericTypeCell { /// Initialize a [`GenericTypeCell`] for generic types. pub const fn new() -> Self { - Self(RwLock::new(TypeIdMap::with_hasher(NoOpHash))) + Self(RwLock::new(TypeIdHashMap::with_hasher(NoOpHash))) } /// Returns a reference to the [`TypedProperty`] stored in the cell. @@ -278,7 +278,7 @@ impl GenericTypeCell { write_lock .entry(type_id) - .insert_entry({ + .insert({ // We leak here in order to obtain a `&'static` reference. // Otherwise, we won't be able to return a reference due to the `RwLock`. // This should be okay, though, since we expect it to remain statically diff --git a/crates/bevy_render/src/batching/gpu_preprocessing.rs b/crates/bevy_render/src/batching/gpu_preprocessing.rs index c044bdf5c3bfd..9b18ae31e89b0 100644 --- a/crates/bevy_render/src/batching/gpu_preprocessing.rs +++ b/crates/bevy_render/src/batching/gpu_preprocessing.rs @@ -24,7 +24,7 @@ use bevy_log::{error, info_once}; use bevy_math::UVec4; use bevy_platform::collections::{hash_map::Entry, HashMap, HashSet}; use bevy_tasks::ComputeTaskPool; -use bevy_utils::{default, TypeIdMap}; +use bevy_utils::{default, TypeIdHashMap}; use bytemuck::{Pod, Zeroable}; use encase::{internal::WriteInto, ShaderSize}; use nonmax::NonMaxU32; @@ -187,7 +187,7 @@ where /// /// The keys of this map are the type IDs of each phase: e.g. `Opaque3d`, /// `AlphaMask3d`, etc. - pub phase_instance_buffers: TypeIdMap>, + pub phase_instance_buffers: TypeIdHashMap>, } impl Default for BatchedInstanceBuffers @@ -199,7 +199,7 @@ where BatchedInstanceBuffers { current_input_buffer: InstanceInputUniformBuffer::new(), previous_input_buffer: PreviousInstanceInputUniformBuffer::new(), - phase_instance_buffers: TypeIdMap::default(), + phase_instance_buffers: TypeIdHashMap::default(), } } } @@ -930,7 +930,7 @@ pub struct IndirectParametersBuffers { /// /// Examples of phase type IDs are `Opaque3d` and `AlphaMask3d`. #[deref] - pub buffers: TypeIdMap, + pub buffers: TypeIdHashMap, } /// Configuration for [`IndirectParametersBuffers`]. diff --git a/crates/bevy_render/src/material_bind_groups.rs b/crates/bevy_render/src/material_bind_groups.rs index d11936c6dffea..7419bf9c4c4a2 100644 --- a/crates/bevy_render/src/material_bind_groups.rs +++ b/crates/bevy_render/src/material_bind_groups.rs @@ -14,7 +14,7 @@ use bevy_ecs::{ }; use bevy_platform::collections::{hash_map::Entry, HashMap, HashSet}; use bevy_reflect::{prelude::ReflectDefault, Reflect}; -use bevy_utils::{default, TypeIdMap}; +use bevy_utils::{default, TypeIdHashMap}; use bytemuck::{Pod, Zeroable}; use core::hash::Hash; use core::{cmp::Ordering, iter, mem, ops::Range}; @@ -49,7 +49,7 @@ use crate::{ pub struct MaterialBindGroupPlugin; #[derive(Resource, Deref, DerefMut, Default)] -pub struct MaterialBindGroupAllocators(TypeIdMap); +pub struct MaterialBindGroupAllocators(TypeIdHashMap); /// A resource that maps each untyped material ID to its binding. /// diff --git a/crates/bevy_render/src/render_phase/draw.rs b/crates/bevy_render/src/render_phase/draw.rs index 13d4f67da52eb..bd488727af46b 100644 --- a/crates/bevy_render/src/render_phase/draw.rs +++ b/crates/bevy_render/src/render_phase/draw.rs @@ -9,7 +9,7 @@ use bevy_ecs::{ system::{ReadOnlySystemParam, SystemParam, SystemParamItem, SystemState}, world::World, }; -use bevy_utils::TypeIdMap; +use bevy_utils::TypeIdHashMap; use core::{any::TypeId, fmt::Debug}; use std::sync::{PoisonError, RwLock, RwLockReadGuard, RwLockWriteGuard}; use thiserror::Error; @@ -56,7 +56,7 @@ pub enum DrawError { /// For retrieval, the [`Draw`] functions are mapped to their respective [`TypeId`]s. pub struct DrawFunctionsInternal { pub draw_functions: Vec>>, - pub indices: TypeIdMap, + pub indices: TypeIdHashMap, } impl DrawFunctionsInternal

{ diff --git a/crates/bevy_render/src/view/visibility/mod.rs b/crates/bevy_render/src/view/visibility/mod.rs index a500afc9dcfef..dd1a462eda903 100644 --- a/crates/bevy_render/src/view/visibility/mod.rs +++ b/crates/bevy_render/src/view/visibility/mod.rs @@ -14,7 +14,7 @@ use bevy_ecs::{ use bevy_log::info_span; use bevy_platform::collections::{HashMap, HashSet}; use bevy_reflect::{prelude::ReflectDefault, Reflect}; -use bevy_utils::TypeIdMap; +use bevy_utils::TypeIdHashMap; use crate::{ sync_world::{MainEntity, MainEntityHashMap, RenderEntity}, @@ -45,7 +45,7 @@ pub use range::*; pub struct RenderVisibleEntities { /// Entities visible from this view or subview, sorted by /// [`VisibilityClass`]. - pub classes: TypeIdMap, + pub classes: TypeIdHashMap, } /// Collection of entities visible from a single light. @@ -125,7 +125,7 @@ pub struct RenderVisibleEntitiesClass { pub struct RenderExtractedVisibleEntities { /// Entities that the CPU has determined to be visible from this view or /// subview, sorted by [`VisibilityClass`]. - pub classes: TypeIdMap, + pub classes: TypeIdHashMap, } /// The entities that the CPU has determined are visible from a single diff --git a/crates/bevy_scene/src/resolved_scene.rs b/crates/bevy_scene/src/resolved_scene.rs index 46383461a1881..0964d3b437e25 100644 --- a/crates/bevy_scene/src/resolved_scene.rs +++ b/crates/bevy_scene/src/resolved_scene.rs @@ -10,7 +10,7 @@ use bevy_ecs::{ world::{EntityWorldMut, World}, }; use bevy_platform::collections::HashSet; -use bevy_utils::TypeIdMap; +use bevy_utils::{TypeIdHashMap, TypeIdIndexMap}; use core::any::{Any, TypeId}; use thiserror::Error; @@ -171,12 +171,12 @@ pub struct ResolvedScene { /// /// [`Children`]: bevy_ecs::hierarchy::Children // PERF: special casing Children might make sense here to avoid hashing - related: TypeIdMap, + related: TypeIdIndexMap, /// The cached [`ScenePatch`] to apply _first_ before applying this [`ResolvedScene`]. cached: Option, /// A [`TypeId`] to `templates` index mapping. If a [`Template`] is intended to be shared / patched across scenes, it should be registered /// here. - template_indices: TypeIdMap, + template_indices: TypeIdHashMap, /// A list of all [`SceneEntityReference`] values associated with this entity. There can be more than one if this scene uses /// "flattened" caching. pub entity_references: Vec, @@ -436,13 +436,13 @@ impl ResolvedScene { template: Box, ) { match self.template_indices.entry(type_id) { - bevy_utils::TypeIdMapEntry::Occupied(occupied_entry) => { + bevy_utils::TypeIdHashMapEntry::Occupied(occupied_entry) => { let index = *occupied_entry.get(); // SAFETY: just looked up a valid index let stored_template = unsafe { self.component_templates.get_unchecked_mut(index) }; *stored_template = template; } - bevy_utils::TypeIdMapEntry::Vacant(vacant_entry) => { + bevy_utils::TypeIdHashMapEntry::Vacant(vacant_entry) => { vacant_entry.insert(self.component_templates.len()); self.component_templates.push(template); } diff --git a/crates/bevy_utils/src/map.rs b/crates/bevy_utils/src/map.rs index f682183f99821..69b81b7ad8bf7 100644 --- a/crates/bevy_utils/src/map.rs +++ b/crates/bevy_utils/src/map.rs @@ -6,7 +6,17 @@ use bevy_platform::{ }; use indexmap::map::IndexMap; -/// The [`Entry`][indexmap::map::Entry] type for [`TypeIdMap`]. +/// The [`hash_map::Entry`][bevy_platform::collections::hash_map::Entry] type for [`TypeIdHashMap`]. +pub use bevy_platform::collections::hash_map::Entry as TypeIdHashMapEntry; + +/// The [`Entry`][indexmap::map::Entry] type for [`TypeIdIndexMap`]. +pub use indexmap::map::Entry as TypeIdIndexMapEntry; + +/// Deprecated compatibility alias for [`TypeIdIndexMapEntry`]. +#[deprecated( + since = "0.20.0", + note = "use `TypeIdHashMapEntry` or `TypeIdIndexMapEntry` instead" +)] pub use indexmap::map::Entry as TypeIdMapEntry; /// A [`HashMap`] pre-configured to use [`Hashed`] keys and [`PassHash`] passthrough hashing. @@ -38,27 +48,36 @@ impl PreHashMapExt for PreHashMap = HashMap; + +/// A specialized index map type with a key of [`TypeId`]. /// Iteration order only depends on the order of insertions and deletions. -pub type TypeIdMap = IndexMap; +pub type TypeIdIndexMap = IndexMap; -/// Extension trait to make use of [`TypeIdMap`] more ergonomic. +/// Deprecated compatibility alias for [`TypeIdIndexMap`]. +#[deprecated( + since = "0.20.0", + note = "use `TypeIdHashMap` or `TypeIdIndexMap` instead" +)] +pub type TypeIdMap = TypeIdIndexMap; + +/// Extension trait to make use of [`TypeIdIndexMap`] more ergonomic. /// -/// Each function on this trait is a trivial wrapper for a function -/// on [`IndexMap`], replacing a `TypeId` key with a -/// generic parameter `T`. +/// Each function on this trait is a trivial wrapper for a map function, +/// replacing a `TypeId` key with a generic parameter `T`. /// /// # Examples /// /// ```rust /// # use std::any::TypeId; -/// # use bevy_utils::TypeIdMap; +/// # use bevy_utils::TypeIdIndexMap; /// use bevy_utils::TypeIdMapExt; /// /// struct MyType; /// -/// // Using the built-in `HashMap` functions requires manually looking up `TypeId`s. -/// let mut map = TypeIdMap::default(); +/// // Using the built-in map functions requires manually looking up `TypeId`s. +/// let mut map = TypeIdIndexMap::default(); /// map.insert(TypeId::of::(), 7); /// assert_eq!(map.get(&TypeId::of::()), Some(&7)); /// @@ -84,10 +103,10 @@ pub trait TypeIdMapExt { fn remove_type(&mut self) -> Option; /// Gets the type `T`'s entry in the map for in-place manipulation. - fn entry_type(&mut self) -> TypeIdMapEntry<'_, TypeId, V>; + fn entry_type(&mut self) -> TypeIdIndexMapEntry<'_, TypeId, V>; } -impl TypeIdMapExt for TypeIdMap { +impl TypeIdMapExt for TypeIdIndexMap { #[inline] fn insert_type(&mut self, v: V) -> Option { self.insert(TypeId::of::(), v) @@ -109,7 +128,60 @@ impl TypeIdMapExt for TypeIdMap { } #[inline] - fn entry_type(&mut self) -> TypeIdMapEntry<'_, TypeId, V> { + fn entry_type(&mut self) -> TypeIdIndexMapEntry<'_, TypeId, V> { + self.entry(TypeId::of::()) + } +} + +/// Extension trait to make use of [`TypeIdHashMap`] more ergonomic. +pub trait TypeIdHashMapExt { + /// Inserts a value for the type `T`. + /// + /// If the map did not previously contain this key then [`None`] is returned, + /// otherwise the value for this key is updated and the old value returned. + fn insert_type(&mut self, v: V) -> Option; + + /// Returns a reference to the value for type `T`, if one exists. + fn get_type(&self) -> Option<&V>; + + /// Returns a mutable reference to the value for type `T`, if one exists. + fn get_type_mut(&mut self) -> Option<&mut V>; + + /// Removes type `T` from the map, returning the value for this + /// key if it was previously present. + fn remove_type(&mut self) -> Option; + + /// Gets the type `T`'s entry in the map for in-place manipulation. + fn entry_type( + &mut self, + ) -> TypeIdHashMapEntry<'_, TypeId, V, NoOpHash>; +} + +impl TypeIdHashMapExt for TypeIdHashMap { + #[inline] + fn insert_type(&mut self, v: V) -> Option { + self.insert(TypeId::of::(), v) + } + + #[inline] + fn get_type(&self) -> Option<&V> { + self.get(&TypeId::of::()) + } + + #[inline] + fn get_type_mut(&mut self) -> Option<&mut V> { + self.get_mut(&TypeId::of::()) + } + + #[inline] + fn remove_type(&mut self) -> Option { + self.remove(&TypeId::of::()) + } + + #[inline] + fn entry_type( + &mut self, + ) -> TypeIdHashMapEntry<'_, TypeId, V, NoOpHash> { self.entry(TypeId::of::()) } }