#![cfg_attr(not(test), no_std)]
pub mod lock;
pub mod relation;
pub mod wrap;
use core::marker::PhantomData;
use core::ops::Deref;
use crate::lock::{LockFor, RwLockFor, UnlockedAccess};
use crate::relation::LockBefore;
pub struct Locked<T, L>(T, PhantomData<L>);
pub struct Unlocked;
impl<'a, T> Locked<&'a T, Unlocked> {
pub fn new(t: &'a T) -> Self {
Self::new_with_deref(t)
}
}
impl<T> Locked<T, Unlocked>
where
T: Deref,
T::Target: Sized,
{
pub fn new_with_deref(t: T) -> Self {
Self::new_locked_with_deref(t)
}
}
impl<'a, T, L> Locked<&'a T, L> {
pub fn new_locked(t: &'a T) -> Locked<&'a T, L> {
Self::new_locked_with_deref(t)
}
pub fn unlocked_access<M>(&self) -> T::Guard<'a>
where
T: UnlockedAccess<M>,
{
let Self(t, PhantomData) = self;
T::access(t)
}
pub fn unlocked_access_with<M, X>(&self, f: impl FnOnce(&'a T) -> &'a X) -> X::Guard<'a>
where
X: UnlockedAccess<M>,
{
let Self(t, PhantomData) = self;
X::access(f(t))
}
}
impl<T, L> Locked<T, L>
where
T: Deref,
T::Target: Sized,
{
pub fn new_locked_with_deref(t: T) -> Locked<T, L> {
Self(t, PhantomData)
}
pub fn lock<M>(&mut self) -> <T::Target as LockFor<M>>::Guard<'_>
where
T::Target: LockFor<M>,
L: LockBefore<M>,
{
self.lock_with::<M, _>(|t| t)
}
pub fn lock_and<M>(&mut self) -> (<T::Target as LockFor<M>>::Guard<'_>, Locked<&T::Target, M>)
where
T::Target: LockFor<M>,
L: LockBefore<M>,
{
self.lock_with_and::<M, _>(|t| t)
}
pub fn lock_with<M, X>(&mut self, f: impl FnOnce(&T::Target) -> &X) -> X::Guard<'_>
where
X: LockFor<M>,
L: LockBefore<M>,
{
let (data, _): (_, Locked<&T::Target, M>) = self.lock_with_and::<M, _>(f);
data
}
pub fn lock_with_and<M, X>(
&mut self,
f: impl FnOnce(&T::Target) -> &X,
) -> (X::Guard<'_>, Locked<&T::Target, M>)
where
X: LockFor<M>,
L: LockBefore<M>,
{
let Self(t, PhantomData) = self;
let t = Deref::deref(t);
let data = X::lock(f(t));
(data, Locked(t, PhantomData))
}
pub fn read_lock<M>(&mut self) -> <T::Target as RwLockFor<M>>::ReadGuard<'_>
where
T::Target: RwLockFor<M>,
L: LockBefore<M>,
{
self.read_lock_with::<M, _>(|t| t)
}
pub fn read_lock_and<M>(
&mut self,
) -> (<T::Target as RwLockFor<M>>::ReadGuard<'_>, Locked<&T::Target, M>)
where
T::Target: RwLockFor<M>,
L: LockBefore<M>,
{
self.read_lock_with_and::<M, _>(|t| t)
}
pub fn read_lock_with<M, X>(&mut self, f: impl FnOnce(&T::Target) -> &X) -> X::ReadGuard<'_>
where
X: RwLockFor<M>,
L: LockBefore<M>,
{
let (data, _): (_, Locked<&T::Target, M>) = self.read_lock_with_and::<M, _>(f);
data
}
pub fn read_lock_with_and<M, X>(
&mut self,
f: impl FnOnce(&T::Target) -> &X,
) -> (X::ReadGuard<'_>, Locked<&T::Target, M>)
where
X: RwLockFor<M>,
L: LockBefore<M>,
{
let Self(t, PhantomData) = self;
let t = Deref::deref(t);
let data = X::read_lock(f(t));
(data, Locked(t, PhantomData))
}
pub fn write_lock<M>(&mut self) -> <T::Target as RwLockFor<M>>::WriteGuard<'_>
where
T::Target: RwLockFor<M>,
L: LockBefore<M>,
{
self.write_lock_with::<M, _>(|t| t)
}
pub fn write_lock_and<M>(
&mut self,
) -> (<T::Target as RwLockFor<M>>::WriteGuard<'_>, Locked<&T::Target, M>)
where
T::Target: RwLockFor<M>,
L: LockBefore<M>,
{
self.write_lock_with_and::<M, _>(|t| t)
}
pub fn write_lock_with<M, X>(&mut self, f: impl FnOnce(&T::Target) -> &X) -> X::WriteGuard<'_>
where
X: RwLockFor<M>,
L: LockBefore<M>,
{
let (data, _): (_, Locked<&T::Target, M>) = self.write_lock_with_and::<M, _>(f);
data
}
pub fn write_lock_with_and<M, X>(
&mut self,
f: impl FnOnce(&T::Target) -> &X,
) -> (X::WriteGuard<'_>, Locked<&T::Target, M>)
where
X: RwLockFor<M>,
L: LockBefore<M>,
{
let Self(t, PhantomData) = self;
let t = Deref::deref(t);
let data = X::write_lock(f(t));
(data, Locked(t, PhantomData))
}
pub fn as_owned(&mut self) -> Locked<&T::Target, L> {
self.cast_with(|s| s)
}
pub fn cast<R>(&mut self) -> Locked<&R, L>
where
T::Target: AsRef<R>,
{
self.cast_with(AsRef::as_ref)
}
pub fn cast_with<R>(&mut self, f: impl FnOnce(&T::Target) -> &R) -> Locked<&R, L> {
let Self(t, PhantomData) = self;
Locked(f(Deref::deref(t)), PhantomData)
}
pub fn cast_locked<M>(&mut self) -> Locked<&T::Target, M>
where
L: LockBefore<M>,
{
let Self(t, _marker) = self;
Locked(Deref::deref(t), PhantomData)
}
pub fn copied(&self) -> T::Target
where
T::Target: Copy,
{
let Self(t, PhantomData) = self;
*t.deref()
}
pub fn adopt<'a, N>(
&'a mut self,
n: &'a N,
) -> Locked<OwnedTupleWrapper<&'a T::Target, &'a N>, L> {
let Self(t, PhantomData) = self;
Locked(OwnedWrapper(TupleWrapper(Deref::deref(t), n)), PhantomData)
}
pub fn cast_left<'a, X, A: Deref + 'a, B: Deref + 'a, F: FnOnce(&A::Target) -> &X>(
&'a mut self,
f: F,
) -> Locked<OwnedTupleWrapper<&'a X, &'a B::Target>, L>
where
T: Deref<Target = TupleWrapper<A, B>>,
{
let Self(t, PhantomData) = self;
Locked(Deref::deref(t).cast_left(f), PhantomData)
}
pub fn cast_right<'a, X, A: Deref + 'a, B: Deref + 'a, F: FnOnce(&B::Target) -> &X>(
&'a mut self,
f: F,
) -> Locked<OwnedTupleWrapper<&'a A::Target, &'a X>, L>
where
T: Deref<Target = TupleWrapper<A, B>>,
{
let Self(t, PhantomData) = self;
Locked(Deref::deref(t).cast_right(f), PhantomData)
}
pub fn replace<'a, N>(&'a mut self, n: &'a N) -> Locked<&'a N, L> {
Locked::new_locked(n)
}
}
pub struct OwnedWrapper<T>(T);
impl<T> Deref for OwnedWrapper<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
let Self(t) = self;
t
}
}
pub type OwnedTupleWrapper<A, B> = OwnedWrapper<TupleWrapper<A, B>>;
pub struct TupleWrapper<A, B>(A, B);
impl<A, B> TupleWrapper<A, B>
where
A: Deref,
B: Deref,
{
pub fn left(&self) -> &A::Target {
let Self(a, _) = self;
a.deref()
}
pub fn right(&self) -> &B::Target {
let Self(_, b) = self;
b.deref()
}
pub fn both(&self) -> (&A::Target, &B::Target) {
let Self(a, b) = self;
(a.deref(), b.deref())
}
pub fn cast_left<X, F: FnOnce(&A::Target) -> &X>(
&self,
f: F,
) -> OwnedTupleWrapper<&X, &B::Target> {
let Self(a, b) = self;
OwnedWrapper(TupleWrapper(f(Deref::deref(a)), Deref::deref(b)))
}
pub fn cast_right<X, F: FnOnce(&B::Target) -> &X>(
&self,
f: F,
) -> OwnedTupleWrapper<&A::Target, &X> {
let Self(a, b) = self;
OwnedWrapper(TupleWrapper(Deref::deref(a), f(Deref::deref(b))))
}
}
#[cfg(test)]
mod test {
use std::ops::Deref;
use std::sync::{Mutex, MutexGuard};
mod lock_levels {
extern crate self as lock_tree;
use crate::relation::LockAfter;
use crate::{impl_lock_after, Unlocked};
pub enum A {}
pub enum B {}
pub enum C {}
pub enum D {}
pub enum E {}
impl LockAfter<Unlocked> for A {}
impl_lock_after!(A => B);
impl_lock_after!(B => C);
impl_lock_after!(B => D);
impl_lock_after!(D => E);
}
use crate::lock::{LockFor, UnlockedAccess};
use crate::Locked;
use lock_levels::{A, B, C, D, E};
#[derive(Default)]
struct Data {
a: Mutex<u8>,
b: Mutex<u16>,
c: Mutex<u64>,
d: Mutex<u128>,
e: Vec<Mutex<usize>>,
u: usize,
}
impl LockFor<A> for Data {
type Data = u8;
type Guard<'l> = MutexGuard<'l, u8>;
fn lock(&self) -> Self::Guard<'_> {
self.a.lock().unwrap()
}
}
impl LockFor<B> for Data {
type Data = u16;
type Guard<'l> = MutexGuard<'l, u16>;
fn lock(&self) -> Self::Guard<'_> {
self.b.lock().unwrap()
}
}
impl LockFor<C> for Data {
type Data = u64;
type Guard<'l> = MutexGuard<'l, u64>;
fn lock(&self) -> Self::Guard<'_> {
self.c.lock().unwrap()
}
}
impl LockFor<D> for Data {
type Data = u128;
type Guard<'l> = MutexGuard<'l, u128>;
fn lock(&self) -> Self::Guard<'_> {
self.d.lock().unwrap()
}
}
impl LockFor<E> for Mutex<usize> {
type Data = usize;
type Guard<'l> = MutexGuard<'l, usize>;
fn lock(&self) -> Self::Guard<'_> {
self.lock().unwrap()
}
}
enum UnlockedUsize {}
enum UnlockedELen {}
impl UnlockedAccess<UnlockedUsize> for Data {
type Data = usize;
type Guard<'l>
= &'l usize
where
Self: 'l;
fn access(&self) -> Self::Guard<'_> {
&self.u
}
}
struct DerefWrapper<T>(T);
impl<T> Deref for DerefWrapper<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl UnlockedAccess<UnlockedELen> for Data {
type Data = usize;
type Guard<'l> = DerefWrapper<usize>;
fn access(&self) -> Self::Guard<'_> {
DerefWrapper(self.e.len())
}
}
#[test]
fn lock_a_then_c() {
let data = Data::default();
let mut w = Locked::new(&data);
let (_a, mut wa) = w.lock_and::<A>();
let (_c, _wc) = wa.lock_and::<C>();
}
#[test]
fn unlocked_access_does_not_prevent_locking() {
let data = Data { a: Mutex::new(15), u: 34, ..Data::default() };
let mut locked = Locked::new(&data);
let u = locked.unlocked_access::<UnlockedUsize>();
let a = locked.lock::<A>();
assert_eq!(u, &34);
assert_eq!(&*a, &15);
}
#[test]
fn unlocked_access_with_does_not_prevent_locking() {
let data = Data { a: Mutex::new(15), u: 34, ..Data::default() };
let data = (data,);
let mut locked = Locked::new(&data);
let u = locked.unlocked_access_with::<UnlockedUsize, _>(|(data,)| data);
let a = locked.lock_with::<A, _>(|(data,)| data);
assert_eq!(u, &34);
assert_eq!(&*a, &15);
}
#[test]
fn cast_with_for_indexing_into_sub_field_state() {
let data = Data { e: (0..10).map(Mutex::new).collect(), ..Data::default() };
let mut locked = Locked::new(&data);
for i in 0..*locked.unlocked_access::<UnlockedELen>() {
let mut locked_element = locked.cast_with(|data| &data.e[i]);
let mut item = locked_element.lock::<E>();
assert_eq!(*item, i);
*item = i + 1;
}
}
#[test]
fn adopt() {
let data_left = Data { a: Mutex::new(55), b: Mutex::new(11), ..Data::default() };
let mut locked = Locked::new(&data_left);
let data_right = Data { a: Mutex::new(66), b: Mutex::new(22), ..Data::default() };
let mut locked = locked.adopt(&data_right);
let (guard_left, mut locked) = locked.lock_with_and::<A, Data>(|t| t.left());
let guard_right = locked.lock_with::<B, Data>(|t| t.right());
assert_eq!(*guard_left, 55);
assert_eq!(*guard_right, 22);
}
}