localq 0.0.2

No-std async primitives for `!Send` tasks.
Documentation
use core::{
    cell::{Cell, UnsafeCell},
    ops::{Deref, DerefMut},
};

use crate::waiter_queue::WaiterQueue;

/// A `!Sync` async mutex.
pub struct LocalLock<T> {
    value: UnsafeCell<T>,
    is_locked: Cell<bool>,
    waiters: WaiterQueue,
}

impl<T> LocalLock<T> {
    pub fn new(initial: T) -> Self {
        Self {
            value: UnsafeCell::new(initial),
            is_locked: Cell::new(false),
            waiters: WaiterQueue::new(),
        }
    }

    /// Attempt to immediately acquire the lock.
    ///
    /// Returns the lock guard if successful, otherwise returns None.
    #[inline]
    pub fn try_lock(&self) -> Option<LockGuard<'_, T>> {
        if !self.is_locked.get() {
            self.is_locked.set(true);
            Some(LockGuard { lock: self })
        } else {
            None
        }
    }

    /// Acquire the lock, waiting to do so if necessary.
    #[inline]
    pub async fn lock(&self) -> LockGuard<'_, T> {
        self.waiters.wait_until(|| !self.is_locked.get()).await;
        self.is_locked.set(true);
        LockGuard { lock: self }
    }
}

pub struct LockGuard<'a, T> {
    lock: &'a LocalLock<T>,
}

impl<T> Deref for LockGuard<'_, T> {
    type Target = T;

    #[inline]
    fn deref(&self) -> &Self::Target {
        unsafe { &*self.lock.value.get() }
    }
}

impl<T> DerefMut for LockGuard<'_, T> {
    #[inline]
    fn deref_mut(&mut self) -> &mut Self::Target {
        unsafe { &mut *self.lock.value.get() }
    }
}

impl<T> Drop for LockGuard<'_, T> {
    #[inline]
    fn drop(&mut self) {
        self.lock.is_locked.set(false);
        self.lock.waiters.notify(1);
    }
}