1#![cfg_attr(docsrs, feature(doc_auto_cfg))]
2#![doc(
3 html_logo_url = "https://bevyengine.org/assets/icon.png",
4 html_favicon_url = "https://bevyengine.org/assets/icon.png"
5)]
6#![no_std]
7
8#[cfg(feature = "std")]
13extern crate std;
14
15#[cfg(feature = "alloc")]
16extern crate alloc;
17
18pub mod prelude {
22 pub use crate::default;
23}
24
25pub mod synccell;
26pub mod syncunsafecell;
27
28mod default;
29mod once;
30#[cfg(feature = "std")]
31mod parallel_queue;
32
33#[doc(hidden)]
34pub use once::OnceFlag;
35
36pub use default::default;
37
38#[cfg(feature = "std")]
39pub use parallel_queue::*;
40
41use core::mem::ManuallyDrop;
42
43#[cfg(feature = "alloc")]
44use {
45 bevy_platform::{
46 collections::HashMap,
47 hash::{Hashed, NoOpHash, PassHash},
48 },
49 core::{any::TypeId, hash::Hash},
50};
51
52#[cfg(feature = "alloc")]
55pub type PreHashMap<K, V> = HashMap<Hashed<K>, V, PassHash>;
56
57#[cfg(feature = "alloc")]
59pub trait PreHashMapExt<K, V> {
60 fn get_or_insert_with<F: FnOnce() -> V>(&mut self, key: &Hashed<K>, func: F) -> &mut V;
64}
65
66#[cfg(feature = "alloc")]
67impl<K: Hash + Eq + PartialEq + Clone, V> PreHashMapExt<K, V> for PreHashMap<K, V> {
68 #[inline]
69 fn get_or_insert_with<F: FnOnce() -> V>(&mut self, key: &Hashed<K>, func: F) -> &mut V {
70 use bevy_platform::collections::hash_map::RawEntryMut;
71 let entry = self
72 .raw_entry_mut()
73 .from_key_hashed_nocheck(key.hash(), key);
74 match entry {
75 RawEntryMut::Occupied(entry) => entry.into_mut(),
76 RawEntryMut::Vacant(entry) => {
77 let (_, value) = entry.insert_hashed_nocheck(key.hash(), key.clone(), func());
78 value
79 }
80 }
81 }
82}
83
84#[cfg(feature = "alloc")]
87pub type TypeIdMap<V> = HashMap<TypeId, V, NoOpHash>;
88
89pub struct OnDrop<F: FnOnce()> {
124 callback: ManuallyDrop<F>,
125}
126
127impl<F: FnOnce()> OnDrop<F> {
128 pub fn new(callback: F) -> Self {
130 Self {
131 callback: ManuallyDrop::new(callback),
132 }
133 }
134}
135
136impl<F: FnOnce()> Drop for OnDrop<F> {
137 fn drop(&mut self) {
138 #![expect(
139 unsafe_code,
140 reason = "Taking from a ManuallyDrop requires unsafe code."
141 )]
142 let callback = unsafe { ManuallyDrop::take(&mut self.callback) };
144 callback();
145 }
146}
147
148#[cfg(test)]
149mod tests {
150 use super::*;
151 use static_assertions::assert_impl_all;
152
153 assert_impl_all!(PreHashMap::<u64, usize>: Clone);
155
156 #[test]
157 fn fast_typeid_hash() {
158 struct Hasher;
159
160 impl core::hash::Hasher for Hasher {
161 fn finish(&self) -> u64 {
162 0
163 }
164 fn write(&mut self, _: &[u8]) {
165 panic!("Hashing of core::any::TypeId changed");
166 }
167 fn write_u64(&mut self, _: u64) {}
168 }
169
170 Hash::hash(&TypeId::of::<()>(), &mut Hasher);
171 }
172
173 #[cfg(feature = "alloc")]
174 #[test]
175 fn stable_hash_within_same_program_execution() {
176 use alloc::vec::Vec;
177
178 let mut map_1 = <HashMap<_, _>>::default();
179 let mut map_2 = <HashMap<_, _>>::default();
180 for i in 1..10 {
181 map_1.insert(i, i);
182 map_2.insert(i, i);
183 }
184 assert_eq!(
185 map_1.iter().collect::<Vec<_>>(),
186 map_2.iter().collect::<Vec<_>>()
187 );
188 }
189}