safina-sync 0.2.4

Safe structs for sharing or sending data between async tasks
Documentation
#![forbid(unsafe_code)]

use core::future::Future;
use core::ops::{Deref, DerefMut};
use core::pin::Pin;
use core::task::{Context, Poll};
use std::collections::VecDeque;
use std::sync::TryLockError;
use std::task::Waker;

/// An [RAII](https://doc.rust-lang.org/rust-by-example/scope/raii.html)
/// scoped lock of a [`Mutex`](struct.Mutex.html).
/// It automatically unlocks the mutex when dropped (falls out of scope).
///
/// You can access the data in the mutex through this guard's
/// [`Deref`](https://doc.rust-lang.org/stable/std/ops/trait.Deref.html)
/// and
/// [`DerefMut`](https://doc.rust-lang.org/stable/std/ops/trait.DerefMut.html)
/// implementations.
///
/// The struct is not
/// [`Send`](https://doc.rust-lang.org/stable/std/marker/trait.Send.html)
/// so you cannot await while holding it.
///
/// If a task panics while holding the struct, the underlying mutex becomes
/// ["poisoned"](https://doc.rust-lang.org/stable/std/sync/struct.Mutex.html#poisoning)
/// and subsequent calls to `lock` will panic.
#[allow(clippy::module_name_repetitions)]
pub struct MutexGuard<'a, T> {
    mutex: &'a Mutex<T>,
    value_guard: Option<std::sync::MutexGuard<'a, T>>,
}
impl<'a, T> MutexGuard<'a, T> {
    fn new(mutex: &'a Mutex<T>, value_guard: std::sync::MutexGuard<'a, T>) -> MutexGuard<'a, T> {
        let mut inner_guard = mutex.inner.lock().unwrap();
        assert!(!inner_guard.locked);
        inner_guard.locked = true;
        MutexGuard {
            mutex,
            value_guard: Some(value_guard),
        }
    }
}
impl<'a, T> Drop for MutexGuard<'a, T> {
    fn drop(&mut self) {
        let mut wakers = VecDeque::new();
        {
            let mut inner_guard = self.mutex.inner.lock().unwrap();
            assert!(inner_guard.locked);
            inner_guard.locked = false;
            std::mem::swap(&mut inner_guard.wakers, &mut wakers);
        }
        self.value_guard.take();
        for waker in wakers {
            waker.wake();
        }
    }
}
impl<'a, T> Deref for MutexGuard<'a, T> {
    type Target = T;
    fn deref(&self) -> &Self::Target {
        &*self.value_guard.as_ref().unwrap()
    }
}
impl<'a, T> DerefMut for MutexGuard<'a, T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut *self.value_guard.as_mut().unwrap()
    }
}

#[doc(hidden)]
pub struct LockFuture<'a, T> {
    mutex: &'a Mutex<T>,
}
impl<'a, T> Future for LockFuture<'a, T> {
    type Output = MutexGuard<'a, T>;

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        loop {
            match self.mutex.value.try_lock() {
                Ok(guard) => return Poll::Ready(MutexGuard::new(self.mutex, guard)),
                Err(TryLockError::Poisoned(e)) => panic!("{}", e),
                Err(TryLockError::WouldBlock) => {}
            }
            let mut guard = self.mutex.inner.lock().unwrap();
            if guard.locked {
                // Mutex is locked.  Add our waker and sleep.
                guard.wakers.push_back(cx.waker().clone());
                return Poll::Pending;
            }
            // Mutex is now unlocked.  Try to acquire it again.
        }
    }
}

struct Inner {
    wakers: VecDeque<Waker>,
    locked: bool,
}

/// A wrapper around
/// [`std::sync::Mutex`](https://doc.rust-lang.org/stable/std/sync/struct.Mutex.html)
/// with an async [`lock`](#method.lock) method.
pub struct Mutex<T> {
    inner: std::sync::Mutex<Inner>,
    value: std::sync::Mutex<T>,
}

impl<T> Mutex<T> {
    pub fn new(value: T) -> Mutex<T> {
        Self {
            inner: std::sync::Mutex::new(Inner {
                wakers: VecDeque::new(),
                locked: false,
            }),
            value: std::sync::Mutex::new(value),
        }
    }

    /// Acquires the mutex, sleeping the current task until it is able to do so.
    ///
    /// After this function returns, is the only task holding the lock.
    ///
    /// The returned guard is an
    /// [RAII](https://doc.rust-lang.org/rust-by-example/scope/raii.html)
    /// scoped lock.
    /// It automatically unlocks the mutex when dropped (falls out of scope).
    ///
    /// The returned guard is not
    /// [`Send`](https://doc.rust-lang.org/stable/std/marker/trait.Send.html)
    /// so you cannot `await` while holding it.
    ///
    /// If a task panics while holding the guard, the underlying mutex becomes
    /// ["poisoned"](https://doc.rust-lang.org/stable/std/sync/struct.Mutex.html#poisoning)
    /// and subsequent calls to `lock` will panic.
    pub async fn lock(&self) -> MutexGuard<'_, T> {
        LockFuture { mutex: self }.await
    }
}