error: lifetime may not live long enough
--> src/main.rs:48:27
|
48 | foo.transaction(|foo| async move {
| ______________________----_^
| | | |
| | | return type of closure `impl Future` contains a lifetime `'2`
| | has type `&'1 mut Foo`
49 | | Ok(println!("{:?}", foo))
50 | | }).await
| |_____^ returning this value requires that `'1` must outlive `'2`
Here's the constraints.
All of the Connection::xx_transaction methods need &mut self as an argument.
I want to solve this within the Connection trait and its usage.
Don't want to define extra traits/structs if possible.
I suspect the problem is that |foo| given in the callback is deliberately limited to be valid only immediately within that closure and it's not allowed to be "smuggled" outside of it via returned future. There is no lifetime connecting FnOnce(&mut Self) borrow with the lifetime of the returned R future, so the R future is not allowed to be related to the Self reference in any way.
async move doesn't do anything to references. It can only move owned values, but you can't own data behind a reference.
Another problem is that lifetimes of &mut references are invariant (i.e. completely inflexible and can't be extended or shortened, except reborrow sometimes), so if you put &'a mut the borrow checker is likely to be overly pedantic about it.
Maybe you can you use F: for<'a> FnOnce(&'a Self) -> Pin<Box<dyn Future<yadayada> + 'a>>?
You're going to need for<'a> syntax to create a lifetime just for the function call, and not put anything on the struct/trait, because that would tie the single call to lifetime of the whole connection. But AFAIK for<'a> won't let you to put the same lifetime on -> R (it's a limitation of the syntax), that's why you're going to need to box the future.