1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
//! The guard that undoes what an unwinding callback would otherwise leave behind.
//!
//! Everything an operator keeps on its stack — a subscription, an observer, a queued value — is
//! released by the unwind itself, so it needs no guard. What the unwind does not undo is a change
//! already written to a **shared state that outlives the panicking call**: a delivery left in its
//! delivering state, a subscriber counted into a ref count, a source left subscribed after its
//! termination. Those states are reached by writing them *before* the callback and finishing the
//! transaction *after* it, which is exactly the step a panic skips.
//!
//! [`OnPanic`] runs that finishing step on the unwinding thread instead. Its action therefore
//! runs under the constraints of a `Drop` during a panic:
//!
//! - **It must not panic.** A panic while panicking aborts the process. It may drop values, and
//! run the ordinary disposals that dropping them entails, but it should not call further into
//! code that is free to unwind.
//! - **It must not take a lock the panicking thread already holds**, which in this crate means it
//! is only ever wrapped around callbacks that run with no lock held — observer notifications and
//! external subscriptions. A guard that has to lock is safe exactly where the returning path
//! locks too.
//!
//! The guard is armed for the scope it is bound to, so it must be bound: `let _guard = …`, and
//! `drop(guard)` where the scope ends before the enclosing block. When the returning path needs
//! something back from the guard, park it in the guard's state and take it with
//! [`OnPanic::disarm`], which ends the scope and hands the state over.
use Educe;
/// Runs `action` with the guarded state if the current scope unwinds, and nothing otherwise.
///
/// See the [module documentation](self) for what the action may do. Use [`on_panic`] when there is
/// no state to carry.
>);
/// Runs `action` if the current scope unwinds, for a guard that carries no state.