1use sim_kernel::{Args, Cx, Result, Value};
2
3#[derive(Clone, Debug)]
5pub struct CloseGuard {
6 pub value: Value,
8 pub close_fn: Value,
10}
11
12impl CloseGuard {
13 pub fn new(value: Value, close_fn: Value) -> Self {
15 Self { value, close_fn }
16 }
17}
18
19pub 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}