Skip to main content

teksilo_data/
tree_model.rs

1// SPDX-License-Identifier: MPL-2.0
2// SPDX-FileCopyrightText: 2026 FernTech
3
4//! `TreeModel` — concrete reactive tree with shared, cloneable handles.
5//!
6//! `TreeModel<T>` owns a hierarchy of `T` items in a flat SlotMap arena with
7//! parent-child links. Every structural mutation (`insert_root`, `insert_child`,
8//! `remove`, `move_node`, `update`) emits a [`TreeChange`] to all registered
9//! observers before returning. Node identity is a stable, versioned `NodeId`
10//! (a SlotMap key) that is never reused after removal.
11//!
12//! Cloning produces a second handle to the **same** data — all handles see the
13//! same hierarchy and receive the same change notifications. Register observers
14//! via [`observe_changes`](TreeModel::observe_changes); the returned
15//! [`ObserverHandle`] is RAII — dropping it
16//! unregisters the callback.
17//!
18//! For per-view expand/collapse state wrap the model in a
19//! [`TreeSlice`](crate::TreeSlice). For sort/filter projections use
20//! [`SortFilterTreeModel`](crate::SortFilterTreeModel).
21//!
22//! ## Example
23//!
24//! ```rust
25//! # use teksilo_data::{TreeModel, TreeChange};
26//! let tree = TreeModel::new();
27//! let root = tree.insert_root(0, "root");
28//! let child = tree.insert_child(root, 0, "child");
29//!
30//! assert_eq!(tree.root_count(), 1);
31//! assert_eq!(tree.child_count(root), 1);
32//! assert_eq!(tree.parent(child), Some(root));
33//!
34//! let clone = tree.clone();
35//! clone.insert_root(1, "root2");
36//! assert_eq!(tree.root_count(), 2); // both handles share the same data
37//! ```
38
39use std::cell::RefCell;
40use std::rc::Rc;
41
42use slotmap::SlotMap;
43
44use teksilo_core::ObserverHandle;
45
46use crate::tree_change::{NodeId, TreeChange};
47
48struct TreeNode<T> {
49    data: T,
50    parent: Option<NodeId>,
51    children: Vec<NodeId>,
52}
53
54struct TreeObserverEntry {
55    id: u64,
56    callback: Rc<dyn Fn(&TreeChange)>,
57}
58
59struct TreeModelInner<T> {
60    arena: SlotMap<slotmap::DefaultKey, TreeNode<T>>,
61    roots: Vec<NodeId>,
62    observers: Vec<TreeObserverEntry>,
63    next_observer_id: u64,
64    /// Strong handle to the debug-registry adapter for this tree.
65    /// Owned here so the registration drops automatically when the
66    /// inner is freed (the adapter holds only a `Weak` to inner,
67    /// breaking the cycle). `None` until `.debug_named()` is called.
68    /// Compiled out in release.
69    #[cfg(debug_assertions)]
70    debug_adapter: Option<Rc<dyn crate::debug_registry::ModelDebug>>,
71}
72
73/// A concrete reactive tree that stores a hierarchy of `T` items in a flat arena.
74///
75/// `TreeModel<T>` is `Clone` — cloning produces a second handle to the same
76/// underlying data. All handles see the same hierarchy and receive the same
77/// [`TreeChange`] notifications from [`observe_changes`](Self::observe_changes).
78/// Nodes are identified by opaque [`NodeId`] handles that are stable and
79/// non-reusable across mutations (versioned SlotMap keys).
80pub struct TreeModel<T: 'static> {
81    inner: Rc<RefCell<TreeModelInner<T>>>,
82}
83
84impl<T: 'static> TreeModel<T> {
85    /// Create an empty tree model with no roots and no observers.
86    pub fn new() -> Self {
87        Self {
88            inner: Rc::new(RefCell::new(TreeModelInner {
89                arena: SlotMap::new(),
90                roots: Vec::new(),
91                observers: Vec::new(),
92                next_observer_id: 1,
93                #[cfg(debug_assertions)]
94                debug_adapter: None,
95            })),
96        }
97    }
98
99    // --- Structural queries ---
100
101    /// Number of root-level nodes.
102    pub fn root_count(&self) -> usize {
103        self.inner.borrow().roots.len()
104    }
105
106    /// Get the `NodeId` of a root-level node by index.
107    ///
108    /// # Panics
109    /// Panics if `index >= root_count()`.
110    pub fn root(&self, index: usize) -> NodeId {
111        self.inner.borrow().roots[index]
112    }
113
114    /// Number of children of the given node.
115    pub fn child_count(&self, parent: NodeId) -> usize {
116        let guard = self.inner.borrow();
117        guard
118            .arena
119            .get(parent.key())
120            .map(|n| n.children.len())
121            .unwrap_or(0)
122    }
123
124    /// Get the `NodeId` of a child by parent and index.
125    ///
126    /// # Panics
127    /// Panics if the parent or index is invalid.
128    pub fn child(&self, parent: NodeId, index: usize) -> NodeId {
129        let guard = self.inner.borrow();
130        guard.arena[parent.key()].children[index]
131    }
132
133    /// Get the parent of a node, or `None` if it is a root.
134    pub fn parent(&self, node: NodeId) -> Option<NodeId> {
135        let guard = self.inner.borrow();
136        guard.arena.get(node.key()).and_then(|n| n.parent)
137    }
138
139    /// Compute the depth of a node (0 for roots).
140    pub fn depth(&self, node: NodeId) -> usize {
141        let guard = self.inner.borrow();
142        let mut depth = 0;
143        let mut current = guard.arena.get(node.key()).and_then(|n| n.parent);
144        while let Some(pid) = current {
145            depth += 1;
146            current = guard.arena.get(pid.key()).and_then(|n| n.parent);
147        }
148        depth
149    }
150
151    /// Whether the given node has any children.
152    pub fn has_children(&self, node: NodeId) -> bool {
153        self.child_count(node) > 0
154    }
155
156    /// Get the children of a node as a vector of `NodeId`.
157    pub fn children(&self, node: NodeId) -> Vec<NodeId> {
158        let guard = self.inner.borrow();
159        guard
160            .arena
161            .get(node.key())
162            .map(|n| n.children.clone())
163            .unwrap_or_default()
164    }
165
166    /// Access a node's data via a callback. Returns `None` if the node doesn't exist.
167    pub fn with_item<R>(&self, node: NodeId, f: impl FnOnce(&T) -> R) -> Option<R> {
168        let guard = self.inner.borrow();
169        guard.arena.get(node.key()).map(|n| f(&n.data))
170    }
171
172    /// Find the first node matching a predicate (depth-first from roots).
173    pub fn find_by(&self, predicate: impl Fn(&T) -> bool) -> Option<NodeId> {
174        let guard = self.inner.borrow();
175        let mut stack: Vec<NodeId> = guard.roots.iter().rev().copied().collect();
176        while let Some(nid) = stack.pop() {
177            if let Some(node) = guard.arena.get(nid.key()) {
178                if predicate(&node.data) {
179                    return Some(nid);
180                }
181                for &child_id in node.children.iter().rev() {
182                    stack.push(child_id);
183                }
184            }
185        }
186        None
187    }
188
189    // --- Mutations ---
190
191    /// Insert a new root-level node at the given index.
192    ///
193    /// # Panics
194    /// Panics if `index > root_count()`.
195    pub fn insert_root(&self, index: usize, item: T) -> NodeId {
196        let node_id = {
197            let mut guard = self.inner.borrow_mut();
198            let key = guard.arena.insert(TreeNode {
199                data: item,
200                parent: None,
201                children: Vec::new(),
202            });
203            let node_id = NodeId::from_key(key);
204            guard.roots.insert(index, node_id);
205            node_id
206        };
207        self.notify(TreeChange::NodeInserted {
208            parent: None,
209            index,
210            node: node_id,
211        });
212        node_id
213    }
214
215    /// Insert a new child node under the given parent at the given index.
216    ///
217    /// # Panics
218    /// Panics if the parent is invalid or `index > child_count(parent)`.
219    pub fn insert_child(&self, parent: NodeId, index: usize, item: T) -> NodeId {
220        let node_id = {
221            let mut guard = self.inner.borrow_mut();
222            let key = guard.arena.insert(TreeNode {
223                data: item,
224                parent: Some(parent),
225                children: Vec::new(),
226            });
227            let node_id = NodeId::from_key(key);
228            guard.arena[parent.key()].children.insert(index, node_id);
229            node_id
230        };
231        self.notify(TreeChange::NodeInserted {
232            parent: Some(parent),
233            index,
234            node: node_id,
235        });
236        node_id
237    }
238
239    /// Remove a node and its entire subtree.
240    ///
241    /// # Panics
242    /// Panics if the node is invalid.
243    pub fn remove(&self, node: NodeId) {
244        let parent = {
245            let mut guard = self.inner.borrow_mut();
246            let parent = guard.arena[node.key()].parent;
247            // Remove from parent's children list or from roots
248            if let Some(pid) = parent {
249                guard.arena[pid.key()].children.retain(|&c| c != node);
250            } else {
251                guard.roots.retain(|&r| r != node);
252            }
253            // Recursively remove subtree from arena
254            Self::remove_subtree(&mut guard.arena, node);
255            parent
256        };
257        self.notify(TreeChange::NodeRemoved { parent, node });
258    }
259
260    /// Move a node (and its subtree) to a new parent at the given index.
261    ///
262    /// # Panics
263    /// Panics if any of the nodes are invalid, or if the target is a
264    /// descendant of the source (would create a cycle).
265    pub fn move_node(&self, node: NodeId, new_parent: NodeId, new_index: usize) {
266        let old_parent = {
267            let mut guard = self.inner.borrow_mut();
268            // Ensure we're not creating a cycle
269            assert!(
270                !Self::is_descendant_of(&guard.arena, new_parent, node),
271                "cannot move a node into its own subtree"
272            );
273
274            let old_parent = guard.arena[node.key()].parent;
275
276            // Remove from old parent
277            if let Some(pid) = old_parent {
278                guard.arena[pid.key()].children.retain(|&c| c != node);
279            } else {
280                guard.roots.retain(|&r| r != node);
281            }
282
283            // Insert into new parent
284            guard.arena[node.key()].parent = Some(new_parent);
285            guard.arena[new_parent.key()]
286                .children
287                .insert(new_index, node);
288
289            old_parent
290        };
291        self.notify(TreeChange::NodeMoved {
292            node,
293            old_parent,
294            new_parent: Some(new_parent),
295            new_index,
296        });
297    }
298
299    /// Move a node to the root level at the given index.
300    pub fn move_to_root(&self, node: NodeId, new_index: usize) {
301        let old_parent = {
302            let mut guard = self.inner.borrow_mut();
303            let old_parent = guard.arena[node.key()].parent;
304
305            // Remove from old parent
306            if let Some(pid) = old_parent {
307                guard.arena[pid.key()].children.retain(|&c| c != node);
308            } else {
309                guard.roots.retain(|&r| r != node);
310            }
311
312            // Insert into roots
313            guard.arena[node.key()].parent = None;
314            guard.roots.insert(new_index, node);
315
316            old_parent
317        };
318        self.notify(TreeChange::NodeMoved {
319            node,
320            old_parent,
321            new_parent: None,
322            new_index,
323        });
324    }
325
326    /// Update a node's data in place.
327    ///
328    /// # Panics
329    /// Panics if the node is invalid.
330    pub fn update(&self, node: NodeId, item: T) {
331        {
332            let mut guard = self.inner.borrow_mut();
333            guard.arena[node.key()].data = item;
334        }
335        self.notify(TreeChange::NodeUpdated { node });
336    }
337
338    // --- Observation ---
339
340    /// Register an observer for tree change notifications.
341    /// Returns an `ObserverHandle` — dropping it removes the callback.
342    pub fn observe_changes(&self, f: impl Fn(&TreeChange) + 'static) -> ObserverHandle {
343        let mut guard = self.inner.borrow_mut();
344        let id = guard.next_observer_id;
345        guard.next_observer_id += 1;
346        guard.observers.push(TreeObserverEntry {
347            id,
348            callback: Rc::new(f),
349        });
350        let inner = self.inner.clone();
351        ObserverHandle::new(
352            self.inner.clone(),
353            id,
354            Rc::new(move |observer_id| {
355                inner.borrow_mut().observers.retain(|e| e.id != observer_id);
356            }),
357        )
358    }
359
360    // --- Internal helpers ---
361
362    fn notify(&self, change: TreeChange) {
363        let callbacks: Vec<Rc<dyn Fn(&TreeChange)>> = self
364            .inner
365            .borrow()
366            .observers
367            .iter()
368            .map(|e| e.callback.clone())
369            .collect();
370        for cb in &callbacks {
371            cb(&change);
372        }
373    }
374
375    /// Explicit-stack walk: collect every id in the subtree first (reading
376    /// `.children` before anything is removed), then free them all. Removal
377    /// order doesn't matter — freeing a slot doesn't touch any other
378    /// entry's `children` list — so this stays depth-bounded by the
379    /// subtree's node count rather than the call stack.
380    fn remove_subtree(arena: &mut SlotMap<slotmap::DefaultKey, TreeNode<T>>, node: NodeId) {
381        let mut stack = vec![node];
382        let mut to_remove = Vec::new();
383        while let Some(current) = stack.pop() {
384            if let Some(n) = arena.get(current.key()) {
385                stack.extend(n.children.iter().copied());
386            }
387            to_remove.push(current);
388        }
389        for id in to_remove {
390            arena.remove(id.key());
391        }
392    }
393
394    fn is_descendant_of(
395        arena: &SlotMap<slotmap::DefaultKey, TreeNode<T>>,
396        candidate: NodeId,
397        ancestor: NodeId,
398    ) -> bool {
399        let mut current = Some(candidate);
400        while let Some(nid) = current {
401            if nid == ancestor {
402                return true;
403            }
404            current = arena.get(nid.key()).and_then(|n| n.parent);
405        }
406        false
407    }
408}
409
410impl<T: std::fmt::Debug + 'static> TreeModel<T> {
411    /// Register this tree with the debug inspector under `name`. In
412    /// release builds (`!cfg(debug_assertions)`) this is a no-op
413    /// pass-through so call sites stay free of `#[cfg]` lines.
414    ///
415    /// Idempotent on repeated calls — the latest registration wins.
416    /// The registration drops automatically when the last `TreeModel`
417    /// handle is freed (the adapter the registry holds is `Weak`).
418    pub fn debug_named(self, _name: impl Into<String>) -> Self {
419        #[cfg(debug_assertions)]
420        {
421            let weak = Rc::downgrade(&self.inner);
422            let adapter: Rc<dyn crate::debug_registry::ModelDebug> =
423                Rc::new(TreeModelDebug::<T> { weak });
424            let name = _name.into();
425            crate::debug_registry::register(name, Rc::downgrade(&adapter));
426            self.inner.borrow_mut().debug_adapter = Some(adapter);
427        }
428        self
429    }
430}
431
432#[cfg(debug_assertions)]
433struct TreeModelDebug<T> {
434    weak: std::rc::Weak<RefCell<TreeModelInner<T>>>,
435}
436
437#[cfg(debug_assertions)]
438impl<T: std::fmt::Debug + 'static> crate::debug_registry::ModelDebug for TreeModelDebug<T> {
439    fn kind(&self) -> &'static str {
440        "TreeModel"
441    }
442    fn len(&self) -> usize {
443        self.weak
444            .upgrade()
445            .map(|inner| inner.borrow().arena.len())
446            .unwrap_or(0)
447    }
448    fn debug_dump(&self, out: &mut dyn std::fmt::Write) {
449        let Some(inner) = self.weak.upgrade() else {
450            return;
451        };
452        let guard = inner.borrow();
453        // Depth-first walk from each root, indenting by depth.
454        let roots: Vec<NodeId> = guard.roots.clone();
455        for root in roots {
456            dump_subtree(&guard, root, 0, out);
457        }
458    }
459}
460
461#[cfg(debug_assertions)]
462fn dump_subtree<T: std::fmt::Debug>(
463    guard: &TreeModelInner<T>,
464    node: NodeId,
465    depth: usize,
466    out: &mut dyn std::fmt::Write,
467) {
468    let Some(n) = guard.arena.get(node.key()) else {
469        return;
470    };
471    let _ = writeln!(out, "{:indent$}{:?}", "", n.data, indent = depth * 2);
472    let children = n.children.clone();
473    for child in children {
474        dump_subtree(guard, child, depth + 1, out);
475    }
476}
477
478impl<T: 'static> Default for TreeModel<T> {
479    fn default() -> Self {
480        Self::new()
481    }
482}
483
484impl<T: 'static> Clone for TreeModel<T> {
485    fn clone(&self) -> Self {
486        Self {
487            inner: self.inner.clone(),
488        }
489    }
490}
491
492impl<T: std::fmt::Debug + 'static> std::fmt::Debug for TreeModel<T> {
493    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
494        let guard = self.inner.borrow();
495        f.debug_struct("TreeModel")
496            .field("root_count", &guard.roots.len())
497            .field("total_nodes", &guard.arena.len())
498            .finish()
499    }
500}
501
502#[cfg(test)]
503mod tests {
504    use std::cell::Cell;
505
506    use super::*;
507
508    fn sample_tree() -> (TreeModel<&'static str>, NodeId, NodeId, NodeId, NodeId) {
509        let tree = TreeModel::new();
510        let a = tree.insert_root(0, "A");
511        let b = tree.insert_root(1, "B");
512        let a1 = tree.insert_child(a, 0, "A1");
513        let a2 = tree.insert_child(a, 1, "A2");
514        (tree, a, b, a1, a2)
515    }
516
517    #[test]
518    fn empty_tree() {
519        let tree: TreeModel<i32> = TreeModel::new();
520        assert_eq!(tree.root_count(), 0);
521    }
522
523    #[test]
524    fn insert_roots() {
525        let tree = TreeModel::new();
526        let a = tree.insert_root(0, "A");
527        let b = tree.insert_root(1, "B");
528        assert_eq!(tree.root_count(), 2);
529        assert_eq!(tree.root(0), a);
530        assert_eq!(tree.root(1), b);
531    }
532
533    #[test]
534    fn insert_children() {
535        let (tree, a, _, a1, a2) = sample_tree();
536        assert_eq!(tree.child_count(a), 2);
537        assert_eq!(tree.child(a, 0), a1);
538        assert_eq!(tree.child(a, 1), a2);
539    }
540
541    #[test]
542    fn parent_and_depth() {
543        let (tree, a, _, a1, _) = sample_tree();
544        assert_eq!(tree.parent(a), None);
545        assert_eq!(tree.parent(a1), Some(a));
546        assert_eq!(tree.depth(a), 0);
547        assert_eq!(tree.depth(a1), 1);
548    }
549
550    #[test]
551    fn has_children_query() {
552        let (tree, a, b, _, _) = sample_tree();
553        assert!(tree.has_children(a));
554        assert!(!tree.has_children(b));
555    }
556
557    #[test]
558    fn with_item() {
559        let (tree, a, _, _, _) = sample_tree();
560        assert_eq!(tree.with_item(a, |v| *v), Some("A"));
561    }
562
563    #[test]
564    fn find_by() {
565        let (tree, _, _, a1, _) = sample_tree();
566        let found = tree.find_by(|v| *v == "A1");
567        assert_eq!(found, Some(a1));
568
569        let not_found = tree.find_by(|v| *v == "Z");
570        assert_eq!(not_found, None);
571    }
572
573    #[test]
574    fn insert_root_emits_change() {
575        let tree = TreeModel::new();
576        let changes: Rc<RefCell<Vec<TreeChange>>> = Rc::new(RefCell::new(Vec::new()));
577        let c = changes.clone();
578        let _handle = tree.observe_changes(move |change| {
579            c.borrow_mut().push(change.clone());
580        });
581
582        let a = tree.insert_root(0, "A");
583        let log = changes.borrow();
584        assert_eq!(
585            log[0],
586            TreeChange::NodeInserted {
587                parent: None,
588                index: 0,
589                node: a
590            }
591        );
592    }
593
594    #[test]
595    fn insert_child_emits_change() {
596        let tree = TreeModel::new();
597        let a = tree.insert_root(0, "A");
598
599        let changes: Rc<RefCell<Vec<TreeChange>>> = Rc::new(RefCell::new(Vec::new()));
600        let c = changes.clone();
601        let _handle = tree.observe_changes(move |change| {
602            c.borrow_mut().push(change.clone());
603        });
604
605        let a1 = tree.insert_child(a, 0, "A1");
606        let log = changes.borrow();
607        assert_eq!(log.len(), 1, "insert_child should emit exactly one change");
608        assert_eq!(
609            log[0],
610            TreeChange::NodeInserted {
611                parent: Some(a),
612                index: 0,
613                node: a1
614            }
615        );
616    }
617
618    #[test]
619    fn remove_emits_change() {
620        let (tree, a, _, a1, _) = sample_tree();
621        let changes: Rc<RefCell<Vec<TreeChange>>> = Rc::new(RefCell::new(Vec::new()));
622        let c = changes.clone();
623        let _handle = tree.observe_changes(move |change| {
624            c.borrow_mut().push(change.clone());
625        });
626
627        tree.remove(a1);
628        assert_eq!(tree.child_count(a), 1);
629        let log = changes.borrow();
630        assert_eq!(log.len(), 1, "remove should emit exactly one change");
631        assert_eq!(
632            log[0],
633            TreeChange::NodeRemoved {
634                parent: Some(a),
635                node: a1
636            }
637        );
638    }
639
640    #[test]
641    fn remove_subtree() {
642        let tree = TreeModel::new();
643        let a = tree.insert_root(0, "A");
644        let a1 = tree.insert_child(a, 0, "A1");
645        let a1a = tree.insert_child(a1, 0, "A1a");
646
647        tree.remove(a1);
648        assert_eq!(tree.child_count(a), 0);
649        // Both a1 and its descendant a1a should be gone from the arena
650        assert_eq!(tree.with_item(a1, |_| ()), None, "a1 should be removed");
651        assert_eq!(
652            tree.with_item(a1a, |_| ()),
653            None,
654            "a1a (grandchild) should also be removed"
655        );
656    }
657
658    #[test]
659    fn remove_root() {
660        let (tree, a, b, _, _) = sample_tree();
661        tree.remove(a);
662        assert_eq!(tree.root_count(), 1);
663        assert_eq!(tree.root(0), b);
664    }
665
666    #[test]
667    fn move_node() {
668        let (tree, a, b, a1, _) = sample_tree();
669        let changes: Rc<RefCell<Vec<TreeChange>>> = Rc::new(RefCell::new(Vec::new()));
670        let c = changes.clone();
671        let _handle = tree.observe_changes(move |change| {
672            c.borrow_mut().push(change.clone());
673        });
674
675        tree.move_node(a1, b, 0);
676
677        assert_eq!(tree.child_count(a), 1); // only a2 left
678        assert_eq!(tree.child_count(b), 1); // a1 moved here
679        assert_eq!(tree.child(b, 0), a1);
680        assert_eq!(tree.parent(a1), Some(b));
681
682        let log = changes.borrow();
683        assert_eq!(
684            log[0],
685            TreeChange::NodeMoved {
686                node: a1,
687                old_parent: Some(a),
688                new_parent: Some(b),
689                new_index: 0,
690            }
691        );
692    }
693
694    #[test]
695    fn move_to_root() {
696        let (tree, a, _, a1, _) = sample_tree();
697        tree.move_to_root(a1, 0);
698
699        assert_eq!(tree.root_count(), 3); // a1, A, B
700        assert_eq!(tree.root(0), a1);
701        assert_eq!(tree.parent(a1), None);
702        assert_eq!(tree.child_count(a), 1); // only a2 left
703    }
704
705    #[test]
706    #[should_panic(expected = "cannot move a node into its own subtree")]
707    fn move_into_own_subtree_panics() {
708        let (tree, a, _, a1, _) = sample_tree();
709        tree.move_node(a, a1, 0); // A into A1 would create a cycle
710    }
711
712    #[test]
713    fn update_emits_change() {
714        let (tree, a, _, _, _) = sample_tree();
715        let changes: Rc<RefCell<Vec<TreeChange>>> = Rc::new(RefCell::new(Vec::new()));
716        let c = changes.clone();
717        let _handle = tree.observe_changes(move |change| {
718            c.borrow_mut().push(change.clone());
719        });
720
721        tree.update(a, "A-updated");
722        assert_eq!(tree.with_item(a, |v| *v), Some("A-updated"));
723        let log = changes.borrow();
724        assert_eq!(log[0], TreeChange::NodeUpdated { node: a });
725    }
726
727    #[test]
728    fn observer_removed_on_handle_drop() {
729        let tree = TreeModel::new();
730        let count = Rc::new(Cell::new(0));
731        let c = count.clone();
732        let handle = tree.observe_changes(move |_| c.set(c.get() + 1));
733
734        tree.insert_root(0, "A");
735        assert_eq!(count.get(), 1);
736
737        drop(handle);
738        tree.insert_root(1, "B");
739        assert_eq!(count.get(), 1); // Not called again
740    }
741
742    #[test]
743    fn clone_shares_data() {
744        let tree = TreeModel::new();
745        let a = tree.insert_root(0, "A");
746
747        let clone = tree.clone();
748        assert_eq!(clone.root_count(), 1);
749        assert_eq!(clone.with_item(a, |v| *v), Some("A"));
750
751        clone.insert_root(1, "B");
752        assert_eq!(tree.root_count(), 2);
753    }
754
755    #[test]
756    fn deep_tree_depth() {
757        let tree = TreeModel::new();
758        let r = tree.insert_root(0, "r");
759        let c1 = tree.insert_child(r, 0, "c1");
760        let c2 = tree.insert_child(c1, 0, "c2");
761        let c3 = tree.insert_child(c2, 0, "c3");
762        assert_eq!(tree.depth(r), 0);
763        assert_eq!(tree.depth(c1), 1);
764        assert_eq!(tree.depth(c2), 2);
765        assert_eq!(tree.depth(c3), 3);
766    }
767
768    #[test]
769    fn children_returns_correct_ids() {
770        let (tree, a, _, a1, a2) = sample_tree();
771        let children = tree.children(a);
772        assert_eq!(children, vec![a1, a2]);
773    }
774
775    /// `remove` walks the whole subtree via `remove_subtree`; a 50,000-deep
776    /// single-child chain must not overflow the call stack (it's an
777    /// explicit-stack walk, not recursion).
778    #[test]
779    fn remove_deep_chain_does_not_overflow() {
780        const DEPTH: usize = 50_000;
781        let tree = TreeModel::new();
782        let root = tree.insert_root(0, 0usize);
783        let mut leaf = root;
784        for i in 1..DEPTH {
785            leaf = tree.insert_child(leaf, 0, i);
786        }
787        tree.remove(root);
788        assert_eq!(tree.root_count(), 0);
789        assert_eq!(tree.with_item(leaf, |_| ()), None);
790    }
791}