#![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)]
use std::cell::UnsafeCell;
use std::fmt;
use std::mem;
use std::ops::{Deref, DerefMut};
use std::sync::Arc;
use async_mutex::{Mutex, MutexGuard};
pub struct Lock<T>(Arc<Inner<T>>);
unsafe impl<T: Send> Send for Lock<T> {}
unsafe impl<T: Send> Sync for Lock<T> {}
impl<T> Clone for Lock<T> {
fn clone(&self) -> Lock<T> {
Lock(self.0.clone())
}
}
struct Inner<T> {
mutex: Mutex<()>,
data: UnsafeCell<T>,
}
unsafe impl<T: Send> Send for Inner<T> {}
unsafe impl<T: Send> Sync for Inner<T> {}
impl<T> Lock<T> {
pub fn new(data: T) -> Lock<T> {
Lock(Arc::new(Inner {
mutex: Mutex::new(()),
data: UnsafeCell::new(data),
}))
}
#[inline]
pub async fn lock(&self) -> LockGuard<T> {
LockGuard::new(self.clone(), self.0.mutex.lock().await)
}
#[inline]
pub fn try_lock(&self) -> Option<LockGuard<T>> {
self.0
.mutex
.try_lock()
.map(|guard| LockGuard::new(self.clone(), guard))
}
}
impl<T: fmt::Debug> fmt::Debug for Lock<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
struct Locked;
impl fmt::Debug for Locked {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("<locked>")
}
}
match self.try_lock() {
None => f.debug_struct("Lock").field("data", &Locked).finish(),
Some(guard) => f.debug_struct("Lock").field("data", &&*guard).finish(),
}
}
}
impl<T> From<T> for Lock<T> {
fn from(val: T) -> Lock<T> {
Lock::new(val)
}
}
impl<T: Default> Default for Lock<T> {
fn default() -> Lock<T> {
Lock::new(Default::default())
}
}
pub struct LockGuard<T>(Lock<T>, MutexGuard<'static, ()>);
unsafe impl<T: Send> Send for LockGuard<T> {}
unsafe impl<T: Sync> Sync for LockGuard<T> {}
impl<T> LockGuard<T> {
fn new(lock: Lock<T>, inner: MutexGuard<'_, ()>) -> LockGuard<T> {
let inner = unsafe { mem::transmute::<MutexGuard<'_, ()>, MutexGuard<'static, ()>>(inner) };
LockGuard(lock, inner)
}
pub fn source(guard: &LockGuard<T>) -> &Lock<T> {
&guard.0
}
}
impl<T: fmt::Debug> fmt::Debug for LockGuard<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&**self, f)
}
}
impl<T: fmt::Display> fmt::Display for LockGuard<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
(**self).fmt(f)
}
}
impl<T> Deref for LockGuard<T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { &*(self.0).0.data.get() }
}
}
impl<T> DerefMut for LockGuard<T> {
fn deref_mut(&mut self) -> &mut T {
unsafe { &mut *(self.0).0.data.get() }
}
}
struct CallOnDrop<F: Fn()>(F);
impl<F: Fn()> Drop for CallOnDrop<F> {
fn drop(&mut self) {
(self.0)();
}
}