use sim_kernel::{Args, Cx, Result, Value};
#[derive(Clone, Debug)]
pub struct CloseGuard {
pub value: Value,
pub close_fn: Value,
}
impl CloseGuard {
pub fn new(value: Value, close_fn: Value) -> Self {
Self { value, close_fn }
}
}
pub fn run_with_close_guards(
cx: &mut Cx,
guards: Vec<CloseGuard>,
body: impl FnOnce(&mut Cx) -> Result<Value>,
) -> Result<Value> {
let result = body(cx);
let pending_error = pending_error_value(cx, &result)?;
let mut first_close_error = None;
for guard in guards.into_iter().rev() {
let close_result = cx.call_value(
guard.close_fn,
Args::new(vec![guard.value, pending_error.clone()]),
);
if let Err(error) = close_result {
first_close_error.get_or_insert(error);
}
}
match result {
Ok(value) => match first_close_error {
Some(error) => Err(error),
None => Ok(value),
},
Err(error) => Err(error),
}
}
fn pending_error_value(cx: &mut Cx, result: &Result<Value>) -> Result<Value> {
match result {
Ok(_) => cx.factory().nil(),
Err(error) => cx.factory().string(error.to_string()),
}
}