use std::boxed::Box;
use std::cell::UnsafeCell;
use std::marker::PhantomData;
use std::mem::MaybeUninit;
use std::pin::Pin;
use std::sync::TryLockError;
#[cold]
fn init_inner_mutex() -> Pin<Box<Inner>> {
Box::pin(Inner {
lock: std::sync::Mutex::new(()),
guard: UnsafeCell::new(MaybeUninit::uninit()),
})
}
struct Inner {
lock: std::sync::Mutex<()>,
guard: UnsafeCell<MaybeUninit<std::sync::MutexGuard<'static, ()>>>,
}
pub struct RawStdMutex(std::sync::OnceLock<Pin<Box<Inner>>>);
unsafe impl Send for RawStdMutex {}
unsafe impl Sync for RawStdMutex {}
impl RawStdMutex {
unsafe fn save_guard(&self, guard: std::sync::MutexGuard<'_, ()>) {
unsafe {
#[allow(clippy::needless_lifetimes)]
unsafe fn extend_life<'a, 'b>(
x: std::sync::MutexGuard<'a, ()>,
) -> std::sync::MutexGuard<'b, ()> {
unsafe { core::mem::transmute(x) }
}
let this = &**self.0.get().unwrap_unchecked();
*this.guard.get() = MaybeUninit::new(extend_life(guard))
}
}
}
unsafe impl lock_api::RawMutex for RawStdMutex {
#[allow(clippy::declare_interior_mutable_const)]
const INIT: Self = Self(std::sync::OnceLock::new());
type GuardMarker = PhantomData<std::sync::MutexGuard<'static, ()>>;
fn lock(&self) {
match self.0.get_or_init(init_inner_mutex).lock.lock() {
Ok(guard) => unsafe { self.save_guard(guard) },
Err(_) => unreachable!(),
}
}
fn try_lock(&self) -> bool {
match self.0.get_or_init(init_inner_mutex).lock.try_lock() {
Ok(guard) => {
unsafe { self.save_guard(guard) }
true
}
Err(TryLockError::WouldBlock) => false,
Err(TryLockError::Poisoned(_)) => unreachable!(),
}
}
unsafe fn unlock(&self) {
unsafe { MaybeUninit::assume_init_drop(&mut *self.0.get().unwrap_unchecked().guard.get()) }
}
fn is_locked(&self) -> bool {
let Some(this) = self.0.get() else {
return false;
};
match this.lock.try_lock() {
Ok(_) => false,
Err(TryLockError::WouldBlock) => true,
Err(TryLockError::Poisoned(_)) => unreachable!(),
}
}
}