1use std::any::Any;
2use std::cell::RefCell;
3use std::rc::{Rc, Weak};
4
5thread_local! {
6 static CURRENT_SCOPE: RefCell<Option<Weak<ScopeInner>>> = RefCell::new(None);
7}
8
9pub struct Scope {
10 inner: Rc<ScopeInner>,
11}
12
13struct ScopeInner {
14 disposers: RefCell<Vec<Box<dyn FnOnce()>>>,
15 children: RefCell<Vec<Scope>>,
16 memo_cache: RefCell<std::collections::HashMap<String, Box<dyn Any>>>,
17}
18
19impl Scope {
20 pub fn new() -> Self {
21 Self {
22 inner: Rc::new(ScopeInner {
23 disposers: RefCell::new(Vec::new()),
24 children: RefCell::new(Vec::new()),
25 memo_cache: RefCell::new(std::collections::HashMap::new()),
26 }),
27 }
28 }
29
30 pub fn run<R>(&self, f: impl FnOnce() -> R) -> R {
31 CURRENT_SCOPE.with(|current| {
32 let prev = current.borrow().clone();
33 *current.borrow_mut() = Some(Rc::downgrade(&self.inner));
34 let result = f();
35 *current.borrow_mut() = prev;
36 result
37 })
38 }
39
40 pub fn add_disposer(&self, disposer: impl FnOnce() + 'static) {
41 self.inner.disposers.borrow_mut().push(Box::new(disposer));
42 }
43
44 pub fn child(&self) -> Scope {
45 let child = Scope::new();
46 self.inner.children.borrow_mut().push(child.clone());
47 child
48 }
49
50 pub fn dispose(self) {
51 let children = std::mem::take(&mut *self.inner.children.borrow_mut());
53 for child in children {
54 child.dispose();
55 }
56
57 let disposers = std::mem::take(&mut *self.inner.disposers.borrow_mut());
59 for disposer in disposers {
60 disposer();
61 }
62 }
63}
64
65impl Clone for Scope {
66 fn clone(&self) -> Self {
67 Self {
68 inner: self.inner.clone(),
69 }
70 }
71}
72
73pub fn current_scope() -> Option<Scope> {
74 CURRENT_SCOPE.with(|current| {
75 current
76 .borrow()
77 .as_ref()
78 .and_then(|weak| weak.upgrade().map(|inner| Scope { inner }))
79 })
80}
81
82pub fn scoped_effect<F>(f: F)
84where
85 F: FnOnce() -> Box<dyn FnOnce()> + 'static,
86{
87 if let Some(scope) = current_scope() {
88 let cleanup = f();
89 scope.add_disposer(cleanup);
90 } else {
91 let _ = f();
93 }
94}
95
96impl Drop for ScopeInner {
97 fn drop(&mut self) {
98 let children = std::mem::take(&mut *self.children.borrow_mut());
99 for child in children {
100 drop(child);
101 }
102
103 let disposers = std::mem::take(&mut *self.disposers.borrow_mut());
104 for disposer in disposers {
105 disposer();
106 }
107 }
108}