Skip to main content

guinea_core/scope/
tree.rs

1use std::cell::RefCell;
2use std::rc::{Rc, Weak};
3use std::sync::atomic::{AtomicU64, Ordering};
4
5use super::{MAIN, Outlet, Scope, ScopeData};
6
7/// Numbers every scope once, from 1: a node that holds no scope is numbered 0.
8static 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/// Every scope in one [`ScopeTree`], and which sits under which.
19#[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    /// Takes the scope at `index` and everything under it out of the tree,
64    /// children before their parent and the newest child first, and hands
65    /// back what they held in that order.
66    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    /// Where a `Scope` finds its tree. Weak: each tree is its [`ScopeTree`]'s,
101    /// and the thread ending lets go of nothing here but names.
102    static TREES: RefCell<Vec<Weak<RefCell<Tree>>>> = const { RefCell::new(Vec::new()) };
103}
104
105/// Lists `tree`, in the first slot whose tree is gone, and says which.
106fn 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/// Removes its scope when dropped: for a child that nothing else will remove.
132#[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
155/// A tree of scopes, and the owner of every scope in it: letting go of it
156/// removes its root and everything under it, the last first.
157///
158/// Whoever hosts something holds one - an application, a window with no
159/// application around it, a test.
160pub 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    /// The scope at the top of the tree.
181    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}