#[cfg(not(feature = "std"))]
use spin::{Mutex as MutexImported, MutexGuard, Once as OnceImported, RwLock as RwLockImported};
#[cfg(feature = "std")]
use std::sync::{
Mutex as MutexImported, MutexGuard, OnceLock as OnceImported, RwLock as RwLockImported,
};
#[cfg(not(feature = "std"))]
pub use spin::{Lazy, RwLockReadGuard, RwLockWriteGuard};
#[cfg(feature = "std")]
pub use std::sync::{LazyLock as Lazy, RwLockReadGuard, RwLockWriteGuard};
pub use spin::Once;
#[cfg(target_has_atomic = "ptr")]
pub use alloc::sync::Arc;
#[cfg(not(target_has_atomic = "ptr"))]
pub use portable_atomic_util::Arc;
#[cfg(target_has_atomic = "ptr")]
pub use core::sync::atomic::{AtomicBool, AtomicU8, AtomicU32, AtomicUsize, Ordering};
#[cfg(not(target_has_atomic = "ptr"))]
pub use portable_atomic::{AtomicBool, AtomicU8, AtomicU32, AtomicUsize, Ordering};
#[derive(Debug, Default)]
pub struct Mutex<T> {
inner: MutexImported<T>,
}
impl<T> Mutex<T> {
#[inline(always)]
pub const fn new(value: T) -> Self {
Self {
inner: MutexImported::new(value),
}
}
#[inline(always)]
pub fn lock(&self) -> MutexGuard<'_, T> {
#[cfg(not(feature = "std"))]
{
self.inner.lock()
}
#[cfg(feature = "std")]
{
self.inner
.lock()
.unwrap_or_else(|poisoned| poisoned.into_inner())
}
}
}
#[derive(Debug)]
pub struct RwLock<T> {
inner: RwLockImported<T>,
}
impl<T> RwLock<T> {
#[inline(always)]
pub const fn new(value: T) -> Self {
Self {
inner: RwLockImported::new(value),
}
}
#[inline(always)]
pub fn read(&self) -> RwLockReadGuard<'_, T> {
#[cfg(not(feature = "std"))]
{
self.inner.read()
}
#[cfg(feature = "std")]
{
self.inner
.read()
.unwrap_or_else(|poisoned| poisoned.into_inner())
}
}
#[inline(always)]
pub fn write(&self) -> RwLockWriteGuard<'_, T> {
#[cfg(not(feature = "std"))]
{
self.inner.write()
}
#[cfg(feature = "std")]
{
self.inner
.write()
.unwrap_or_else(|poisoned| poisoned.into_inner())
}
}
}
#[allow(dead_code)]
#[derive(Eq, PartialEq, Clone, Copy, Hash, Debug)]
pub struct ThreadId(core::num::NonZeroU64);
pub struct SyncOnceCell<T>(OnceImported<T>);
impl<T> Default for SyncOnceCell<T> {
fn default() -> Self {
Self::new()
}
}
impl<T> SyncOnceCell<T> {
#[inline(always)]
pub fn new() -> Self {
Self(OnceImported::new())
}
#[inline(always)]
pub fn initialized(value: T) -> Self {
#[cfg(not(feature = "std"))]
{
let cell = OnceImported::initialized(value);
Self(cell)
}
#[cfg(feature = "std")]
{
let cell = OnceImported::new();
let _ = cell.set(value);
Self(cell)
}
}
#[inline(always)]
pub fn get_or_init<F>(&self, f: F) -> &T
where
F: FnOnce() -> T,
{
#[cfg(not(feature = "std"))]
{
self.0.call_once(f)
}
#[cfg(feature = "std")]
{
self.0.get_or_init(f)
}
}
}
#[cfg(all(test, feature = "std"))]
mod tests {
use super::*;
#[test]
fn poisoned_mutex_recovers() {
let mutex = Mutex::new(0u32);
std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
let _guard = mutex.lock();
panic!("poison the lock");
}))
.unwrap_err();
*mutex.lock() += 1;
assert_eq!(*mutex.lock(), 1);
}
#[test]
fn poisoned_rwlock_recovers() {
let lock = RwLock::new(0u32);
std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
let _guard = lock.write();
panic!("poison the lock");
}))
.unwrap_err();
assert_eq!(*lock.read(), 0);
}
}