Trait abstracting over Mutex and RefCell?


#1

Hi all,

Is there an existing trait that abstracts over RefCell and Mutex - ie, something provides guarded inner mutability?

I’ve tried defining one, but I can’t get it to compile - I’m having trouble getting the type and lifetime parameters for the associated types right.

use std::cell::{RefCell, Ref, RefMut};
use std::sync::{Mutex, MutexGuard};
use std::ops::{Deref, DerefMut};

pub trait Guarded<T> {
    type Guard: Deref;
    type MutGuard: DerefMut;

    fn borrow<'a>(&'a Self) -> Self::Guard<'a, T>;
    fn borrow_mut<'a>(&'a Self) -> Self::MutGuard<'a, T>;
}

impl<T> Guarded<T> for RefCell<T> {
    type Guard = Ref<'a, T>;
    type MutGuard = RefMut<'a, T>;

    fn borrow<'a>(&'a self) -> Self::Guard<'a, T> { self.borrow() }
    fn borrow_mut<'a>(&'a self) -> Self::MutGuard<'a, T> { self.borrow_mut() }
}

impl<T> Guarded<T> for Mutex<T> {
    type Guard = MutexGuard;
    type MutGuard = MutexGuard;

    fn borrow<'a>(&'a self) -> Self::Guard<'a, T> { self.lock().unwrap() }
    fn borrow_mut<'a>(&'a self) -> Self::MutGuard<'a, T> { self.lock.unwrap() }
}

Does this already exist? Is it possible? (Most of the possible things already exist, so is there some feature missing from the type system which makes this not possible?)

Thanks, J


#2

It’s totally doable but I don’t see why:

use std::cell::{RefCell, Ref, RefMut};
use std::sync::{Mutex, MutexGuard};
use std::ops::{Deref, DerefMut};

pub trait Guarded<'a, T: ?Sized + 'a> {
    type Guard: Deref;
    type MutGuard: DerefMut;

    fn borrow(&'a self) -> Self::Guard;
    fn borrow_mut(&'a mut self) -> Self::MutGuard;
}

impl<'a, T: ?Sized + 'a> Guarded<'a, T> for RefCell<T> {
    type Guard = Ref<'a, T>;
    type MutGuard = RefMut<'a, T>;

    fn borrow(&'a self) -> Self::Guard { RefCell::borrow(self) }
    fn borrow_mut(&'a mut self) -> Self::MutGuard { RefCell::borrow_mut(self) }
}

impl<'a, T: ?Sized + 'a> Guarded<'a, T> for Mutex<T> {
    type Guard = MutexGuard<'a, T>;
    type MutGuard = MutexGuard<'a, T>;

    fn borrow(&'a self) -> Self::Guard { self.lock().unwrap() }
    fn borrow_mut(&'a mut self) -> Self::MutGuard { self.lock().unwrap() }
}



#3

OK, I was trying to avoid making 'a a parameter for the whole trait in favour of something like:

type for <'a> Guard<'a, T>: Deref<Target=T>; // hypothetical syntax
...
fn borrow<'a>(&'a self) -> Guard<'a, T>;

since the lifetime does’t seem like an overall property of the trait but just individual invocations of its methods - but TBH I don’t really understand what the semantics of the former would be anyway.

And why? I’m trying to write some concurrent code which works with both threads or coroutines, so I’m experimenting with abstracting over both with traits.


#4

I believe that requires higher kinded types.


#5

There’s a good explanation here: Lifetimes on Associated Types