use alloc::borrow::ToOwned;
use alloc::boxed::Box;
use alloc::format;
use alloc::string::{String, ToString};
use alloc::vec::Vec;
use hashbrown::HashMap;
use core::hash::{BuildHasher, Hash};
pub use parking_lot::{
MappedRwLockReadGuard as MappedReadGuard, MappedRwLockWriteGuard as MappedWriteGuard,
RwLockReadGuard as ReadGuard, RwLockWriteGuard as WriteGuard,
};
pub use self::atomic::AtomicU64;
pub use self::freeze::{FreezeLock, FreezeReadGuard, FreezeWriteGuard};
#[doc(no_inline)]
pub use self::lock::{Lock, LockGuard, Mode};
pub use self::mode::{
FromDyn, check_dyn_thread_safe, is_dyn_thread_safe, set_dyn_thread_safe_mode,
};
pub use self::parallel::{
broadcast, par_fns, par_for_each_in, par_for_each_slice, par_join, par_map, parallel_guard,
spawn, try_par_for_each_in,
};
pub use self::vec::{AppendOnlyIndexVec, AppendOnlyVec};
pub use self::worker_local::{Registry, WorkerLocal};
pub use crate::rustc_data_structures::marker::*;
mod freeze;
mod lock;
mod parallel;
mod vec;
mod worker_local;
mod atomic {
#[cfg(target_has_atomic = "64")]
pub use core::sync::atomic::AtomicU64;
#[cfg(not(target_has_atomic = "64"))]
pub use portable_atomic::AtomicU64;
}
mod mode {
use core::sync::atomic::{AtomicU8, Ordering};
const UNINITIALIZED: u8 = 0;
const DYN_NOT_THREAD_SAFE: u8 = 1;
const DYN_THREAD_SAFE: u8 = 2;
static DYN_THREAD_SAFE_MODE: AtomicU8 = AtomicU8::new(UNINITIALIZED);
#[inline]
pub fn check_dyn_thread_safe() -> Option<FromDyn<()>> {
is_dyn_thread_safe().then_some(FromDyn(()))
}
#[inline]
pub fn is_dyn_thread_safe() -> bool {
match DYN_THREAD_SAFE_MODE.load(Ordering::Relaxed) {
DYN_NOT_THREAD_SAFE => false,
DYN_THREAD_SAFE => true,
_ => panic!("uninitialized dyn_thread_safe mode!"),
}
}
#[inline]
pub(super) fn might_be_dyn_thread_safe() -> bool {
DYN_THREAD_SAFE_MODE.load(Ordering::Relaxed) != DYN_NOT_THREAD_SAFE
}
pub fn set_dyn_thread_safe_mode(mode: bool) {
let set: u8 = if mode { DYN_THREAD_SAFE } else { DYN_NOT_THREAD_SAFE };
let previous = DYN_THREAD_SAFE_MODE.compare_exchange(
UNINITIALIZED,
set,
Ordering::Relaxed,
Ordering::Relaxed,
);
assert!(previous.is_ok() || previous == Err(set));
}
#[derive(Copy, Clone)]
pub struct FromDyn<T>(T);
impl<T> FromDyn<T> {
#[inline(always)]
pub fn derive<O>(&self, val: O) -> FromDyn<O> {
FromDyn(val)
}
#[inline(always)]
pub fn into_inner(self) -> T {
self.0
}
}
impl<T> core::ops::Deref for FromDyn<T> {
type Target = T;
#[inline(always)]
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T> core::ops::DerefMut for FromDyn<T> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
}
const ERROR_CHECKING: bool = false;
#[derive(Default)]
#[repr(align(64))]
pub struct CacheAligned<T>(pub T);
pub trait HashMapExt<K, V> {
fn insert_same(&mut self, key: K, value: V);
}
impl<K: Eq + Hash, V: Eq, S: BuildHasher> HashMapExt<K, V> for HashMap<K, V, S> {
fn insert_same(&mut self, key: K, value: V) {
self.entry(key).and_modify(|old| assert!(*old == value)).or_insert(value);
}
}
#[derive(Debug, Default)]
pub struct RwLock<T>(parking_lot::RwLock<T>);
impl<T> RwLock<T> {
#[inline(always)]
pub fn new(inner: T) -> Self {
RwLock(parking_lot::RwLock::new(inner))
}
#[inline(always)]
pub fn into_inner(self) -> T {
self.0.into_inner()
}
#[inline(always)]
pub fn get_mut(&mut self) -> &mut T {
self.0.get_mut()
}
#[inline(always)]
pub fn read(&self) -> ReadGuard<'_, T> {
if ERROR_CHECKING {
self.0.try_read().expect("lock was already held")
} else {
self.0.read()
}
}
#[inline(always)]
pub fn try_write(&self) -> Result<WriteGuard<'_, T>, ()> {
self.0.try_write().ok_or(())
}
#[inline(always)]
pub fn write(&self) -> WriteGuard<'_, T> {
if ERROR_CHECKING {
self.0.try_write().expect("lock was already held")
} else {
self.0.write()
}
}
#[inline(always)]
#[track_caller]
pub fn borrow(&self) -> ReadGuard<'_, T> {
self.read()
}
#[inline(always)]
#[track_caller]
pub fn borrow_mut(&self) -> WriteGuard<'_, T> {
self.write()
}
}