use ::std::ops::{Deref, DerefMut};
pub trait MutexFamily {
type Mutex<T: Send + 'static>: Mutex<T>;
fn new<T: Send + 'static>(val: T) -> Self::Mutex<T>;
}
pub trait Mutex<T>: Send + Sync + 'static {
type Guard<'a>: Guard<T>
where
Self: 'a,
T: 'a;
fn lock(&self) -> Self::Guard<'_>;
}
pub trait Guard<T>: Deref<Target = T> + DerefMut {}
pub type MutexGuardType<'a, M, T> = <<M as MutexFamily>::Mutex<T> as Mutex<T>>::Guard<'a>;
#[cfg(feature = "parking_lot")]
pub use self::parking_lot::ParkingLotMutex;
pub use self::std::StdMutex;
mod std {
use super::{Guard, Mutex, MutexFamily};
pub struct StdMutex;
impl MutexFamily for StdMutex {
type Mutex<T: Send + 'static> = std::sync::Mutex<T>;
#[inline]
fn new<T: Send + 'static>(val: T) -> Self::Mutex<T> {
std::sync::Mutex::new(val)
}
}
impl<T: Send + 'static> Mutex<T> for std::sync::Mutex<T> {
type Guard<'a> = std::sync::MutexGuard<'a, T>
where
T: 'a;
#[inline]
fn lock(&self) -> Self::Guard<'_> {
self.lock().unwrap()
}
}
impl<'a, T: 'a> Guard<T> for std::sync::MutexGuard<'a, T> {}
}
#[cfg(feature = "parking_lot")]
mod parking_lot {
use super::{Guard, Mutex, MutexFamily};
pub struct ParkingLotMutex;
impl MutexFamily for ParkingLotMutex {
type Mutex<T: Send + 'static> = parking_lot::Mutex<T>;
#[inline]
fn new<T: Send + 'static>(val: T) -> Self::Mutex<T> {
parking_lot::Mutex::new(val)
}
}
impl<T: Send + 'static> Mutex<T> for parking_lot::Mutex<T> {
type Guard<'a> = parking_lot::MutexGuard<'a, T>
where
T: 'a;
#[inline]
fn lock(&self) -> Self::Guard<'_> {
self.lock()
}
}
impl<'a, T: 'a> Guard<T> for parking_lot::MutexGuard<'a, T> {}
}
#[cfg(test)]
mod tests {
use std::sync::Arc;
#[cfg(feature = "parking_lot")]
use crate::sync::mutex::ParkingLotMutex;
use crate::sync::mutex::{Mutex, MutexFamily, StdMutex};
struct Data {
a: usize,
}
#[test]
fn mutex() {
fn generic<M: MutexFamily>() {
let data = Arc::new(M::new(Data { a: 0 }));
{
let data = Arc::clone(&data);
std::thread::spawn(move || {
let mut guard = data.lock();
guard.a += 1;
})
.join()
.unwrap();
}
let mut guard = data.lock();
guard.a += 1;
assert_eq!(guard.a, 2);
}
generic::<StdMutex>();
#[cfg(feature = "parking_lot")]
generic::<ParkingLotMutex>();
}
}