use std::future::Future;
use std::ops::{Deref, DerefMut};
pub trait AsyncMutexGuard<'mutex, T: ?Sized + 'mutex>: Deref<Target = T> + DerefMut {
type Mutex: AsyncMutex<T> + ?Sized;
fn mutex(&self) -> &'mutex Self::Mutex;
unsafe fn leak(self) -> &'mutex Self::Mutex;
}
pub trait AsyncMutex<T: ?Sized> {
type Guard<'mutex>: AsyncMutexGuard<'mutex, T, Mutex = Self>
where
Self: 'mutex,
T: 'mutex;
fn is_locked(&self) -> bool;
fn lock<'mutex>(&'mutex self) -> impl Future<Output = Self::Guard<'mutex>>
where
T: 'mutex;
fn try_lock(&self) -> Option<Self::Guard<'_>>;
fn get_mut(&mut self) -> &mut T;
unsafe fn unlock(&self);
unsafe fn get_locked(&self) -> Self::Guard<'_>;
}
#[cfg(test)]
mod tests {
use super::*;
use crate as orengine;
use crate::test::{test_local, test_shared};
struct NonSend {
value: i32,
no_send_marker: std::marker::PhantomData<*const ()>,
}
#[test_local]
fn test_local_async_mutex() {
let mutex = crate::sync::LocalMutex::new(NonSend {
value: 0,
no_send_marker: std::marker::PhantomData,
});
let mut guard = mutex.lock().await;
assert_eq!(guard.value, 0);
assert!(mutex.is_locked());
assert!(mutex.try_lock().is_none());
guard.value += 1;
drop(guard);
let mut guard = mutex.try_lock().unwrap();
assert_eq!(guard.value, 1);
assert!(mutex.is_locked());
guard.value += 1;
drop(guard);
assert!(!mutex.is_locked());
}
#[test_shared]
fn test_shared_async_mutex() {
let mutex = crate::sync::NaiveMutex::new(0);
let mut guard = mutex.lock().await;
assert_eq!(*guard, 0);
assert!(mutex.is_locked());
assert!(mutex.try_lock().is_none());
*guard += 1;
drop(guard);
let mut guard = mutex.try_lock().unwrap();
assert_eq!(*guard, 1);
assert!(mutex.is_locked());
*guard += 1;
drop(guard);
assert!(!mutex.is_locked());
}
}