Consider this code (playground):
use std::cell::{RefCell, RefMut};
use std::ops::{Deref, DerefMut};
use std::rc::{Rc, Weak};
fn main() {}
trait Upgrade {
type Strong;
fn upgrade(&self) -> Option<Self::Strong>;
}
impl<T> Upgrade for Weak<T> {
type Strong = Rc<T>;
fn upgrade(&self) -> Option<Self::Strong> {
self.upgrade()
}
}
trait CaptureAndProvideMutRef<T> {
type Reference<'a>: DerefMut<Target = T>
where
T: 'a;
fn capture<F, O>(&self) -> impl Fn(F) -> O
where
// T: 'static, // This makes it work, but also spreads downstream, which is a no-go.
F: for<'b> FnOnce(Self::Reference<'b>) -> O,
O: Default;
}
impl<W, T> CaptureAndProvideMutRef<T> for W
where
W: Clone + Upgrade,
W::Strong: Deref<Target = RefCell<T>>,
{
type Reference<'a> = RefMut<'a, T> where T: 'a;
fn capture<F, O>(&self) -> impl Fn(F) -> O
where
// T: 'static,
//F: for<'b> FnOnce(Self::Reference<'b>) -> O,
F: for<'b> FnOnce(RefMut<'b, T>) -> O, // Reduces errors from 5 to 3.
O: Default,
{
let weak = W::clone(self);
move |f| {
if let Some(strong) = weak.upgrade() {
f(strong.deref().borrow_mut())
} else {
O::default()
}
}
}
}
This generates the error error[E0311]: the parameter type `T` may not live long enough
. The compiler tells me to add the explicit lifetime bound T: 'b
, which is nonsense, because 'b
is inaccessible outside the HRTB (there are GitHub issues already mentioning this).
What are my options to work around this issue and still be able to provide the caller-defined FnOnce
closure a reference that can't last longer than the closure run, so the compiler doesn't complain about f(strong.deref().borrow_mut())
?