| Crates.io | unwind_safe |
| lib.rs | unwind_safe |
| version | 0.1.0 |
| created_at | 2021-03-05 15:50:50.885336+00 |
| updated_at | 2021-12-31 19:48:50.153315+00 |
| description | Readable unwind-safe code thanks to a try-finally-looking builder pattern |
| homepage | https://crates.io/crates/unwind_safe |
| repository | https://github.com/danielhenrymantilla/unwind_safe.rs |
| max_upload_size | |
| id | 364395 |
| size | 26,470 |
::unwind_safelet mut body_called = false;
let mut finally_called = false;
// Let's imagine some code being run in a context where
// panics do not affect us (`panic::catch_unwind`), or some
// executor running stuff on another thread…
let _ = ::crossbeam::thread::scope(|s| drop(s.spawn(|_| {
let ft = {
::unwind_safe::with_state(())
.try_eval(|_| {
body_called = true;
if ::rand::random() {
panic!();
} else {
42
}
})
.finally(|_| { // <- The point of this crate!
finally_called = true;
})
};
// This is only reached when `try_eval` does not panic, obviously.
assert_eq!(ft, 42);
})));
// Whatever code path was taken, the finally block is always executed
// (that's the point of this crate!).
// From a place that survives the panic (if any), we thus observe:
assert!(body_called);
assert!(finally_called);
If the destructor requires access to an owned State1 in the
finally / deferred block, (type State = …: of your choosing),
you can feed that to the ::unwind_safe::with_state::<State> API
entry-point;
the .try_eval(|state: &mut State| { … }) block will then have access to an
exclusive borrow (&mut) to it through the closure's parameter,
and the .finally block will get access to that state in an owned fashion
through its own closure parameter: .finally(|state: State| { … }).
1 This "owned" state may still be a borrow, e.g.,
type State = &mut …;
unsafe code rely on the finally code always being run?Yes! That's the point of the crate, and why it is so named: you can use this
.finally pattern to ensure your unsafe code is unwind-safe ✅
::scopeguardThis is similar to ::scopeguard::defer!, but for the
added ability to get owned access in the finally / defer-red block
while still letting the main block have &mut references to it.
It is thus actually the same as ::scopeguard::guard! The only (but crucial,
imho) difference between these two is the readability of the code: with
.try_eval(…).finally(…), it is more obvious that the code in the
.finally(…) part is running after the one on the main block, which is not
obvious at first sight with ::scopeguard's API (it requires knowing how it
works).