use std::{
fmt, ops,
sync::{LockResult, PoisonError, RwLock, TryLockResult},
};
use rclite::Arc;
use crate::{readguard_into_ref, try_lock_error_map, SharedReadGuard, SharedWriteGuard};
pub struct Shared<T>(Arc<RwLock<T>>);
impl<T> Shared<T> {
pub fn new(data: T) -> Self {
Self(Arc::new(RwLock::new(data)))
}
pub fn unwrap(this: Self) -> Result<T, Self> {
match Arc::try_unwrap(this.0) {
Ok(rwlock) => Ok(rwlock.into_inner().unwrap()),
Err(arc) => Err(Self(arc)),
}
}
#[track_caller]
pub fn get(this: &Self) -> &T {
Self::try_get(this).unwrap()
}
pub fn try_get(this: &Self) -> LockResult<&T> {
match this.0.read() {
Ok(read_guard) => Ok(unsafe { readguard_into_ref(read_guard) }),
Err(poison_err) => {
let read_guard = poison_err.into_inner();
let r = unsafe { readguard_into_ref(read_guard) };
Err(PoisonError::new(r))
}
}
}
pub fn lock(this: &mut Self) -> SharedWriteGuard<'_, T> {
SharedWriteGuard(this.0.write().unwrap())
}
pub fn get_read_lock(this: &Self) -> SharedReadLock<T> {
SharedReadLock(this.0.clone())
}
}
impl<T> ops::Deref for Shared<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
Shared::get(self)
}
}
impl<T: fmt::Debug> fmt::Debug for Shared<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
#[derive(Clone)]
pub struct SharedReadLock<T>(Arc<RwLock<T>>);
impl<T> SharedReadLock<T> {
pub fn lock(&self) -> SharedReadGuard<'_, T> {
SharedReadGuard(self.0.read().unwrap())
}
pub fn try_lock(&self) -> TryLockResult<SharedReadGuard<'_, T>> {
self.0
.try_read()
.map(SharedReadGuard)
.map_err(|err| try_lock_error_map(err, SharedReadGuard))
}
}
impl<T: fmt::Debug> fmt::Debug for SharedReadLock<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}