guinea_core/scope/
tree.rs1use std::cell::RefCell;
2use std::rc::{Rc, Weak};
3use std::sync::atomic::{AtomicU64, Ordering};
4
5use super::{MAIN, Outlet, Scope, ScopeData};
6
7static NEXT_SERIAL: AtomicU64 = AtomicU64::new(1);
9
10pub(super) struct Node {
11 pub(super) serial: u64,
12 pub(super) data: Option<Rc<ScopeData>>,
13 pub(super) parent: Option<u32>,
14 pub(super) outlet: Outlet,
15 pub(super) children: Vec<u32>,
16}
17
18#[derive(Default)]
20pub(super) struct Tree {
21 pub(super) nodes: Vec<Node>,
22 free: Vec<u32>,
23}
24
25impl Tree {
26 pub(super) fn insert(&mut self, parent: Option<u32>, outlet: Outlet) -> (u32, u64) {
27 let serial = NEXT_SERIAL.fetch_add(1, Ordering::Relaxed);
28 let data = Some(Rc::new(ScopeData::default()));
29 let index = match self.free.pop() {
30 Some(index) => {
31 let node = &mut self.nodes[index as usize];
32 node.serial = serial;
33 node.data = data;
34 node.parent = parent;
35 node.outlet = outlet;
36 index
37 }
38 None => {
39 self.nodes.push(Node {
40 serial,
41 data,
42 parent,
43 outlet,
44 children: Vec::new(),
45 });
46 (self.nodes.len() - 1) as u32
47 }
48 };
49
50 if let Some(parent) = parent {
51 self.nodes[parent as usize].children.push(index);
52 }
53
54 (index, serial)
55 }
56
57 pub(super) fn node(&self, index: u32, serial: u64) -> Option<&Node> {
58 self.nodes
59 .get(index as usize)
60 .filter(|node| node.serial == serial && node.data.is_some())
61 }
62
63 pub(super) fn detach(&mut self, index: u32, serial: u64) -> Vec<Rc<ScopeData>> {
67 let Some(node) = self.node(index, serial) else {
68 return Vec::new();
69 };
70 if let Some(parent) = node.parent {
71 self.nodes[parent as usize].children.retain(|child| *child != index);
72 }
73
74 let mut order = Vec::new();
75 self.collect(index, &mut order);
76
77 let mut detached = Vec::with_capacity(order.len());
78 for index in order {
79 let node = &mut self.nodes[index as usize];
80 node.serial = 0;
81 node.parent = None;
82 node.children.clear();
83 if let Some(data) = node.data.take() {
84 detached.push(data);
85 }
86 self.free.push(index);
87 }
88 detached
89 }
90
91 pub(super) fn collect(&self, index: u32, order: &mut Vec<u32>) {
92 for child in self.nodes[index as usize].children.iter().rev() {
93 self.collect(*child, order);
94 }
95 order.push(index);
96 }
97}
98
99thread_local! {
100 static TREES: RefCell<Vec<Weak<RefCell<Tree>>>> = const { RefCell::new(Vec::new()) };
103}
104
105fn register(tree: &Rc<RefCell<Tree>>) -> u32 {
107 TREES.with(|trees| {
108 let mut trees = trees.borrow_mut();
109 let named = Rc::downgrade(tree);
110
111 match trees.iter().position(|slot| slot.strong_count() == 0) {
112 Some(slot) => {
113 trees[slot] = named;
114 slot as u32
115 }
116 None => {
117 trees.push(named);
118 (trees.len() - 1) as u32
119 }
120 }
121 })
122}
123
124pub(super) fn tree(slot: u32) -> Option<Rc<RefCell<Tree>>> {
125 TREES
126 .try_with(|trees| trees.borrow().get(slot as usize).and_then(Weak::upgrade))
127 .ok()
128 .flatten()
129}
130
131#[must_use = "the scope is removed as soon as this is dropped"]
133pub struct ScopeGuard(pub(super) Scope);
134
135impl ScopeGuard {
136 pub fn scope(&self) -> Scope {
137 self.0
138 }
139}
140
141impl std::ops::Deref for ScopeGuard {
142 type Target = Scope;
143
144 fn deref(&self) -> &Scope {
145 &self.0
146 }
147}
148
149impl Drop for ScopeGuard {
150 fn drop(&mut self) {
151 self.0.remove();
152 }
153}
154
155pub struct ScopeTree {
161 _tree: Rc<RefCell<Tree>>,
162 root: Scope,
163}
164
165impl ScopeTree {
166 pub fn new() -> Self {
167 let tree = Rc::new(RefCell::new(Tree::default()));
168 let (index, serial) = tree.borrow_mut().insert(None, MAIN);
169
170 Self {
171 root: Scope {
172 tree: register(&tree),
173 index,
174 serial,
175 },
176 _tree: tree,
177 }
178 }
179
180 pub fn scope(&self) -> Scope {
182 self.root
183 }
184}
185
186impl Drop for ScopeTree {
187 fn drop(&mut self) {
188 self.root.remove();
189 }
190}
191
192impl Default for ScopeTree {
193 fn default() -> Self {
194 Self::new()
195 }
196}
197
198impl std::ops::Deref for ScopeTree {
199 type Target = Scope;
200
201 fn deref(&self) -> &Scope {
202 &self.root
203 }
204}