Given that in the example code at hand one could just as well (with essentially equivalent effect) do the task::spawn call at the end of the that_must_return_before_the_task_runs function[1], I think you need to give us more context as to why you want to achieve what you’re describing here.
which, given the minimal/minimized(?) nature of the code at hand is already what is happening anyways, so the whole thing that’s done here becomes a bit pointless… ↩︎
Maybe it’s about making sure the code runs, too, in a panicking case? Well, I suppose it should be possible (and slightly less convoluted) to use a normal non-async defer approach, and execute the task::spawn call itself only in the deferred code?
I'm writing a zbus server application and my method actually being wrapped and it's return value is sent back to the client. I need to make sure the return value has been sent before my sub-task sends a subsequent signal to the client.
So my example looks more like this
async fn handle_notification(&mut self) {
self.current_id = self.current_id+1;
let (drop_guard, has_returned) = DropGuard::create();
task::spawn(async move {
has_returned.await;
// now we can assume that the client has received my response
// and I can send them messages that refer to `current_id`
});
Ok(self.current_id)
}
I still don’t see how that code is particularly sensible. The task::spawn was already the last thing that happens in handle_notification before the destructors of local variables are run. Making the spawned task wait for drop_guard to be dropped is going to make it wait essentially no longer at all, since dropping drop_guard is the very next thing that happens after the task::spawn call.
Well, even once the method returned, the value is not yet sent. Really, the caller must somehow indicate the action that needs to happen before the sub-task is supposed to start.
So… maybe a callback works?
// feel free to fill in the gaps
// e.g. whether or not the callback should get `Result`, or just not called
// in case of error; and whether or not the callback should be able to
// do some `async` operations
async fn handle_notification(&mut self, callback: impl FnOnce(…)) {
self.current_id = self.current_id+1;
callback(self.current_id) // e.g. sending the id to the client (or
// anything else that should happen *before* the below task
// is started it expected to be done in the callback provided by the caller
// now we can assume that the client has received my response
// and I can send them messages that refer to `current_id`
task::spawn(async move {
…
});
}
Alternatively, instead of accepting a callback, handle_notification could also return both the id and some kind of handle to start the sub-task after the id was taken care of (and e.g. sent off).