Use TypeIdMap whenever possible (#11684)
Use `TypeIdMap<T>` instead of `HashMap<TypeId, T>` - ~~`TypeIdMap` was in `bevy_ecs`. I've kept it there because of #11478~~ - ~~I haven't swapped `bevy_reflect` over because it doesn't depend on `bevy_ecs`, but I'd also be happy with moving `TypeIdMap` to `bevy_utils` and then adding a dependency to that~~ - ~~this is a slight change in the public API of `DrawFunctionsInternal`, does this need to go in the changelog?~~ ## Changelog - moved `TypeIdMap` to `bevy_utils` - changed `DrawFunctionsInternal::indices` to `TypeIdMap` ## Migration Guide - `TypeIdMap` now lives in `bevy_utils` - `DrawFunctionsInternal::indices` now uses a `TypeIdMap`. --------- Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
This commit is contained in:
parent
4e9590a5ce
commit
21aa5fe2b6
@ -1,5 +1,5 @@
|
|||||||
use crate::{App, AppError, Plugin};
|
use crate::{App, AppError, Plugin};
|
||||||
use bevy_utils::{tracing::debug, tracing::warn, HashMap};
|
use bevy_utils::{tracing::debug, tracing::warn, TypeIdMap};
|
||||||
use std::any::TypeId;
|
use std::any::TypeId;
|
||||||
|
|
||||||
/// Combines multiple [`Plugin`]s into a single unit.
|
/// Combines multiple [`Plugin`]s into a single unit.
|
||||||
@ -33,7 +33,7 @@ impl PluginGroup for PluginGroupBuilder {
|
|||||||
/// can be disabled, enabled or reordered.
|
/// can be disabled, enabled or reordered.
|
||||||
pub struct PluginGroupBuilder {
|
pub struct PluginGroupBuilder {
|
||||||
group_name: String,
|
group_name: String,
|
||||||
plugins: HashMap<TypeId, PluginEntry>,
|
plugins: TypeIdMap<PluginEntry>,
|
||||||
order: Vec<TypeId>,
|
order: Vec<TypeId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use bevy_ecs::world::World;
|
use bevy_ecs::world::World;
|
||||||
use bevy_log::warn;
|
use bevy_log::warn;
|
||||||
use bevy_utils::{Entry, HashMap, HashSet};
|
use bevy_utils::{Entry, HashMap, HashSet, TypeIdMap};
|
||||||
use crossbeam_channel::Sender;
|
use crossbeam_channel::Sender;
|
||||||
use std::{
|
use std::{
|
||||||
any::TypeId,
|
any::TypeId,
|
||||||
@ -61,7 +61,7 @@ impl AssetInfo {
|
|||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub(crate) struct AssetInfos {
|
pub(crate) struct AssetInfos {
|
||||||
path_to_id: HashMap<AssetPath<'static>, HashMap<TypeId, UntypedAssetId>>,
|
path_to_id: HashMap<AssetPath<'static>, TypeIdMap<UntypedAssetId>>,
|
||||||
infos: HashMap<UntypedAssetId, AssetInfo>,
|
infos: HashMap<UntypedAssetId, AssetInfo>,
|
||||||
/// If set to `true`, this informs [`AssetInfos`] to track data relevant to watching for changes (such as `load_dependants`)
|
/// If set to `true`, this informs [`AssetInfos`] to track data relevant to watching for changes (such as `load_dependants`)
|
||||||
/// This should only be set at startup.
|
/// This should only be set at startup.
|
||||||
@ -72,10 +72,10 @@ pub(crate) struct AssetInfos {
|
|||||||
/// Tracks living labeled assets for a given source asset.
|
/// Tracks living labeled assets for a given source asset.
|
||||||
/// This should only be set when watching for changes to avoid unnecessary work.
|
/// This should only be set when watching for changes to avoid unnecessary work.
|
||||||
pub(crate) living_labeled_assets: HashMap<AssetPath<'static>, HashSet<String>>,
|
pub(crate) living_labeled_assets: HashMap<AssetPath<'static>, HashSet<String>>,
|
||||||
pub(crate) handle_providers: HashMap<TypeId, AssetHandleProvider>,
|
pub(crate) handle_providers: TypeIdMap<AssetHandleProvider>,
|
||||||
pub(crate) dependency_loaded_event_sender: HashMap<TypeId, fn(&mut World, UntypedAssetId)>,
|
pub(crate) dependency_loaded_event_sender: TypeIdMap<fn(&mut World, UntypedAssetId)>,
|
||||||
pub(crate) dependency_failed_event_sender:
|
pub(crate) dependency_failed_event_sender:
|
||||||
HashMap<TypeId, fn(&mut World, UntypedAssetId, AssetPath<'static>, AssetLoadError)>,
|
TypeIdMap<fn(&mut World, UntypedAssetId, AssetPath<'static>, AssetLoadError)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Debug for AssetInfos {
|
impl std::fmt::Debug for AssetInfos {
|
||||||
@ -112,7 +112,7 @@ impl AssetInfos {
|
|||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn create_handle_internal(
|
fn create_handle_internal(
|
||||||
infos: &mut HashMap<UntypedAssetId, AssetInfo>,
|
infos: &mut HashMap<UntypedAssetId, AssetInfo>,
|
||||||
handle_providers: &HashMap<TypeId, AssetHandleProvider>,
|
handle_providers: &TypeIdMap<AssetHandleProvider>,
|
||||||
living_labeled_assets: &mut HashMap<AssetPath<'static>, HashSet<String>>,
|
living_labeled_assets: &mut HashMap<AssetPath<'static>, HashSet<String>>,
|
||||||
watching_for_changes: bool,
|
watching_for_changes: bool,
|
||||||
type_id: TypeId,
|
type_id: TypeId,
|
||||||
@ -205,7 +205,7 @@ impl AssetInfos {
|
|||||||
.ok_or(GetOrCreateHandleInternalError::HandleMissingButTypeIdNotSpecified)?;
|
.ok_or(GetOrCreateHandleInternalError::HandleMissingButTypeIdNotSpecified)?;
|
||||||
|
|
||||||
match handles.entry(type_id) {
|
match handles.entry(type_id) {
|
||||||
Entry::Occupied(entry) => {
|
bevy_utils::hashbrown::hash_map::Entry::Occupied(entry) => {
|
||||||
let id = *entry.get();
|
let id = *entry.get();
|
||||||
// if there is a path_to_id entry, info always exists
|
// if there is a path_to_id entry, info always exists
|
||||||
let info = self.infos.get_mut(&id).unwrap();
|
let info = self.infos.get_mut(&id).unwrap();
|
||||||
@ -246,7 +246,7 @@ impl AssetInfos {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// The entry does not exist, so this is a "fresh" asset load. We must create a new handle
|
// The entry does not exist, so this is a "fresh" asset load. We must create a new handle
|
||||||
Entry::Vacant(entry) => {
|
bevy_utils::hashbrown::hash_map::Entry::Vacant(entry) => {
|
||||||
let should_load = match loading_mode {
|
let should_load = match loading_mode {
|
||||||
HandleLoadingMode::NotLoading => false,
|
HandleLoadingMode::NotLoading => false,
|
||||||
HandleLoadingMode::Request | HandleLoadingMode::Force => true,
|
HandleLoadingMode::Request | HandleLoadingMode::Force => true,
|
||||||
@ -640,7 +640,7 @@ impl AssetInfos {
|
|||||||
|
|
||||||
fn process_handle_drop_internal(
|
fn process_handle_drop_internal(
|
||||||
infos: &mut HashMap<UntypedAssetId, AssetInfo>,
|
infos: &mut HashMap<UntypedAssetId, AssetInfo>,
|
||||||
path_to_id: &mut HashMap<AssetPath<'static>, HashMap<TypeId, UntypedAssetId>>,
|
path_to_id: &mut HashMap<AssetPath<'static>, TypeIdMap<UntypedAssetId>>,
|
||||||
loader_dependants: &mut HashMap<AssetPath<'static>, HashSet<AssetPath<'static>>>,
|
loader_dependants: &mut HashMap<AssetPath<'static>, HashSet<AssetPath<'static>>>,
|
||||||
living_labeled_assets: &mut HashMap<AssetPath<'static>, HashSet<String>>,
|
living_labeled_assets: &mut HashMap<AssetPath<'static>, HashSet<String>>,
|
||||||
watching_for_changes: bool,
|
watching_for_changes: bool,
|
||||||
|
@ -19,7 +19,7 @@ use crate::{
|
|||||||
use bevy_ecs::prelude::*;
|
use bevy_ecs::prelude::*;
|
||||||
use bevy_log::{error, info, warn};
|
use bevy_log::{error, info, warn};
|
||||||
use bevy_tasks::IoTaskPool;
|
use bevy_tasks::IoTaskPool;
|
||||||
use bevy_utils::{CowArc, HashMap, HashSet};
|
use bevy_utils::{CowArc, HashMap, HashSet, TypeIdMap};
|
||||||
use crossbeam_channel::{Receiver, Sender};
|
use crossbeam_channel::{Receiver, Sender};
|
||||||
use futures_lite::StreamExt;
|
use futures_lite::StreamExt;
|
||||||
use info::*;
|
use info::*;
|
||||||
@ -1238,7 +1238,7 @@ pub fn handle_internal_asset_events(world: &mut World) {
|
|||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub(crate) struct AssetLoaders {
|
pub(crate) struct AssetLoaders {
|
||||||
type_id_to_loader: HashMap<TypeId, MaybeAssetLoader>,
|
type_id_to_loader: TypeIdMap<MaybeAssetLoader>,
|
||||||
extension_to_type_id: HashMap<String, TypeId>,
|
extension_to_type_id: HashMap<String, TypeId>,
|
||||||
type_name_to_type_id: HashMap<&'static str, TypeId>,
|
type_name_to_type_id: HashMap<&'static str, TypeId>,
|
||||||
preregistered_loaders: HashMap<&'static str, TypeId>,
|
preregistered_loaders: HashMap<&'static str, TypeId>,
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
//! This module contains the [`Bundle`] trait and some other helper types.
|
//! This module contains the [`Bundle`] trait and some other helper types.
|
||||||
|
|
||||||
pub use bevy_ecs_macros::Bundle;
|
pub use bevy_ecs_macros::Bundle;
|
||||||
use bevy_utils::{HashMap, HashSet};
|
use bevy_utils::{HashMap, HashSet, TypeIdMap};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
archetype::{
|
archetype::{
|
||||||
@ -14,7 +14,6 @@ use crate::{
|
|||||||
entity::{Entities, Entity, EntityLocation},
|
entity::{Entities, Entity, EntityLocation},
|
||||||
query::DebugCheckedUnwrap,
|
query::DebugCheckedUnwrap,
|
||||||
storage::{SparseSetIndex, SparseSets, Storages, Table, TableRow},
|
storage::{SparseSetIndex, SparseSets, Storages, Table, TableRow},
|
||||||
TypeIdMap,
|
|
||||||
};
|
};
|
||||||
use bevy_ptr::OwningPtr;
|
use bevy_ptr::OwningPtr;
|
||||||
use bevy_utils::all_tuples;
|
use bevy_utils::all_tuples;
|
||||||
|
@ -6,12 +6,12 @@ use crate::{
|
|||||||
storage::{SparseSetIndex, Storages},
|
storage::{SparseSetIndex, Storages},
|
||||||
system::{Local, Resource, SystemParam},
|
system::{Local, Resource, SystemParam},
|
||||||
world::{FromWorld, World},
|
world::{FromWorld, World},
|
||||||
TypeIdMap,
|
|
||||||
};
|
};
|
||||||
pub use bevy_ecs_macros::Component;
|
pub use bevy_ecs_macros::Component;
|
||||||
use bevy_ptr::{OwningPtr, UnsafeCellDeref};
|
use bevy_ptr::{OwningPtr, UnsafeCellDeref};
|
||||||
#[cfg(feature = "bevy_reflect")]
|
#[cfg(feature = "bevy_reflect")]
|
||||||
use bevy_reflect::Reflect;
|
use bevy_reflect::Reflect;
|
||||||
|
use bevy_utils::TypeIdMap;
|
||||||
use std::cell::UnsafeCell;
|
use std::cell::UnsafeCell;
|
||||||
use std::{
|
use std::{
|
||||||
alloc::Layout,
|
alloc::Layout,
|
||||||
|
@ -21,8 +21,6 @@ pub mod storage;
|
|||||||
pub mod system;
|
pub mod system;
|
||||||
pub mod world;
|
pub mod world;
|
||||||
|
|
||||||
use std::any::TypeId;
|
|
||||||
|
|
||||||
pub use bevy_ptr as ptr;
|
pub use bevy_ptr as ptr;
|
||||||
|
|
||||||
/// Most commonly used re-exported types.
|
/// Most commonly used re-exported types.
|
||||||
@ -56,34 +54,6 @@ pub mod prelude {
|
|||||||
|
|
||||||
pub use bevy_utils::all_tuples;
|
pub use bevy_utils::all_tuples;
|
||||||
|
|
||||||
/// A specialized hashmap type with Key of [`TypeId`]
|
|
||||||
type TypeIdMap<V> =
|
|
||||||
std::collections::HashMap<TypeId, V, std::hash::BuildHasherDefault<NoOpTypeIdHasher>>;
|
|
||||||
|
|
||||||
#[doc(hidden)]
|
|
||||||
#[derive(Default)]
|
|
||||||
struct NoOpTypeIdHasher(u64);
|
|
||||||
|
|
||||||
// TypeId already contains a high-quality hash, so skip re-hashing that hash.
|
|
||||||
impl std::hash::Hasher for NoOpTypeIdHasher {
|
|
||||||
fn finish(&self) -> u64 {
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write(&mut self, bytes: &[u8]) {
|
|
||||||
// This will never be called: TypeId always just calls write_u64 once!
|
|
||||||
// This is a known trick and unlikely to change, but isn't officially guaranteed.
|
|
||||||
// Don't break applications (slower fallback, just check in test):
|
|
||||||
self.0 = bytes.iter().fold(self.0, |hash, b| {
|
|
||||||
hash.rotate_left(8).wrapping_add(*b as u64)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_u64(&mut self, i: u64) {
|
|
||||||
self.0 = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate as bevy_ecs;
|
use crate as bevy_ecs;
|
||||||
@ -1755,23 +1725,6 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn fast_typeid_hash() {
|
|
||||||
struct Hasher;
|
|
||||||
|
|
||||||
impl std::hash::Hasher for Hasher {
|
|
||||||
fn finish(&self) -> u64 {
|
|
||||||
0
|
|
||||||
}
|
|
||||||
fn write(&mut self, _: &[u8]) {
|
|
||||||
panic!("Hashing of std::any::TypeId changed");
|
|
||||||
}
|
|
||||||
fn write_u64(&mut self, _: u64) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::hash::Hash::hash(&TypeId::of::<()>(), &mut Hasher);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
struct ComponentA(u32);
|
struct ComponentA(u32);
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ use crate::{
|
|||||||
use bevy_utils::{
|
use bevy_utils::{
|
||||||
thiserror::Error,
|
thiserror::Error,
|
||||||
tracing::{error, info, warn},
|
tracing::{error, info, warn},
|
||||||
|
TypeIdMap,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -617,7 +618,7 @@ struct ScheduleState {
|
|||||||
|
|
||||||
/// changes to system behavior that should be applied the next time
|
/// changes to system behavior that should be applied the next time
|
||||||
/// [`ScheduleState::skipped_systems()`] is called
|
/// [`ScheduleState::skipped_systems()`] is called
|
||||||
behavior_updates: HashMap<TypeId, Option<SystemBehavior>>,
|
behavior_updates: TypeIdMap<Option<SystemBehavior>>,
|
||||||
|
|
||||||
/// This field contains the first steppable system in the schedule.
|
/// This field contains the first steppable system in the schedule.
|
||||||
first: Option<usize>,
|
first: Option<usize>,
|
||||||
|
@ -6,7 +6,7 @@ pub use bevy_gizmos_macros::GizmoConfigGroup;
|
|||||||
use bevy_ecs::{component::Component, system::Resource};
|
use bevy_ecs::{component::Component, system::Resource};
|
||||||
use bevy_reflect::{Reflect, TypePath};
|
use bevy_reflect::{Reflect, TypePath};
|
||||||
use bevy_render::view::RenderLayers;
|
use bevy_render::view::RenderLayers;
|
||||||
use bevy_utils::HashMap;
|
use bevy_utils::TypeIdMap;
|
||||||
use core::panic;
|
use core::panic;
|
||||||
use std::{
|
use std::{
|
||||||
any::TypeId,
|
any::TypeId,
|
||||||
@ -30,7 +30,7 @@ pub struct DefaultGizmoConfigGroup;
|
|||||||
#[derive(Resource, Default)]
|
#[derive(Resource, Default)]
|
||||||
pub struct GizmoConfigStore {
|
pub struct GizmoConfigStore {
|
||||||
// INVARIANT: must map TypeId::of::<T>() to correct type T
|
// INVARIANT: must map TypeId::of::<T>() to correct type T
|
||||||
store: HashMap<TypeId, (GizmoConfig, Box<dyn Reflect>)>,
|
store: TypeIdMap<(GizmoConfig, Box<dyn Reflect>)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GizmoConfigStore {
|
impl GizmoConfigStore {
|
||||||
|
@ -77,7 +77,7 @@ use bevy_render::{
|
|||||||
renderer::RenderDevice,
|
renderer::RenderDevice,
|
||||||
Extract, ExtractSchedule, Render, RenderApp, RenderSet,
|
Extract, ExtractSchedule, Render, RenderApp, RenderSet,
|
||||||
};
|
};
|
||||||
use bevy_utils::HashMap;
|
use bevy_utils::TypeIdMap;
|
||||||
use config::{
|
use config::{
|
||||||
DefaultGizmoConfigGroup, GizmoConfig, GizmoConfigGroup, GizmoConfigStore, GizmoMeshConfig,
|
DefaultGizmoConfigGroup, GizmoConfig, GizmoConfigGroup, GizmoConfigStore, GizmoMeshConfig,
|
||||||
};
|
};
|
||||||
@ -206,8 +206,8 @@ impl AppGizmoBuilder for App {
|
|||||||
|
|
||||||
#[derive(Resource, Default)]
|
#[derive(Resource, Default)]
|
||||||
struct LineGizmoHandles {
|
struct LineGizmoHandles {
|
||||||
list: HashMap<TypeId, Handle<LineGizmo>>,
|
list: TypeIdMap<Handle<LineGizmo>>,
|
||||||
strip: HashMap<TypeId, Handle<LineGizmo>>,
|
strip: TypeIdMap<Handle<LineGizmo>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_gizmo_meshes<T: GizmoConfigGroup>(
|
fn update_gizmo_meshes<T: GizmoConfigGroup>(
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::{serde::Serializable, Reflect, TypeInfo, TypePath, Typed};
|
use crate::{serde::Serializable, Reflect, TypeInfo, TypePath, Typed};
|
||||||
use bevy_ptr::{Ptr, PtrMut};
|
use bevy_ptr::{Ptr, PtrMut};
|
||||||
use bevy_utils::{HashMap, HashSet};
|
use bevy_utils::{HashMap, HashSet, TypeIdMap};
|
||||||
use downcast_rs::{impl_downcast, Downcast};
|
use downcast_rs::{impl_downcast, Downcast};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::{
|
use std::{
|
||||||
@ -22,7 +22,7 @@ use std::{
|
|||||||
/// [Registering]: TypeRegistry::register
|
/// [Registering]: TypeRegistry::register
|
||||||
/// [crate-level documentation]: crate
|
/// [crate-level documentation]: crate
|
||||||
pub struct TypeRegistry {
|
pub struct TypeRegistry {
|
||||||
registrations: HashMap<TypeId, TypeRegistration>,
|
registrations: TypeIdMap<TypeRegistration>,
|
||||||
short_path_to_id: HashMap<&'static str, TypeId>,
|
short_path_to_id: HashMap<&'static str, TypeId>,
|
||||||
type_path_to_id: HashMap<&'static str, TypeId>,
|
type_path_to_id: HashMap<&'static str, TypeId>,
|
||||||
ambiguous_names: HashSet<&'static str>,
|
ambiguous_names: HashSet<&'static str>,
|
||||||
@ -318,7 +318,7 @@ impl TypeRegistryArc {
|
|||||||
///
|
///
|
||||||
/// [crate-level documentation]: crate
|
/// [crate-level documentation]: crate
|
||||||
pub struct TypeRegistration {
|
pub struct TypeRegistration {
|
||||||
data: HashMap<TypeId, Box<dyn TypeData>>,
|
data: TypeIdMap<Box<dyn TypeData>>,
|
||||||
type_info: &'static TypeInfo,
|
type_info: &'static TypeInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -373,7 +373,7 @@ impl TypeRegistration {
|
|||||||
/// Creates type registration information for `T`.
|
/// Creates type registration information for `T`.
|
||||||
pub fn of<T: Reflect + Typed + TypePath>() -> Self {
|
pub fn of<T: Reflect + Typed + TypePath>() -> Self {
|
||||||
Self {
|
Self {
|
||||||
data: HashMap::default(),
|
data: Default::default(),
|
||||||
type_info: T::type_info(),
|
type_info: T::type_info(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -381,7 +381,7 @@ impl TypeRegistration {
|
|||||||
|
|
||||||
impl Clone for TypeRegistration {
|
impl Clone for TypeRegistration {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
let mut data = HashMap::default();
|
let mut data = TypeIdMap::default();
|
||||||
for (id, type_data) in &self.data {
|
for (id, type_data) in &self.data {
|
||||||
data.insert(*id, (*type_data).clone_type_data());
|
data.insert(*id, (*type_data).clone_type_data());
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ use bevy_ecs::{
|
|||||||
system::{ReadOnlySystemParam, Resource, SystemParam, SystemParamItem, SystemState},
|
system::{ReadOnlySystemParam, Resource, SystemParam, SystemParamItem, SystemState},
|
||||||
world::World,
|
world::World,
|
||||||
};
|
};
|
||||||
use bevy_utils::{all_tuples, HashMap};
|
use bevy_utils::{all_tuples, TypeIdMap};
|
||||||
use std::{
|
use std::{
|
||||||
any::TypeId,
|
any::TypeId,
|
||||||
fmt::Debug,
|
fmt::Debug,
|
||||||
@ -47,7 +47,7 @@ pub struct DrawFunctionId(u32);
|
|||||||
/// For retrieval, the [`Draw`] functions are mapped to their respective [`TypeId`]s.
|
/// For retrieval, the [`Draw`] functions are mapped to their respective [`TypeId`]s.
|
||||||
pub struct DrawFunctionsInternal<P: PhaseItem> {
|
pub struct DrawFunctionsInternal<P: PhaseItem> {
|
||||||
pub draw_functions: Vec<Box<dyn Draw<P>>>,
|
pub draw_functions: Vec<Box<dyn Draw<P>>>,
|
||||||
pub indices: HashMap<TypeId, DrawFunctionId>,
|
pub indices: TypeIdMap<DrawFunctionId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P: PhaseItem> DrawFunctionsInternal<P> {
|
impl<P: PhaseItem> DrawFunctionsInternal<P> {
|
||||||
@ -111,7 +111,7 @@ impl<P: PhaseItem> Default for DrawFunctions<P> {
|
|||||||
Self {
|
Self {
|
||||||
internal: RwLock::new(DrawFunctionsInternal {
|
internal: RwLock::new(DrawFunctionsInternal {
|
||||||
draw_functions: Vec::new(),
|
draw_functions: Vec::new(),
|
||||||
indices: HashMap::default(),
|
indices: Default::default(),
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,7 @@ use bevy_ecs::{
|
|||||||
world::World,
|
world::World,
|
||||||
};
|
};
|
||||||
use bevy_reflect::{Reflect, TypePath, TypeRegistryArc};
|
use bevy_reflect::{Reflect, TypePath, TypeRegistryArc};
|
||||||
use bevy_utils::{EntityHashMap, HashMap};
|
use bevy_utils::{EntityHashMap, TypeIdMap};
|
||||||
use std::any::TypeId;
|
|
||||||
|
|
||||||
#[cfg(feature = "serialize")]
|
#[cfg(feature = "serialize")]
|
||||||
use crate::serde::SceneSerializer;
|
use crate::serde::SceneSerializer;
|
||||||
@ -97,7 +96,7 @@ impl DynamicScene {
|
|||||||
// of which entities in the scene use that component.
|
// of which entities in the scene use that component.
|
||||||
// This is so we can update the scene-internal references to references
|
// This is so we can update the scene-internal references to references
|
||||||
// of the actual entities in the world.
|
// of the actual entities in the world.
|
||||||
let mut scene_mappings: HashMap<TypeId, Vec<Entity>> = HashMap::default();
|
let mut scene_mappings: TypeIdMap<Vec<Entity>> = Default::default();
|
||||||
|
|
||||||
for scene_entity in &self.entities {
|
for scene_entity in &self.entities {
|
||||||
// Fetch the entity with the given entity id from the `entity_map`
|
// Fetch the entity with the given entity id from the `entity_map`
|
||||||
@ -132,7 +131,7 @@ impl DynamicScene {
|
|||||||
if registration.data::<ReflectMapEntities>().is_some() {
|
if registration.data::<ReflectMapEntities>().is_some() {
|
||||||
scene_mappings
|
scene_mappings
|
||||||
.entry(registration.type_id())
|
.entry(registration.type_id())
|
||||||
.or_insert(Vec::new())
|
.or_default()
|
||||||
.push(entity);
|
.push(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,6 +43,7 @@ pub mod nonmax {
|
|||||||
|
|
||||||
use hashbrown::hash_map::RawEntryMut;
|
use hashbrown::hash_map::RawEntryMut;
|
||||||
use std::{
|
use std::{
|
||||||
|
any::TypeId,
|
||||||
fmt::Debug,
|
fmt::Debug,
|
||||||
future::Future,
|
future::Future,
|
||||||
hash::{BuildHasher, BuildHasherDefault, Hash, Hasher},
|
hash::{BuildHasher, BuildHasherDefault, Hash, Hasher},
|
||||||
@ -326,6 +327,34 @@ pub type EntityHashMap<K, V> = hashbrown::HashMap<K, V, EntityHash>;
|
|||||||
/// A [`HashSet`] pre-configured to use [`EntityHash`] hashing.
|
/// A [`HashSet`] pre-configured to use [`EntityHash`] hashing.
|
||||||
pub type EntityHashSet<T> = hashbrown::HashSet<T, EntityHash>;
|
pub type EntityHashSet<T> = hashbrown::HashSet<T, EntityHash>;
|
||||||
|
|
||||||
|
/// A specialized hashmap type with Key of [`TypeId`]
|
||||||
|
pub type TypeIdMap<V> =
|
||||||
|
hashbrown::HashMap<TypeId, V, std::hash::BuildHasherDefault<NoOpTypeIdHasher>>;
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct NoOpTypeIdHasher(u64);
|
||||||
|
|
||||||
|
// TypeId already contains a high-quality hash, so skip re-hashing that hash.
|
||||||
|
impl std::hash::Hasher for NoOpTypeIdHasher {
|
||||||
|
fn finish(&self) -> u64 {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write(&mut self, bytes: &[u8]) {
|
||||||
|
// This will never be called: TypeId always just calls write_u64 once!
|
||||||
|
// This is a known trick and unlikely to change, but isn't officially guaranteed.
|
||||||
|
// Don't break applications (slower fallback, just check in test):
|
||||||
|
self.0 = bytes.iter().fold(self.0, |hash, b| {
|
||||||
|
hash.rotate_left(8).wrapping_add(*b as u64)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_u64(&mut self, i: u64) {
|
||||||
|
self.0 = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A type which calls a function when dropped.
|
/// A type which calls a function when dropped.
|
||||||
/// This can be used to ensure that cleanup code is run even in case of a panic.
|
/// This can be used to ensure that cleanup code is run even in case of a panic.
|
||||||
///
|
///
|
||||||
@ -423,4 +452,21 @@ mod tests {
|
|||||||
// Check that the HashMaps are Clone if the key/values are Clone
|
// Check that the HashMaps are Clone if the key/values are Clone
|
||||||
assert_impl_all!(EntityHashMap::<u64, usize>: Clone);
|
assert_impl_all!(EntityHashMap::<u64, usize>: Clone);
|
||||||
assert_impl_all!(PreHashMap::<u64, usize>: Clone);
|
assert_impl_all!(PreHashMap::<u64, usize>: Clone);
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn fast_typeid_hash() {
|
||||||
|
struct Hasher;
|
||||||
|
|
||||||
|
impl std::hash::Hasher for Hasher {
|
||||||
|
fn finish(&self) -> u64 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
fn write(&mut self, _: &[u8]) {
|
||||||
|
panic!("Hashing of std::any::TypeId changed");
|
||||||
|
}
|
||||||
|
fn write_u64(&mut self, _: u64) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::hash::Hash::hash(&TypeId::of::<()>(), &mut Hasher);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user