Skip to main content

sim_lib_control/
unwind.rs

1/// A language-neutral reason for leaving a dynamic extent.
2#[derive(Clone, Debug, PartialEq, Eq)]
3pub enum Unwind<R, B, C, E> {
4    /// Ordinary function or block return.
5    Return(R),
6    /// Exit a repetition construct.
7    Break(B),
8    /// Continue a repetition construct.
9    Continue(C),
10    /// Exceptional completion.
11    Exception(E),
12    /// Cooperative cancellation.
13    Cancelled,
14    /// Explicit close of a suspended extent.
15    Closed,
16}
17
18/// Erased cleanup callback for one dynamic extent.
19type Cleanup<U> = Box<dyn FnOnce(&U)>;
20
21/// Cleanup callbacks for nested dynamic extents.
22pub struct CleanupStack<U> {
23    cleanups: Vec<Cleanup<U>>,
24}
25
26impl<U> Default for CleanupStack<U> {
27    fn default() -> Self {
28        Self {
29            cleanups: Vec::new(),
30        }
31    }
32}
33
34impl<U> CleanupStack<U> {
35    /// Creates an empty cleanup stack.
36    pub fn new() -> Self {
37        Self::default()
38    }
39
40    /// Pushes a cleanup for the current nested extent.
41    pub fn push(&mut self, cleanup: impl FnOnce(&U) + 'static) {
42        self.cleanups.push(Box::new(cleanup));
43    }
44
45    /// Runs every cleanup in reverse nesting order for `reason`.
46    pub fn unwind(mut self, reason: U) -> U {
47        while let Some(cleanup) = self.cleanups.pop() {
48            cleanup(&reason);
49        }
50        reason
51    }
52}