#![feature(associated_type_defaults)]
#![feature(associated_type_bounds)]
#![feature(mutex_unlock)]
#![feature(negative_impls)]
use std::ops::{Deref, DerefMut};
use std::{fmt::{self}, marker::PhantomData, sync::{Arc, LockResult, Mutex, MutexGuard, PoisonError, TryLockError, TryLockResult}};
pub struct RefMutexGuard<'r, 'v, T: ?Sized> {
base: MutexGuard<'r, &'v T>,
phantom: PhantomData<&'r T>,
}
impl<T: ?Sized> !Send for RefMutexGuard<'_, '_, T> {}
#[cfg(test)]
mod tests {
use std::sync::Mutex;
use crate::RefMutexGuard;
#[test]
fn test_sync_guard() {
let mutex = Mutex::new(&0);
let lock = mutex.lock().unwrap();
let _: &dyn Sync = &RefMutexGuard::new(lock);
}
}
impl<'r, 'v, T: ?Sized> RefMutexGuard<'r, 'v, T>
{
pub fn new(lock: MutexGuard<'r, &'v T>) -> Self
{
Self { base: lock, phantom: PhantomData }
}
pub fn from_lock_result(lock: LockResult<MutexGuard<'r, &'v T>>) -> Result<Self, PoisonError<Self>>
{
match lock {
Ok(lock) => Ok(Self::new(lock)),
Err(err) => {
let e = err.into_inner();
let e2 = Self::new(e);
Err(PoisonError::new(e2))
},
}
}
pub fn from_try_lock_result(lock: TryLockResult<MutexGuard<'r, &'v T>>) -> Result<Self, TryLockError<Self>>
{
match lock {
Ok(lock) => Ok(Self::new(lock)),
Err(TryLockError::WouldBlock) => Err(TryLockError::WouldBlock),
Err(TryLockError::Poisoned(err)) => {
let e = err.into_inner();
let e2 = Self::new(e);
Err(TryLockError::Poisoned(PoisonError::new(e2)))
},
}
}
}
impl<'r, 'v, T: ?Sized> From<MutexGuard<'r, &'v T>> for RefMutexGuard<'r, 'v, T> {
fn from(lock: MutexGuard<'r, &'v T>) -> Self {
Self::new(lock)
}
}
impl<'v, T: ?Sized> Deref for RefMutexGuard<'_, 'v, T> {
type Target = &'v T;
fn deref(&self) -> &&'v T {
&*self.base.deref()
}
}
impl<'v, T: ?Sized> DerefMut for RefMutexGuard<'_, 'v, T> {
fn deref_mut(&mut self) -> &mut &'v T {
&mut *self.base.deref_mut()
}
}
impl<T: ?Sized + fmt::Debug> fmt::Debug for RefMutexGuard<'_, '_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("RefMutexGuard(")?;
self.base.fmt(f)?;
f.write_str(")")?;
Ok(())
}
}
impl<T: ?Sized + fmt::Display> fmt::Display for RefMutexGuard<'_, '_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.base.fmt(f)
}
}
pub struct RefMutex<'mutex, T: ?Sized> {
base: Mutex<&'mutex T>,
phantom: PhantomData<&'mutex T>,
}
unsafe impl<'mutex, T: ?Sized + Sync> Sync for RefMutex<'mutex, T> {}
unsafe impl<'mutex, T: ?Sized> Send for RefMutex<'mutex, T> { }
#[cfg(test)]
mod tests2 {
use crate::RefMutex;
#[test]
fn test_sync_guard() {
#[derive(Debug)]
struct NotSend {}
impl !Send for NotSend {}
let mutex = RefMutex::new(&NotSend{}); let _: &dyn Sync = &mutex;
let _: &dyn Send = &mutex;
}
}
impl<'mutex, T: ?Sized + fmt::Debug> RefMutex<'mutex, T> {
fn from_mutex(mutex: Mutex<&'mutex T>) -> Self {
Self { base: mutex, phantom: PhantomData }
}
pub fn move_mutex(r: Arc<Mutex<&'mutex T>>) -> Arc<Self> {
let mutex = Arc::try_unwrap(r).unwrap();
Arc::new(Self::from_mutex(mutex))
}
pub fn new(t: &'mutex T) -> Self {
Self::from_mutex(Mutex::new(t))
}
}
impl<'mutex, T: ?Sized> RefMutex<'mutex, T> {
pub fn lock(&self) -> LockResult<RefMutexGuard<'_, 'mutex, T>> {
RefMutexGuard::from_lock_result(self.base.lock())
}
pub fn try_lock(&self) -> TryLockResult<RefMutexGuard<'_, 'mutex, T>>
{
RefMutexGuard::from_try_lock_result(self.base.try_lock())
}
pub fn unlock(guard: RefMutexGuard<'_, '_, T>) {
Mutex::unlock(guard.base)
}
#[inline]
pub fn is_poisoned(&self) -> bool {
self.base.is_poisoned()
}
pub fn into_inner(self) -> LockResult<&'mutex T>
{
self.base.into_inner()
}
pub fn get_mut(&mut self) -> LockResult<&'mutex T> {
match self.base.get_mut() {
Ok(r) => Ok(*r),
Err(err) => Err(PoisonError::new(*err.into_inner())),
}
}
}
impl<'mutex, T: ?Sized + fmt::Debug> From<Mutex<&'mutex T>> for RefMutex<'mutex, T> {
fn from(mutex: Mutex<&'mutex T>) -> Self {
Self::from_mutex(mutex)
}
}
impl<'mutex, T: ?Sized + fmt::Debug> fmt::Debug for RefMutex<'mutex, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut d = f.debug_struct("RefMutex");
match self.try_lock() {
Ok(guard) => {
d.field("data", &&*guard.base);
}
Err(TryLockError::Poisoned(err)) => {
d.field("data", &&**err.get_ref());
}
Err(TryLockError::WouldBlock) => {
struct LockedPlaceholder;
impl fmt::Debug for LockedPlaceholder {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("<locked>")
}
}
d.field("data", &LockedPlaceholder);
}
}
d.field("poisoned", &self.is_poisoned());
d.finish_non_exhaustive()
}
}