#![doc = include_str!("../README.md")]
#![cfg_attr(docsrs, feature(doc_cfg))]
use std::{
fmt, ops,
sync::{
Arc, LockResult, PoisonError, RwLock, RwLockReadGuard, RwLockWriteGuard, TryLockError,
TryLockResult, Weak,
},
};
#[cfg(feature = "lite")]
pub mod lite;
pub struct Shared<T: ?Sized>(Arc<RwLock<T>>);
#[allow(clippy::arc_with_non_send_sync)] 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)),
}
}
}
impl<T: ?Sized> Shared<T> {
#[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(err) => {
Err(poison_error_map(err, |read_guard| unsafe { readguard_into_ref(read_guard) }))
}
}
}
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())
}
pub fn try_from_inner(rwlock: Arc<RwLock<T>>) -> Result<Self, Arc<RwLock<T>>> {
if Arc::strong_count(&rwlock) == 1 && Arc::weak_count(&rwlock) == 0 {
Ok(Self(rwlock))
} else {
Err(rwlock)
}
}
pub fn into_inner(this: Self) -> Arc<RwLock<T>> {
this.0
}
pub fn read_count(this: &Self) -> usize {
Arc::strong_count(&this.0) - 1
}
pub fn weak_count(this: &Self) -> usize {
Arc::weak_count(&this.0)
}
}
unsafe fn readguard_into_ref<'a, T: ?Sized + 'a>(guard: RwLockReadGuard<'a, T>) -> &'a T {
let reference: &T = &guard;
&*(reference as *const T)
}
impl<T: ?Sized> ops::Deref for Shared<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
Shared::get(self)
}
}
impl<T: fmt::Debug + ?Sized> fmt::Debug for Shared<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl<T: Default> Default for Shared<T> {
fn default() -> Self {
Self::new(T::default())
}
}
pub struct SharedReadLock<T: ?Sized>(Arc<RwLock<T>>);
impl<T: ?Sized> 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))
}
pub fn downgrade(&self) -> WeakReadLock<T> {
WeakReadLock(Arc::downgrade(&self.0))
}
pub fn try_upgrade(self) -> Result<Shared<T>, Self> {
if Arc::strong_count(&self.0) == 1 && Arc::weak_count(&self.0) == 0 {
Ok(Shared(self.0))
} else {
Err(self)
}
}
pub fn from_inner(rwlock: Arc<RwLock<T>>) -> Self {
Self(rwlock)
}
pub fn try_into_inner(self) -> Result<Arc<RwLock<T>>, Self> {
if Arc::strong_count(&self.0) == 1 && Arc::weak_count(&self.0) == 0 {
Ok(self.0)
} else {
Err(self)
}
}
}
impl<T: ?Sized> Clone for SharedReadLock<T> {
fn clone(&self) -> Self {
Self(Arc::clone(&self.0))
}
}
impl<T: fmt::Debug + ?Sized> fmt::Debug for SharedReadLock<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
pub struct WeakReadLock<T: ?Sized>(Weak<RwLock<T>>);
impl<T: ?Sized> WeakReadLock<T> {
pub fn upgrade(&self) -> Option<SharedReadLock<T>> {
Weak::upgrade(&self.0).map(SharedReadLock)
}
}
impl<T: ?Sized> Clone for WeakReadLock<T> {
fn clone(&self) -> Self {
Self(Weak::clone(&self.0))
}
}
impl<T: fmt::Debug + ?Sized> fmt::Debug for WeakReadLock<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
#[clippy::has_significant_drop]
pub struct SharedReadGuard<'a, T: ?Sized>(RwLockReadGuard<'a, T>);
impl<'a, T: ?Sized + 'a> SharedReadGuard<'a, T> {
pub fn from_inner(guard: RwLockReadGuard<'a, T>) -> Self {
Self(guard)
}
}
impl<'a, T: ?Sized + 'a> ops::Deref for SharedReadGuard<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<'a, T: fmt::Debug + ?Sized + 'a> fmt::Debug for SharedReadGuard<'a, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
#[clippy::has_significant_drop]
pub struct SharedWriteGuard<'a, T: ?Sized>(RwLockWriteGuard<'a, T>);
impl<'a, T: ?Sized> SharedWriteGuard<'a, T> {
pub fn from_inner(guard: RwLockWriteGuard<'a, T>) -> Self {
Self(guard)
}
}
impl<'a, T: ?Sized + 'a> ops::Deref for SharedWriteGuard<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<'a, T: ?Sized + 'a> ops::DerefMut for SharedWriteGuard<'a, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<'a, T: fmt::Debug + ?Sized + 'a> fmt::Debug for SharedWriteGuard<'a, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
fn poison_error_map<T, U>(error: PoisonError<T>, f: impl FnOnce(T) -> U) -> PoisonError<U> {
let inner = error.into_inner();
PoisonError::new(f(inner))
}
fn try_lock_error_map<T, U>(error: TryLockError<T>, f: impl FnOnce(T) -> U) -> TryLockError<U> {
match error {
TryLockError::Poisoned(err) => TryLockError::Poisoned(poison_error_map(err, f)),
TryLockError::WouldBlock => TryLockError::WouldBlock,
}
}