use alloc::sync::Arc;
use thread_checked_lock::{
HandlePoisonResult as _, LockError, ThreadCheckedMutex, ThreadCheckedMutexGuard,
};
use crate::container_traits::{
FragileTryContainer, FragileTryMutContainer, TryContainer, TryMutContainer,
};
#[derive(Debug, Clone, Copy)]
pub enum ErasedLockError {
Poisoned,
LockedByCurrentThread,
}
impl ErasedLockError {
#[inline]
#[must_use]
pub fn panic_if_poison(self) -> Self {
match self {
#[expect(
clippy::panic,
reason = "library users will frequently want to panic on poison",
)]
Self::Poisoned => panic!("ErasedLockError was poison"),
Self::LockedByCurrentThread => Self::LockedByCurrentThread,
}
}
}
impl<T> From<LockError<T>> for ErasedLockError {
#[inline]
fn from(value: LockError<T>) -> Self {
match value {
LockError::Poisoned(_) => Self::Poisoned,
LockError::LockedByCurrentThread => Self::LockedByCurrentThread,
}
}
}
impl<T: ?Sized> FragileTryContainer<T> for Arc<ThreadCheckedMutex<T>> {
type Ref<'a> = ThreadCheckedMutexGuard<'a, T> where T: 'a;
type RefError = ErasedLockError;
#[inline]
fn new_container(t: T) -> Self where T: Sized {
Self::new(ThreadCheckedMutex::new(t))
}
#[inline]
fn into_inner(self) -> Option<T> where T: Sized {
let result = Self::into_inner(self)?
.into_inner()
.ignore_poison();
match result {
Ok(t) => Some(t),
#[expect(unreachable_code, reason = "yeah, that's the point")]
Err(poisonless_poison) => match poisonless_poison.poison.into_inner() {},
}
}
#[inline]
fn try_get_ref(&self) -> Result<Self::Ref<'_>, Self::RefError> {
self.lock().map_err(Into::into)
}
}
impl<T: ?Sized> TryContainer<T> for Arc<ThreadCheckedMutex<T>> {}
impl<T: ?Sized> FragileTryMutContainer<T> for Arc<ThreadCheckedMutex<T>> {
type RefMut<'a> = ThreadCheckedMutexGuard<'a, T> where T: 'a;
type RefMutError = ErasedLockError;
#[inline]
fn try_get_mut(&mut self) -> Result<Self::RefMut<'_>, Self::RefMutError> {
self.lock().map_err(Into::into)
}
}
impl<T: ?Sized> TryMutContainer<T> for Arc<ThreadCheckedMutex<T>> {}