I'm having difficulties expressing my problem, so I'll try explaining using code comments below:
// So, I have this Runtime trait. It has a lot of associated types, one of them is Mutex.
// We can think Runtime trait as a way for me to generalize the side effect in my code.
// One obvious way to implement it is just using std::sync::Mutex for Mutex.
// But, I think this can be helpful if I want to do deterministic-simulation-testing (DST) by replacing
// the mutex and all other side effects so the effects are deterministic.
trait Runtime {
// I have this associated type called Mutex that should implements
// Mutex trait.
// Now, I'm stuck at how do I express that my mutex's guard is Self::Guard.
type Mutex<T>: Mutex<T>;
type Guard<'a, T: 'a>: DerefMut<Target = T>;
}
trait Mutex<T> {
type Guard<'a>: DerefMut<Target = T>
where
Self: 'a;
fn lock<'a>(&'a self) -> Self::Guard<'a>;
}
My question is on the Runtime::Mutex type. How do I express that the Mutex<T>::Guard is Self::Guard?
This bound compiles, but I’m not sure if it has exactly the semantics you need (I still don’t quite understand when for<‘a> implies ’static and when it doesn’t):
type Mutex<T>: for<'a> Mutex<T, Guard<'a>=Self::Guard<'a,T>>;
This is what I currently do. But you still need to specify the bound like this:
struct Page<'a, R: Runtime>
where
R::Mutex<()>: 'a, // We still need this
{
frame: Guard<'a, R, ()>, // But, thanks to type alias, this part is simpler.
}
Right, because the trait does not express that R::Mutex<T> outlives T. You could constrain T and Mutex<T> to be 'static if that is acceptable for your use-case, or introduce a lifetime for the Mutex. Not that the result is that much more readable...
No, it is limited. Having to be defined for all lifetimes (so that the HRTB can be satisfied) is not the same thing as being forced to live for 'static. (Whether that's a blocker for the OP or not is another question.)