pub async fn try_finally<B, F, BFut, FFut, Out, Err>(
body: B,
finally: F,
) -> Result<Out, Err>
Expand description
An approximation of a “try/finally” block for async Result-returning code.
This function can be used to simulate a “try/finally” block that may be
familiar from languages with an exception system. The provided body
closure
will be called and awaited and its result returned. The provided finally
closure
will be called and awaited at the completion of the body, regardless of whether
the body returned successfully, returned an error, or panicked.
This pattern can be useful for running cleanup code, for example in cleaning up
after running a test. Rust code would typically use a scope guard with a Drop
impl
for doing such cleanup work, but that doesn’t handle code that needs to be async.
§Example
use cobalt_async::try_finally;
use anyhow::Ok;
let mut cleaned_up = false;
let res = try_finally(
|| async {
Ok("the body ran successfully")
},
|| async {
cleaned_up = true;
Ok(())
}
).await.unwrap();
assert_eq!(res, "the body ran successfully");
assert!(cleaned_up);
If the body closure references state that is not UnwindSafe
, you may need
to manually annotate it with AssertUnwindSafe
, and ensure that the finally
closure does not manipulate that state in a way that would violate unwind safety.
use cobalt_async::try_finally;
use anyhow::Ok;
use std::cell::RefCell;
let mut cleaned_up = false;
let mut data = RefCell::new(0);
// If the body code panics, we promise not to look at `data` in the finally code.
let data = std::panic::AssertUnwindSafe(data);
let res = try_finally(
|| async {
Ok(data.replace(42))
},
|| async {
cleaned_up = true;
Ok(())
}
).await.unwrap();
assert_eq!(res, 0);
assert_eq!(data.take(), 42);
assert!(cleaned_up);
§Notes
-
As with
Drop
, running thefinally
closure on panic is not guaranteed. In particular it will not be run when the panic mode is set to abort. -
Panics in the
finally
code will not be caught, and may potentially mask panics from thebody
code. -
Errors returned by the
finally
code will be returned to the caller, potentially masking errors returned by thebody
code.