1use core::{any::TypeId, hash::Hash};
2
3use bevy_platform::{
4 collections::{hash_map::Entry, HashMap},
5 hash::{Hashed, NoOpHash, PassHash},
6};
7
8pub type PreHashMap<K, V> = HashMap<Hashed<K>, V, PassHash>;
11
12pub trait PreHashMapExt<K, V> {
14 fn get_or_insert_with<F: FnOnce() -> V>(&mut self, key: &Hashed<K>, func: F) -> &mut V;
18}
19
20impl<K: Hash + Eq + PartialEq + Clone, V> PreHashMapExt<K, V> for PreHashMap<K, V> {
21 #[inline]
22 fn get_or_insert_with<F: FnOnce() -> V>(&mut self, key: &Hashed<K>, func: F) -> &mut V {
23 use bevy_platform::collections::hash_map::RawEntryMut;
24 let entry = self
25 .raw_entry_mut()
26 .from_key_hashed_nocheck(key.hash(), key);
27 match entry {
28 RawEntryMut::Occupied(entry) => entry.into_mut(),
29 RawEntryMut::Vacant(entry) => {
30 let (_, value) = entry.insert_hashed_nocheck(key.hash(), key.clone(), func());
31 value
32 }
33 }
34 }
35}
36
37pub type TypeIdMap<V> = HashMap<TypeId, V, NoOpHash>;
40
41pub trait TypeIdMapExt<V> {
66 fn insert_type<T: ?Sized + 'static>(&mut self, v: V) -> Option<V>;
71
72 fn get_type<T: ?Sized + 'static>(&self) -> Option<&V>;
74
75 fn get_type_mut<T: ?Sized + 'static>(&mut self) -> Option<&mut V>;
77
78 fn remove_type<T: ?Sized + 'static>(&mut self) -> Option<V>;
81
82 fn entry_type<T: ?Sized + 'static>(&mut self) -> Entry<'_, TypeId, V, NoOpHash>;
84}
85
86impl<V> TypeIdMapExt<V> for TypeIdMap<V> {
87 #[inline]
88 fn insert_type<T: ?Sized + 'static>(&mut self, v: V) -> Option<V> {
89 self.insert(TypeId::of::<T>(), v)
90 }
91
92 #[inline]
93 fn get_type<T: ?Sized + 'static>(&self) -> Option<&V> {
94 self.get(&TypeId::of::<T>())
95 }
96
97 #[inline]
98 fn get_type_mut<T: ?Sized + 'static>(&mut self) -> Option<&mut V> {
99 self.get_mut(&TypeId::of::<T>())
100 }
101
102 #[inline]
103 fn remove_type<T: ?Sized + 'static>(&mut self) -> Option<V> {
104 self.remove(&TypeId::of::<T>())
105 }
106
107 #[inline]
108 fn entry_type<T: ?Sized + 'static>(&mut self) -> Entry<'_, TypeId, V, NoOpHash> {
109 self.entry(TypeId::of::<T>())
110 }
111}
112
113#[cfg(test)]
114mod tests {
115 use super::*;
116 use static_assertions::assert_impl_all;
117
118 assert_impl_all!(PreHashMap::<u64, usize>: Clone);
120
121 #[test]
122 fn fast_typeid_hash() {
123 struct Hasher;
124
125 impl core::hash::Hasher for Hasher {
126 fn finish(&self) -> u64 {
127 0
128 }
129 fn write(&mut self, _: &[u8]) {
130 panic!("Hashing of core::any::TypeId changed");
131 }
132 fn write_u64(&mut self, _: u64) {}
133 }
134
135 Hash::hash(&TypeId::of::<()>(), &mut Hasher);
136 }
137
138 crate::cfg::alloc! {
139 #[test]
140 fn stable_hash_within_same_program_execution() {
141 use alloc::vec::Vec;
142
143 let mut map_1 = <HashMap<_, _>>::default();
144 let mut map_2 = <HashMap<_, _>>::default();
145 for i in 1..10 {
146 map_1.insert(i, i);
147 map_2.insert(i, i);
148 }
149 assert_eq!(
150 map_1.iter().collect::<Vec<_>>(),
151 map_2.iter().collect::<Vec<_>>()
152 );
153 }
154 }
155}