use crate::func::Env;
use crate::gc::Frame;
use crate::trace::{Trace, Tracer};
use alloc::vec::Vec;
use core::cell::RefCell;
type Deferred = (fn(Env), Env);
#[derive(Default)]
pub struct Defers {
list: RefCell<Vec<Deferred>>,
}
impl Trace for Defers {
fn trace(&self, t: &mut Tracer<'_>) {
for (_, env) in self.list.borrow().iter() {
env.trace(t);
}
}
}
impl Defers {
pub fn new() -> Self {
Defers {
list: RefCell::new(Vec::new()),
}
}
#[inline]
pub fn push(&self, f: fn(Env), env: Env) {
self.list.borrow_mut().push((f, env));
}
#[cfg(feature = "std")]
pub fn run(&self) {
let mut pending: Option<alloc::boxed::Box<dyn core::any::Any + Send>> = None;
let frame = Frame::<1>::new();
frame.scope(|| {
loop {
let Some((f, env)) = self.list.borrow_mut().pop() else {
break;
};
frame.set(0, &env);
if let Err(p) = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| f(env))) {
pending = Some(p);
}
}
});
if let Some(p) = pending {
std::panic::resume_unwind(p);
}
}
#[cfg(not(feature = "std"))]
pub fn run(&self) {
let frame = Frame::<1>::new();
frame.scope(|| {
loop {
let Some((f, env)) = self.list.borrow_mut().pop() else {
break;
};
frame.set(0, &env);
f(env);
}
});
}
}