Skip to main content

sim_lib_control/
close.rs

1use sim_kernel::{Args, Cx, Result, Value};
2
3/// A value paired with the callable that closes it at scope exit.
4#[derive(Clone, Debug)]
5pub struct CloseGuard {
6    /// The value being closed.
7    pub value: Value,
8    /// The callable invoked to close `value`.
9    pub close_fn: Value,
10}
11
12impl CloseGuard {
13    /// Builds a guard for `value` using `close_fn` as the close operation.
14    pub fn new(value: Value, close_fn: Value) -> Self {
15        Self { value, close_fn }
16    }
17}
18
19/// Runs `body` and closes all guards in reverse order before returning.
20///
21/// Each close function receives the guarded value and a pending-error argument.
22/// The pending-error argument is `nil` on a normal return, or a string
23/// representation of the body error when `body` fails. All guards are invoked
24/// even when an earlier guard reports an error. Body errors take precedence
25/// over close errors; otherwise the first close error is returned.
26pub fn run_with_close_guards(
27    cx: &mut Cx,
28    guards: Vec<CloseGuard>,
29    body: impl FnOnce(&mut Cx) -> Result<Value>,
30) -> Result<Value> {
31    let result = body(cx);
32    let pending_error = pending_error_value(cx, &result)?;
33    let mut first_close_error = None;
34
35    for guard in guards.into_iter().rev() {
36        let close_result = cx.call_value(
37            guard.close_fn,
38            Args::new(vec![guard.value, pending_error.clone()]),
39        );
40        if let Err(error) = close_result {
41            first_close_error.get_or_insert(error);
42        }
43    }
44
45    match result {
46        Ok(value) => match first_close_error {
47            Some(error) => Err(error),
48            None => Ok(value),
49        },
50        Err(error) => Err(error),
51    }
52}
53
54fn pending_error_value(cx: &mut Cx, result: &Result<Value>) -> Result<Value> {
55    match result {
56        Ok(_) => cx.factory().nil(),
57        Err(error) => cx.factory().string(error.to_string()),
58    }
59}