The way this can currently be made working is by introducing a new trait. Adapting one that I have previously presented in a different thread:
use std::future::Future;
trait AsyncSingleArgFnMut<Arg>: FnMut(Arg) -> <Self as AsyncSingleArgFnMut<Arg>>::Fut {
type Fut: Future<Output=<Self as AsyncSingleArgFnMut<Arg>>::Output>;
type Output;
}
impl<Arg, F, Fut> AsyncSingleArgFnMut<Arg> for F
where
F: FnMut(Arg) -> Fut,
Fut: Future,
{
type Fut = Fut;
type Output = Fut::Output;
}
struct Foo {}
impl Foo {
// Operation that may fail and should be retried.
async fn operation(&mut self) -> bool {
unimplemented!()
}
// Directly retry the operation in a loop.
async fn direct(&mut self) {
loop {
if self.operation().await {
return;
}
}
}
// Retry the operation via a retry_loop helper function.
async fn indirect_1(&mut self) {
self.retry_loop_1(Foo::operation).await
}
// I have no idea why this still doesn’t work
async fn indirect_2(&mut self) {
//self.retry_loop_1(|this: &mut Self| this.operation()).await
}
async fn retry_loop_1<F>(&mut self, mut f: F)
where
for<'a> F: AsyncSingleArgFnMut<&'a mut Self, Output=bool>
{
loop {
if f(self).await {
return;
}
}
}
}
As noted above, it is a bit puzzling to me why indirect_2
still doesn’t work and I have no idea how to fix it.
Edit: Here’s the adaptation to your Bar<'a>
example (click to expand)
struct Bar<'a> {
data: &'a str,
}
impl<'a> Bar<'a> {
async fn indirect_4(&mut self) {
self.retry_loop_4(Self::operation).await
}
async fn retry_loop_4<F>(&mut self, mut f: F)
where
for<'b> F: AsyncSingleArgFnMut<&'b mut Self, Output=bool>,
{
loop {
if f(self).await {
return;
}
}
}
async fn operation(&mut self) -> bool {
unimplemented!()
}
}