TL;DR: Has anybody figured out a nice pattern for having async object methods that need &mut self
?
I'd like to do something like the following:
struct Foo { ... }
impl Foo {
async fn bar(&mut self, ...) -> Result<...> { ... }
async fn baz(&mut self, ...) -> Result<...> { ... }
pub async fn run(self) {
...
// Note that I don't even need multi-threaded parallelism,
// running all of Foo's futures on the same thread is fine.
while let Some(event) = receive_event().await {
match event {
Event::Bar(args) => task::spawn_local(self.bar(args)),
Event::Baz(args) => task::spawn_local(self.baz(args)),
}
}
...
}
}
Obviously, that isn't going to fly as written above, because the very first future will have borrowed self
mutably (and also because spawn wants a 'static future).
The only thing that comes to mind is moving all mutable state into another struct, then writing code like:
async fn bar(self: Rc<Foo>) {
let state = self.mutable_state.borrow_mut();
... // mutate state
drop(state)
nested_async_call_1().await?;
let state = self.mutable_state.borrow_mut();
... // mutate state some more
drop(state)
nested_async_call_2().await?;
... // and so on
}
The above seems... not very elegant and boilerplate-y. I am wondering if anyone has figured a better was of writing this sort of code?
Perhaps there's a some clever crate out there, that can move all that borrow_mut()
business outside of the async method's body?