use std::any::Any;
use std::cell::RefCell;
use std::rc::Rc;
use crate::effect::EffectImpl;
pub(crate) struct Scope {
pub(crate) cleanups: RefCell<Vec<Box<dyn FnOnce()>>>,
pub(crate) effects: RefCell<Vec<Rc<EffectImpl>>>,
pub(crate) keepers: RefCell<Vec<Box<dyn Any>>>,
}
impl Scope {
pub(crate) fn new() -> Rc<Self> {
Rc::new(Self {
cleanups: RefCell::new(Vec::new()),
effects: RefCell::new(Vec::new()),
keepers: RefCell::new(Vec::new()),
})
}
pub(crate) fn on_cleanup(&self, f: impl FnOnce() + 'static) {
self.cleanups.borrow_mut().push(Box::new(f));
}
pub(crate) fn keep_alive<T: 'static>(&self, x: T) {
self.keepers.borrow_mut().push(Box::new(x));
}
pub(crate) fn add_effect(&self, e: Rc<EffectImpl>) {
self.effects.borrow_mut().push(e);
}
}
impl Drop for Scope {
fn drop(&mut self) {
for cleanup in self.cleanups.borrow_mut().drain(..).rev() {
cleanup();
}
}
}
thread_local! {
static CURRENT_SCOPE: RefCell<Option<Rc<Scope>>> = const { RefCell::new(None) };
}
pub(crate) fn with_current_scope<R>(scope: &Rc<Scope>, f: impl FnOnce() -> R) -> R {
let prev = CURRENT_SCOPE.with(|c| c.replace(Some(scope.clone())));
let result = f();
CURRENT_SCOPE.with(|c| *c.borrow_mut() = prev);
result
}
pub(crate) fn current_scope() -> Rc<Scope> {
CURRENT_SCOPE.with(|c| {
c.borrow()
.clone()
.expect("current_scope() called outside an island mount")
})
}