1#![cfg_attr(docsrs, feature(doc_auto_cfg))]
2#![expect(
3 unsafe_code,
4 reason = "Some utilities, such as futures and cells, require unsafe code."
5)]
6#![doc(
7 html_logo_url = "https://bevyengine.org/assets/icon.png",
8 html_favicon_url = "https://bevyengine.org/assets/icon.png"
9)]
10#![cfg_attr(not(feature = "std"), no_std)]
11
12#[cfg(feature = "alloc")]
17extern crate alloc;
18
19pub mod prelude {
23 pub use crate::default;
24}
25
26pub mod futures;
27pub mod synccell;
28pub mod syncunsafecell;
29
30mod default;
31mod object_safe;
32pub use object_safe::assert_object_safe;
33mod once;
34#[cfg(feature = "std")]
35mod parallel_queue;
36mod time;
37
38pub use ahash::{AHasher, RandomState};
39pub use bevy_utils_proc_macros::*;
40pub use default::default;
41pub use hashbrown;
42#[cfg(feature = "std")]
43pub use parallel_queue::*;
44pub use time::*;
45pub use tracing;
46
47#[cfg(feature = "alloc")]
48use alloc::boxed::Box;
49
50use core::{
51 any::TypeId,
52 fmt::Debug,
53 hash::{BuildHasher, BuildHasherDefault, Hash, Hasher},
54 marker::PhantomData,
55 mem::ManuallyDrop,
56 ops::Deref,
57};
58use hashbrown::hash_map::RawEntryMut;
59
60#[cfg(not(target_arch = "wasm32"))]
61mod conditional_send {
62 pub trait ConditionalSend: Send {}
65 impl<T: Send> ConditionalSend for T {}
66}
67
68#[cfg(target_arch = "wasm32")]
69#[expect(missing_docs, reason = "Not all docs are written yet (#3492).")]
70mod conditional_send {
71 pub trait ConditionalSend {}
72 impl<T> ConditionalSend for T {}
73}
74
75pub use conditional_send::*;
76
77pub trait ConditionalSendFuture: core::future::Future + ConditionalSend {}
80impl<T: core::future::Future + ConditionalSend> ConditionalSendFuture for T {}
81
82#[cfg(feature = "alloc")]
84pub type BoxedFuture<'a, T> = core::pin::Pin<Box<dyn ConditionalSendFuture<Output = T> + 'a>>;
85
86pub type Entry<'a, K, V, S = BuildHasherDefault<AHasher>> = hashbrown::hash_map::Entry<'a, K, V, S>;
88
89#[derive(Debug, Clone, Default)]
91pub struct FixedState;
92
93impl BuildHasher for FixedState {
94 type Hasher = AHasher;
95
96 #[inline]
97 fn build_hasher(&self) -> AHasher {
98 RandomState::with_seeds(
99 0b10010101111011100000010011000100,
100 0b00000011001001101011001001111000,
101 0b11001111011010110111100010110101,
102 0b00000100001111100011010011010101,
103 )
104 .build_hasher()
105 }
106}
107
108pub type HashMap<K, V> = hashbrown::HashMap<K, V, BuildHasherDefault<AHasher>>;
117
118#[deprecated(
126 note = "Will be required to use the hash library of your choice. Alias for: hashbrown::HashMap<K, V, FixedState>"
127)]
128pub type StableHashMap<K, V> = hashbrown::HashMap<K, V, FixedState>;
129
130pub type HashSet<K> = hashbrown::HashSet<K, BuildHasherDefault<AHasher>>;
139
140#[deprecated(
148 note = "Will be required to use the hash library of your choice. Alias for: hashbrown::HashSet<K, FixedState>"
149)]
150pub type StableHashSet<K> = hashbrown::HashSet<K, FixedState>;
151
152pub struct Hashed<V, H = FixedState> {
159 hash: u64,
160 value: V,
161 marker: PhantomData<H>,
162}
163
164impl<V: Hash, H: BuildHasher + Default> Hashed<V, H> {
165 pub fn new(value: V) -> Self {
167 Self {
168 hash: H::default().hash_one(&value),
169 value,
170 marker: PhantomData,
171 }
172 }
173
174 #[inline]
176 pub fn hash(&self) -> u64 {
177 self.hash
178 }
179}
180
181impl<V, H> Hash for Hashed<V, H> {
182 #[inline]
183 fn hash<R: Hasher>(&self, state: &mut R) {
184 state.write_u64(self.hash);
185 }
186}
187
188impl<V, H> Deref for Hashed<V, H> {
189 type Target = V;
190
191 #[inline]
192 fn deref(&self) -> &Self::Target {
193 &self.value
194 }
195}
196
197impl<V: PartialEq, H> PartialEq for Hashed<V, H> {
198 #[inline]
201 fn eq(&self, other: &Self) -> bool {
202 self.hash == other.hash && self.value.eq(&other.value)
203 }
204}
205
206impl<V: Debug, H> Debug for Hashed<V, H> {
207 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
208 f.debug_struct("Hashed")
209 .field("hash", &self.hash)
210 .field("value", &self.value)
211 .finish()
212 }
213}
214
215impl<V: Clone, H> Clone for Hashed<V, H> {
216 #[inline]
217 fn clone(&self) -> Self {
218 Self {
219 hash: self.hash,
220 value: self.value.clone(),
221 marker: PhantomData,
222 }
223 }
224}
225
226impl<V: Copy, H> Copy for Hashed<V, H> {}
227
228impl<V: Eq, H> Eq for Hashed<V, H> {}
229
230#[derive(Default, Clone)]
232pub struct PassHash;
233
234impl BuildHasher for PassHash {
235 type Hasher = PassHasher;
236
237 fn build_hasher(&self) -> Self::Hasher {
238 PassHasher::default()
239 }
240}
241
242#[derive(Debug, Default)]
245pub struct PassHasher {
246 hash: u64,
247}
248
249impl Hasher for PassHasher {
250 #[inline]
251 fn finish(&self) -> u64 {
252 self.hash
253 }
254
255 fn write(&mut self, _bytes: &[u8]) {
256 panic!("can only hash u64 using PassHasher");
257 }
258
259 #[inline]
260 fn write_u64(&mut self, i: u64) {
261 self.hash = i;
262 }
263}
264
265pub type PreHashMap<K, V> = hashbrown::HashMap<Hashed<K>, V, PassHash>;
268
269pub trait PreHashMapExt<K, V> {
271 fn get_or_insert_with<F: FnOnce() -> V>(&mut self, key: &Hashed<K>, func: F) -> &mut V;
275}
276
277impl<K: Hash + Eq + PartialEq + Clone, V> PreHashMapExt<K, V> for PreHashMap<K, V> {
278 #[inline]
279 fn get_or_insert_with<F: FnOnce() -> V>(&mut self, key: &Hashed<K>, func: F) -> &mut V {
280 let entry = self
281 .raw_entry_mut()
282 .from_key_hashed_nocheck(key.hash(), key);
283 match entry {
284 RawEntryMut::Occupied(entry) => entry.into_mut(),
285 RawEntryMut::Vacant(entry) => {
286 let (_, value) = entry.insert_hashed_nocheck(key.hash(), key.clone(), func());
287 value
288 }
289 }
290 }
291}
292
293pub type TypeIdMap<V> = hashbrown::HashMap<TypeId, V, NoOpHash>;
296
297#[derive(Clone, Default)]
299pub struct NoOpHash;
300
301impl BuildHasher for NoOpHash {
302 type Hasher = NoOpHasher;
303
304 fn build_hasher(&self) -> Self::Hasher {
305 NoOpHasher(0)
306 }
307}
308
309#[doc(hidden)]
310pub struct NoOpHasher(u64);
311
312impl Hasher for NoOpHasher {
315 fn finish(&self) -> u64 {
316 self.0
317 }
318
319 fn write(&mut self, bytes: &[u8]) {
320 self.0 = bytes.iter().fold(self.0, |hash, b| {
323 hash.rotate_left(8).wrapping_add(*b as u64)
324 });
325 }
326
327 #[inline]
328 fn write_u64(&mut self, i: u64) {
329 self.0 = i;
330 }
331}
332
333pub struct OnDrop<F: FnOnce()> {
368 callback: ManuallyDrop<F>,
369}
370
371impl<F: FnOnce()> OnDrop<F> {
372 pub fn new(callback: F) -> Self {
374 Self {
375 callback: ManuallyDrop::new(callback),
376 }
377 }
378}
379
380impl<F: FnOnce()> Drop for OnDrop<F> {
381 fn drop(&mut self) {
382 let callback = unsafe { ManuallyDrop::take(&mut self.callback) };
384 callback();
385 }
386}
387
388pub fn info<T: Debug>(data: T) {
390 tracing::info!("{:?}", data);
391}
392
393pub fn dbg<T: Debug>(data: T) {
395 tracing::debug!("{:?}", data);
396}
397
398pub fn warn<E: Debug>(result: Result<(), E>) {
400 if let Err(warn) = result {
401 tracing::warn!("{:?}", warn);
402 }
403}
404
405pub fn error<E: Debug>(result: Result<(), E>) {
407 if let Err(error) = result {
408 tracing::error!("{:?}", error);
409 }
410}
411
412#[macro_export]
414macro_rules! detailed_trace {
415 ($($tts:tt)*) => {
416 if cfg!(feature = "detailed_trace") {
417 $crate::tracing::trace!($($tts)*);
418 }
419 }
420}
421
422#[cfg(test)]
423mod tests {
424 use super::*;
425 use static_assertions::assert_impl_all;
426
427 assert_impl_all!(PreHashMap::<u64, usize>: Clone);
429
430 #[test]
431 fn fast_typeid_hash() {
432 struct Hasher;
433
434 impl core::hash::Hasher for Hasher {
435 fn finish(&self) -> u64 {
436 0
437 }
438 fn write(&mut self, _: &[u8]) {
439 panic!("Hashing of core::any::TypeId changed");
440 }
441 fn write_u64(&mut self, _: u64) {}
442 }
443
444 Hash::hash(&TypeId::of::<()>(), &mut Hasher);
445 }
446
447 #[cfg(feature = "alloc")]
448 #[test]
449 fn stable_hash_within_same_program_execution() {
450 use alloc::vec::Vec;
451
452 let mut map_1 = HashMap::new();
453 let mut map_2 = HashMap::new();
454 for i in 1..10 {
455 map_1.insert(i, i);
456 map_2.insert(i, i);
457 }
458 assert_eq!(
459 map_1.iter().collect::<Vec<_>>(),
460 map_2.iter().collect::<Vec<_>>()
461 );
462 }
463}