use core::{
cell::UnsafeCell,
ops::{Deref, DerefMut},
sync::atomic::{AtomicBool, AtomicU8, Ordering},
};
pub struct Mutex<T> {
locked: AtomicBool,
data: UnsafeCell<T>,
}
pub struct MutexGuard<'a, T> {
mutex: &'a Mutex<T>,
}
impl<T> Mutex<T> {
pub const fn new(data: T) -> Self {
Self { locked: AtomicBool::new(false), data: UnsafeCell::new(data) }
}
pub fn lock(&self) -> Result<MutexGuard<'_, T>, PoisonError<MutexGuard<'_, T>>> {
while self.locked.swap(true, Ordering::Acquire) {
core::hint::spin_loop();
}
Ok(MutexGuard { mutex: self })
}
}
unsafe impl<T: Send> Sync for Mutex<T> {}
unsafe impl<T: Send> Send for Mutex<T> {}
impl<T> Deref for MutexGuard<'_, T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { &*self.mutex.data.get() }
}
}
impl<T> DerefMut for MutexGuard<'_, T> {
fn deref_mut(&mut self) -> &mut T {
unsafe { &mut *self.mutex.data.get() }
}
}
impl<T> Drop for MutexGuard<'_, T> {
fn drop(&mut self) {
self.mutex.locked.store(false, Ordering::Release);
}
}
pub struct PoisonError<T> {
_guard: T,
}
impl<T> PoisonError<T> {
#[allow(dead_code)]
pub fn new(guard: T) -> Self {
PoisonError { _guard: guard }
}
}
impl<T> core::fmt::Debug for PoisonError<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str("PoisonError { .. }")
}
}
impl<T> core::fmt::Display for PoisonError<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str("poisoned lock: another task failed while holding the lock")
}
}
const UNINIT: u8 = 0;
const INITIALIZING: u8 = 1;
const INITIALIZED: u8 = 2;
pub struct OnceLock<T> {
inner: UnsafeCell<Option<T>>,
state: AtomicU8,
}
unsafe impl<T: Send> Sync for OnceLock<T> {}
unsafe impl<T: Send> Send for OnceLock<T> {}
impl<T> OnceLock<T> {
pub const fn new() -> Self {
OnceLock { inner: UnsafeCell::new(None), state: AtomicU8::new(UNINIT) }
}
pub fn get(&self) -> Option<&T> {
if self.state.load(Ordering::Acquire) == INITIALIZED {
unsafe { (*self.inner.get()).as_ref() }
} else {
None
}
}
pub fn set(&self, value: T) -> Result<(), T> {
match self.state.compare_exchange(
UNINIT,
INITIALIZING,
Ordering::Acquire,
Ordering::Acquire,
) {
Ok(_) => {
unsafe {
*self.inner.get() = Some(value);
}
self.state.store(INITIALIZED, Ordering::Release);
Ok(())
}
Err(_) => Err(value),
}
}
pub fn get_or_init<F>(&self, f: F) -> &T
where
F: FnOnce() -> T,
{
match self.state.compare_exchange(
UNINIT,
INITIALIZING,
Ordering::Acquire,
Ordering::Acquire,
) {
Ok(_) => {
let value = f();
unsafe {
*self.inner.get() = Some(value);
}
self.state.store(INITIALIZED, Ordering::Release);
}
Err(INITIALIZED) => {}
Err(_) => {
while self.state.load(Ordering::Acquire) != INITIALIZED {
core::hint::spin_loop();
}
}
}
unsafe { (*self.inner.get()).as_ref().unwrap() }
}
}
impl<T> Default for OnceLock<T> {
fn default() -> Self {
Self::new()
}
}
pub struct LazyLock<T, F = fn() -> T> {
once: OnceLock<T>,
init: Mutex<Option<F>>,
}
unsafe impl<T: Send + Sync, F: Send> Sync for LazyLock<T, F> {}
unsafe impl<T: Send, F: Send> Send for LazyLock<T, F> {}
impl<T, F: FnOnce() -> T> LazyLock<T, F> {
pub const fn new(f: F) -> Self {
LazyLock { once: OnceLock::new(), init: Mutex::new(Some(f)) }
}
pub fn force(&self) -> &T {
self.once.get_or_init(|| {
let f = self
.init
.lock()
.expect("LazyLock init mutex poisoned")
.take()
.expect("LazyLock init function already taken");
f()
})
}
}
impl<T, F: FnOnce() -> T> core::ops::Deref for LazyLock<T, F> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.force()
}
}