use core::marker::PhantomData;
use core::ops::{Deref, DerefMut};
use loom::cell::{ConstPtr, MutPtr, UnsafeCell};
pub unsafe trait Guard: Sized {
type Target: ?Sized;
fn get(&self) -> &UnsafeCell<Self::Target>;
fn get_ref(&self) -> GuardDeref<'_, Self> {
GuardDeref::new(self)
}
fn get_mut(&mut self) -> GuardDerefMut<'_, Self> {
GuardDerefMut::new(self)
}
}
pub struct GuardDeref<'a, G: Guard> {
ptr: ConstPtr<G::Target>,
marker: PhantomData<(&'a G::Target, &'a G)>,
}
impl<G: Guard> GuardDeref<'_, G> {
fn new(guard: &G) -> Self {
let ptr = guard.get().get();
Self { ptr, marker: PhantomData }
}
}
impl<G: Guard> Deref for GuardDeref<'_, G> {
type Target = G::Target;
fn deref(&self) -> &Self::Target {
unsafe { self.ptr.deref() }
}
}
pub struct GuardDerefMut<'a, G: Guard> {
ptr: MutPtr<G::Target>,
marker: PhantomData<(&'a mut G::Target, &'a mut G)>,
}
impl<G: Guard> GuardDerefMut<'_, G> {
#[allow(clippy::needless_pass_by_ref_mut)]
fn new(guard: &mut G) -> Self {
let ptr = guard.get().get_mut();
Self { ptr, marker: PhantomData }
}
}
impl<G: Guard> Deref for GuardDerefMut<'_, G> {
type Target = G::Target;
fn deref(&self) -> &Self::Target {
unsafe { self.ptr.deref() }
}
}
impl<G: Guard> DerefMut for GuardDerefMut<'_, G> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { self.ptr.deref() }
}
}
pub mod models {
use core::array;
use loom::sync::Arc;
use loom::{model, thread};
use crate::test::{AsDeref, AsDerefMut, LockThen};
type Int = usize;
const LOCKS: Int = 3;
fn inc<L: LockThen<Target = Int>>(lock: &Arc<L>) {
lock.lock_then(|mut data| *data.as_deref_mut() += 1);
}
fn get<L: LockThen<Target = Int>>(lock: &Arc<L>) -> Int {
lock.lock_then(|data| *data.as_deref())
}
pub fn lock_join<L: LockThen<Target = Int> + 'static>() {
model(|| {
const RUNS: Int = LOCKS;
let lock = Arc::new(L::new(0));
let handles: [_; RUNS] = array::from_fn(|_| {
let lock = Arc::clone(&lock);
thread::spawn(move || inc(&lock))
});
for handle in handles {
handle.join().unwrap();
}
let value = get(&lock);
assert_eq!(RUNS, value);
});
}
}