use js_sys::*;
use std::cell::*;
use std::hint::*;
use std::marker::*;
use std::mem::*;
use std::panic::*;
use std::sync::*;
use std::sync::atomic::*;
use std::time::*;
#[inline(always)]
fn can_block() -> bool {
thread_local! {
static CAN_BLOCK: bool = web_sys::window().is_none();
}
CAN_BLOCK.with(|x| *x)
}
#[derive(Debug, Default)]
#[repr(transparent)]
pub struct Condvar {
inner: std::sync::Condvar
}
impl Condvar {
const FALSE_TIMEOUT_RESULT: WaitTimeoutResult = unsafe { transmute(false) };
#[must_use]
#[inline]
pub const fn new() -> Condvar {
Condvar { inner: std::sync::Condvar::new() }
}
pub fn wait<'a, T>(&self, guard: MutexGuard<'a, T>) -> LockResult<MutexGuard<'a, T>> {
if can_block() {
self.inner.wait(guard)
}
else {
Self::guard_to_mutex(guard).lock()
}
}
pub fn wait_while<'a, T, F>(
&self,
mut guard: MutexGuard<'a, T>,
mut condition: F,
) -> LockResult<MutexGuard<'a, T>>
where
F: FnMut(&mut T) -> bool,
{
while condition(&mut *guard) {
guard = self.wait(guard)?;
}
Ok(guard)
}
#[allow(deprecated)]
#[deprecated(since = "1.6.0", note = "replaced by `std::sync::Condvar::wait_timeout`")]
pub fn wait_timeout_ms<'a, T>(
&self,
guard: MutexGuard<'a, T>,
ms: u32,
) -> LockResult<(MutexGuard<'a, T>, bool)> {
unsafe {
if can_block() {
self.inner.wait_timeout_ms(guard, ms)
}
else {
Self::guard_to_mutex(guard).lock().map(|guard| (guard, false)).map_err(|poison| transmute((poison.into_inner(), false)))
}
}
}
pub fn wait_timeout<'a, T>(
&self,
guard: MutexGuard<'a, T>,
dur: Duration,
) -> LockResult<(MutexGuard<'a, T>, WaitTimeoutResult)> {
unsafe {
if can_block() {
self.inner.wait_timeout(guard, dur)
}
else {
Self::guard_to_mutex(guard).lock().map(|guard| (guard, Self::FALSE_TIMEOUT_RESULT)).map_err(|poison| transmute((poison.into_inner(), Self::FALSE_TIMEOUT_RESULT)))
}
}
}
pub fn wait_timeout_while<'a, T, F>(
&self,
guard: MutexGuard<'a, T>,
dur: Duration,
condition: F,
) -> LockResult<(MutexGuard<'a, T>, WaitTimeoutResult)>
where
F: FnMut(&mut T) -> bool,
{
unsafe {
if can_block() {
self.inner.wait_timeout_while(guard, dur, condition)
}
else {
Self::guard_to_mutex(guard).lock().map(|guard| (guard, Self::FALSE_TIMEOUT_RESULT)).map_err(|poison| transmute((poison.into_inner(), Self::FALSE_TIMEOUT_RESULT)))
}
}
}
pub fn notify_one(&self) {
self.inner.notify_one()
}
pub fn notify_all(&self) {
self.inner.notify_all()
}
fn guard_to_mutex<T: ?Sized>(guard: MutexGuard<T>) -> &Mutex<T> {
unsafe {
transmute::<_, &&Mutex<T>>(&guard)
}
}
}
#[derive(Debug, Default)]
#[repr(transparent)]
pub struct Mutex<T: ?Sized> {
inner: std::sync::Mutex<T>
}
impl<T> Mutex<T> {
#[inline]
pub const fn new(t: T) -> Mutex<T> {
Mutex { inner: std::sync::Mutex::new(t) }
}
}
impl<T: ?Sized> Mutex<T> {
pub fn lock(&self) -> LockResult<MutexGuard<'_, T>> {
if can_block() {
self.inner.lock()
}
else {
loop {
match self.inner.try_lock() {
Ok(guard) => return Ok(guard),
Err(TryLockError::WouldBlock) => {},
Err(TryLockError::Poisoned(err)) => return Err(err)
}
}
}
}
pub fn try_lock(&self) -> TryLockResult<MutexGuard<'_, T>> {
self.inner.try_lock()
}
#[cfg(feature = "mutex_unlock")]
pub fn unlock(guard: MutexGuard<'_, T>) {
std::sync::Mutex::unlock(guard);
}
#[inline]
pub fn is_poisoned(&self) -> bool {
self.inner.is_poisoned()
}
#[inline]
#[cfg(feature = "mutex_unpoison")]
pub fn clear_poison(&self) {
self.inner.clear_poison();
}
pub fn into_inner(self) -> LockResult<T>
where
T: Sized,
{
self.inner.into_inner()
}
pub fn get_mut(&mut self) -> LockResult<&mut T> {
self.inner.get_mut()
}
}
impl<T> From<T> for Mutex<T> {
fn from(t: T) -> Self {
Mutex::new(t)
}
}
#[derive(Debug, Default)]
#[repr(transparent)]
pub struct RwLock<T: ?Sized> {
inner: std::sync::RwLock<T>
}
impl<T> RwLock<T> {
#[inline]
pub const fn new(t: T) -> RwLock<T> {
RwLock { inner: std::sync::RwLock::new(t) }
}
}
impl<T: ?Sized> RwLock<T> {
#[inline]
pub fn read(&self) -> LockResult<RwLockReadGuard<'_, T>> {
if can_block() {
self.inner.read()
}
else {
loop {
match self.inner.try_read() {
Ok(guard) => return Ok(guard),
Err(TryLockError::WouldBlock) => {},
Err(TryLockError::Poisoned(err)) => return Err(err)
}
}
}
}
#[inline]
pub fn try_read(&self) -> TryLockResult<RwLockReadGuard<'_, T>> {
self.inner.try_read()
}
#[inline]
pub fn write(&self) -> LockResult<RwLockWriteGuard<'_, T>> {
if can_block() {
self.inner.write()
}
else {
loop {
match self.inner.try_write() {
Ok(guard) => return Ok(guard),
Err(TryLockError::WouldBlock) => {},
Err(TryLockError::Poisoned(err)) => return Err(err)
}
}
}
}
#[inline]
pub fn try_write(&self) -> TryLockResult<RwLockWriteGuard<'_, T>> {
self.inner.try_write()
}
#[inline]
pub fn is_poisoned(&self) -> bool {
self.inner.is_poisoned()
}
#[inline]
#[cfg(feature = "mutex_unpoison")]
pub fn clear_poison(&self) {
self.inner.clear_poison();
}
pub fn into_inner(self) -> LockResult<T>
where
T: Sized,
{
self.inner.into_inner()
}
pub fn get_mut(&mut self) -> LockResult<&mut T> {
self.inner.get_mut()
}
}
impl<T> From<T> for RwLock<T> {
fn from(t: T) -> Self {
RwLock::new(t)
}
}
#[deprecated(
since = "1.38.0",
note = "the `new` function is now preferred"
)]
pub const ONCE_INIT: Once = Once::new();
#[derive(Debug)]
#[repr(transparent)]
pub struct Once {
inner: std::sync::Once,
}
impl Once {
const INCOMPLETE: u32 = 0;
const POISONED: u32 = 1;
const RUNNING: u32 = 2;
const QUEUED: u32 = 3;
const COMPLETE: u32 = 4;
#[inline]
#[must_use]
pub const fn new() -> Once {
Once { inner: std::sync::Once::new() }
}
#[inline]
#[track_caller]
pub fn call_once<F>(&self, f: F)
where
F: FnOnce(),
{
if can_block() {
self.inner.call_once(f);
}
else {
let mut f = Some(f);
self.call_spin(false, &mut |_| f.take().unwrap()());
}
}
#[inline]
pub fn call_once_force<F>(&self, f: F)
where
F: FnOnce(&std::sync::OnceState),
{
if can_block() {
self.inner.call_once_force(f);
}
else {
let mut f = Some(f);
self.call_spin(true, &mut |p| f.take().unwrap()(p));
}
}
#[inline]
pub fn is_completed(&self) -> bool {
self.inner.is_completed()
}
#[cold]
#[track_caller]
fn call_spin(&self, ignore_poisoning: bool, f: &mut impl FnMut(&std::sync::OnceState)) {
unsafe {
let mut state = self.state().load(Ordering::Acquire);
loop {
match state {
Self::POISONED if !ignore_poisoning => {
panic!("Once instance has previously been poisoned");
}
Self::INCOMPLETE | Self::POISONED => {
if let Err(new) =
self.state().compare_exchange_weak(state, Self::RUNNING, Ordering::Acquire, Ordering::Acquire)
{
state = new;
continue;
}
let mut waiter_queue =
CompletionGuard { state: self.state(), set_state_on_drop_to: Self::POISONED };
let f_state = OnceState {
poisoned: state == Self::POISONED,
set_state_to: Cell::new(Self::COMPLETE),
};
f(transmute(&f_state));
waiter_queue.set_state_on_drop_to = f_state.set_state_to.get();
drop(waiter_queue);
return;
}
Self::RUNNING | Self::QUEUED => {
if state == Self::RUNNING {
if let Err(new) = self.state().compare_exchange_weak(Self::RUNNING, Self::QUEUED, Ordering::Relaxed, Ordering::Acquire) {
state = new;
continue;
}
}
state = self.state().load(Ordering::Acquire);
}
Self::COMPLETE => return,
_ => unreachable!("state is never set to invalid values"),
}
}
}
}
fn state(&self) -> &AtomicU32 {
unsafe {
transmute(self)
}
}
}
struct CompletionGuard<'a> {
state: &'a AtomicU32,
set_state_on_drop_to: u32,
}
impl<'a> Drop for CompletionGuard<'a> {
#[inline]
fn drop(&mut self) {
unsafe {
if self.state.swap(self.set_state_on_drop_to, Ordering::Release) == Once::QUEUED {
let view = Int32Array::view_mut_raw(self.state as *const _ as *mut _, 1);
let _ = Atomics::notify(&view, 0);
}
}
}
}
#[allow(dead_code)]
struct OnceState {
poisoned: bool,
set_state_to: Cell<u32>,
}
#[repr(C)]
pub struct OnceLock<T> {
once: Once,
value: UnsafeCell<MaybeUninit<T>>,
_marker: PhantomData<T>,
}
impl<T> OnceLock<T> {
#[inline]
#[must_use]
pub const fn new() -> OnceLock<T> {
OnceLock {
once: Once::new(),
value: UnsafeCell::new(MaybeUninit::uninit()),
_marker: PhantomData,
}
}
#[inline]
pub fn get(&self) -> Option<&T> {
if self.is_initialized() {
Some(unsafe { self.get_unchecked() })
} else {
None
}
}
#[inline]
pub fn get_mut(&mut self) -> Option<&mut T> {
if self.is_initialized() {
Some(unsafe { self.get_unchecked_mut() })
} else {
None
}
}
#[inline]
pub fn set(&self, value: T) -> Result<(), T> {
match self.try_insert(value) {
Ok(_) => Ok(()),
Err((_, value)) => Err(value),
}
}
#[inline]
#[cfg(feature = "once_cell_try_insert")]
pub fn try_insert(&self, value: T) -> Result<&T, (&T, T)> {
let mut value = Some(value);
let res = self.get_or_init(|| value.take().unwrap());
match value {
None => Ok(res),
Some(value) => Err((res, value)),
}
}
#[inline]
pub fn try_insert(&self, value: T) -> Result<&T, (&T, T)> {
let mut value = Some(value);
let res = self.get_or_init(|| value.take().unwrap());
match value {
None => Ok(res),
Some(value) => Err((res, value)),
}
}
#[inline]
pub fn get_or_init<F>(&self, f: F) -> &T
where
F: FnOnce() -> T,
{
unsafe {
if let Some(value) = self.get() {
return value;
}
if self.initialize(|| Ok::<T, ()>(f())).is_err() {
unreachable_unchecked();
}
debug_assert!(self.is_initialized());
self.get_unchecked()
}
}
#[inline]
#[cfg(feature = "once_cell_try")]
pub fn get_or_try_init<F, E>(&self, f: F) -> Result<&T, E>
where
F: FnOnce() -> Result<T, E>,
{
if let Some(value) = self.get() {
return Ok(value);
}
self.initialize(f)?;
debug_assert!(self.is_initialized());
Ok(unsafe { self.get_unchecked() })
}
#[inline]
pub fn into_inner(mut self) -> Option<T> {
self.take()
}
#[inline]
pub fn take(&mut self) -> Option<T> {
if self.is_initialized() {
self.once = Once::new();
unsafe { Some((&mut *self.value.get()).assume_init_read()) }
} else {
None
}
}
#[inline]
fn is_initialized(&self) -> bool {
self.once.is_completed()
}
#[cold]
fn initialize<F, E>(&self, f: F) -> Result<(), E>
where
F: FnOnce() -> Result<T, E>,
{
unsafe {
let mut res: Result<(), E> = Ok(());
let slot = &self.value;
self.once.call_once_force(|p| {
match f() {
Ok(value) => {
(&mut *slot.get()).write(value);
}
Err(e) => {
res = Err(e);
transmute::<_, &OnceState>(p).set_state_to.set(Once::POISONED);
}
}
});
res
}
}
#[inline]
unsafe fn get_unchecked(&self) -> &T {
debug_assert!(self.is_initialized());
(&*self.value.get()).assume_init_ref()
}
#[inline]
unsafe fn get_unchecked_mut(&mut self) -> &mut T {
debug_assert!(self.is_initialized());
(&mut *self.value.get()).assume_init_mut()
}
}
unsafe impl<T: Sync + Send> Sync for OnceLock<T> {}
unsafe impl<T: Send> Send for OnceLock<T> {}
impl<T: RefUnwindSafe + UnwindSafe> RefUnwindSafe for OnceLock<T> {}
impl<T: UnwindSafe> UnwindSafe for OnceLock<T> {}
impl<T> Default for OnceLock<T> {
#[inline]
fn default() -> OnceLock<T> {
OnceLock::new()
}
}
impl<T: std::fmt::Debug> std::fmt::Debug for OnceLock<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut d = f.debug_tuple("OnceLock");
match self.get() {
Some(v) => d.field(v),
None => d.field(&format_args!("<uninit>")),
};
d.finish()
}
}
impl<T: Clone> Clone for OnceLock<T> {
#[inline]
fn clone(&self) -> OnceLock<T> {
let cell = Self::new();
if let Some(value) = self.get() {
match cell.set(value.clone()) {
Ok(()) => (),
Err(_) => unreachable!(),
}
}
cell
}
}
impl<T> From<T> for OnceLock<T> {
#[inline]
fn from(value: T) -> Self {
let cell = Self::new();
match cell.set(value) {
Ok(()) => cell,
Err(_) => unreachable!(),
}
}
}
impl<T: PartialEq> PartialEq for OnceLock<T> {
#[inline]
fn eq(&self, other: &OnceLock<T>) -> bool {
self.get() == other.get()
}
}
impl<T: Eq> Eq for OnceLock<T> {}
impl<T> Drop for OnceLock<T> {
#[inline]
fn drop(&mut self) {
if self.is_initialized() {
unsafe { (&mut *self.value.get()).assume_init_drop() };
}
}
}