dsa_rust/hierarchies/
safe_linked_gentree.rs

1/*! A safe, linked, n-ary tree implementation
2
3# About
4Following classical DSA curricula, this implementation relies on pointers for the structure's composition and navigation. This module explores the use of reference counting and interior mutability through the [Rc] and [RefCell] types (respectively) for a safe, positional implementation that avoids dangling pointers and reference cycles for proper [Drop] semantics.
5
6Reference counting provides a synchronous, deterministic form of memory management that acts like a garbage collector and prevents dangling pointers by automatically managing lifetimes. The structure is able to keep objects alive until their reference count hits zero, potentially even after they've gone out of their original scope. To avoid memory leaks caused by reference cycles, tree nodes use strong `Rc` pointers for children and [Weak] pointers for parent links. This ensures the tree can be correctly dropped recursively from the top down.
7
8Using smart pointers to manage reference counting and interior mutability to skirt multiple mutable references is an elegant solution to the linked desgin, but its still a bit painful, and potentially overkill for many applications. The good news is that there are much easier ways to accomplish similar goals. To wit, this library also includes a `Vec`-backed tree structure with a similar API. For more polished levels of functionality with the same arena-style backing structure concepts see [id_tree](https://docs.rs/id_tree/latest/id_tree/). It is worth noting that `id_tree` uses a hash map to store node IDs, so it may not be as performanat as either a pointer-backed or simple indexed tree structure for smaller, short-lived tree structures.
9
10# Design
11The base [GenTree] structure is sparse and only contains basic operations for constructors and metadata retrieval. Most of the magic happens in the [CursorMut] struct. Both structs rely on a [Position] struct which provides a safe handle to all the reference-counted pointers required to make tree go brrr.
12
13# Example
14This section presents an algorithm that builds a tree from a `Vec` of custom `Heading` objects that contain a level and a heading value. Assume the inputs to the algorithm start at level 1 with the first (and lowest) level in the `Vec<Heading>` list being 2. The result is a single, empty root node represented by `[]`.
15```text
16    []
1718    ├── Landlocked
19    │   ├── Switzerland
20    │   │   └── Geneva
21    │   │       └── Old Town
22    │   │           └── Cathédrale Saint-Pierre
23    │   └── Bolivia
24    │       └── []
25    │           └── []
26    │               ├── Puerta del Sol
27    │               └── Puerta de la Luna
28    └── Islands
29        ├── Marine
30        │   └── Australia
31        └── Fresh Water
32```
33```rust
34    use dsa_rust::hierarchies::safe_linked_gentree::GenTree;
35
36    struct Heading {
37        level: usize,
38        title: String,
39    }
40    impl Heading {
41        fn new(title: String, level: usize) -> Heading {
42            Heading { level, title }
43        }
44    }
45
46    pub fn construct(mut cur_level: usize, data: Vec<Heading>) -> GenTree<Heading> {
47        // Instantiates a Tree with a generic root and traversal positioning
48        let mut tree: GenTree<Heading> = GenTree::<Heading>::new();
49        let mut cursor = tree.cursor_mut(); // Sets cursor to tree.root
50
51        // Constructs tree from Vec<T>
52        for heading in data {
53            let data_level = heading.level;
54
55            // Case 1: Adds a child to the current parent and sets level cursor
56            if data_level == cur_level + 1 {
57                cursor.add_child(heading);
58                cur_level += 1;
59            }
60            // Case 2: Adds a child with multi-generational skips
61            else if data_level > cur_level {
62                let diff = data_level - cur_level;
63                for _ in 1..diff {
64                    let empty = Heading::new("[]".to_string(), 0);
65                    cursor.add_child(empty);
66                    cur_level += 1;
67                }
68                cursor.add_child(heading);
69                cur_level += 1;
70            }
71            // Case 3: Adds sibling to current parent
72            else if data_level == cur_level {
73                cursor.ascend().ok();
74                cursor.add_child(heading);
75            }
76            // Case 4: Adds a child to the appropriate ancestor,
77            // ensuring proper generational skips
78            else {
79                let diff = cur_level - data_level;
80                for _ in 0..=diff {
81                    cursor.ascend().ok();
82                    cur_level -= 1;
83                }
84                cursor.add_child(heading);
85                cur_level += 1;
86            }
87        }
88        tree
89    }
90
91```
92
93*/
94
95use std::cell::{Ref, RefCell};
96use std::rc::{Rc, Weak};
97//use std::marker::PhantomData;
98
99/// The `Position` struct provides a safe, lightweight handle to `Node` data.
100/// All meaningful accessors and mutators appear on the [CursorMut] struct.
101// Position only contains private members, but must be public due to its
102// presence as a CursorMut return type.
103pub struct Position<T> {
104    ptr: Option<Rc<RefCell<Node<T>>>>,
105}
106impl<T> Position<T> {
107    /// Creates a handle to Node and returns it as a Position.
108    fn new(ptr: Node<T>) -> Self {
109        Position {
110            ptr: Some(Rc::new(RefCell::new(ptr))),
111        }
112    }
113
114    /// Returns an reference to the data at the Position, if Some.
115    fn get_data(&self) -> Option<Ref<'_, T>> {
116        let node_ref: Ref<Node<T>> = self.ptr.as_ref()?.borrow();
117        Ref::filter_map(node_ref, |node| node.data.as_ref()).ok()
118        //if let Some(val) = self.ptr.as_ref() {
119        //    Some((*(*val)).borrow())
120        //} else { None }
121    }
122
123    /// Returns the Node from a Position, if Some.
124    //fn get_node(&self) -> Ref<Node<T>> {
125    //    self.ptr.as_ref().unwrap().borrow()
126    //}
127    fn get_node(&self) -> Option<Ref<'_, Node<T>>> {
128        self.ptr.as_ref().map(|rc| rc.borrow())
129    }
130
131    /// Returns the Position for the current Position's parent, if Some.
132    //fn get_parent_pos(&self) -> Option<Position<T>> {
133    //    if let Some(parent) = self.ptr.as_ref().unwrap().borrow().parent.clone() {
134    //        Some(parent)
135    //    } else { None }
136    //}
137    fn get_parent_pos(&self) -> Option<Position<T>> {
138        if let Some(weak_parent) = &self.ptr.as_ref()?.borrow().parent {
139            weak_parent.upgrade().map(|rc| Position { ptr: Some(rc) })
140        } else {
141            None
142        }
143    }
144}
145// "Shallow" clone only clones/increases the Rc, not the whole Node
146impl<T> Clone for Position<T> {
147    fn clone(&self) -> Self {
148        Position {
149            ptr: self.ptr.clone(),
150        }
151    }
152}
153impl<T> PartialEq for Position<T> {
154    fn eq(&self, other: &Self) -> bool {
155        match (&self.ptr, &other.ptr) {
156            (Some(a), Some(b)) => Rc::ptr_eq(a, b),
157            (None, None) => true,
158            _ => false,
159        }
160    }
161}
162impl<T> std::fmt::Debug for Position<T> {
163    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
164        match &self.ptr {
165            Some(rc) => write!(f, "Position({:p})", Rc::as_ptr(rc)),
166            None => write!(f, "Position(None)"),
167        }
168    }
169}
170
171/// Internal-only struct that represents the heart of the general tree. The `Node`
172/// struct contains strong pointers to children, but weak pointers to parent nodes
173/// for proper drop semantics to avoid reference cycles.
174struct Node<T> {
175    parent: Option<Weak<RefCell<Node<T>>>>,
176    children: Vec<Position<T>>, // Always exists for a Node, even if empty
177    data: Option<T>,
178}
179impl<T> Node<T> {
180    /// Builds a new Node and returns its position.
181    fn root(data: Option<T>) -> Node<T> {
182        Node {
183            parent: None,
184            children: Vec::new(),
185            data,
186        }
187    }
188
189    /// Creates a new `Node` with given data for the given `Position`.
190    fn new(parent: &Position<T>, data: T) -> Node<T> {
191        Node {
192            //parent: Some(parent.clone()),
193            parent: Some(Rc::downgrade(parent.ptr.as_ref().unwrap())),
194            children: Vec::new(),
195            data: Some(data),
196        }
197    }
198}
199
200/// The `GenTree` struct represents a positional, linked-based general
201/// tree structure that contains a pointer to the root node and the structure's size.
202/// The genericity of the struct means you'll have to explicitly type the
203/// tree at instantiation.
204///
205/// Most of the major accessors and mutators appear on the [CursorMut] struct.
206///
207/// Example:
208/// ```example
209///     // Creates a tree over Heading objects
210///     let mut tree: GenTree<Heading> = GenTree::<Heading>::new();
211///
212///     // Creates a CursorMut to navigate/mutate the tree,
213///     // starting at the root node
214///     let mut cursor = tree.cursor_mut();
215/// ```
216#[derive(Debug)]
217pub struct GenTree<T> {
218    root: Position<T>,
219    size: usize,
220}
221impl<T> Default for GenTree<T> {
222    fn default() -> Self {
223        Self::new()
224    }
225}
226impl<T> GenTree<T> {
227    /// Instantiates a new `GenTree`.
228    pub fn new() -> GenTree<T> {
229        let root: Position<T> = Position::new(Node::root(None));
230        GenTree { root, size: 0 }
231    }
232
233    /// Returns the `Position` of the tree's root.
234    pub fn root(&self) -> Position<T> {
235        self.root.clone()
236    }
237
238    /// Creates a `CursorMut` starting at the tree's root.
239    pub fn cursor_mut(&mut self) -> CursorMut<'_, T> {
240        CursorMut {
241            node: self.root.clone(),
242            tree: self,
243        }
244    }
245
246    /// Creates a `CursorMut` from a given `Position`.
247    pub fn cursor_from(&mut self, position: Position<T>) -> CursorMut<'_, T> {
248        CursorMut {
249            node: position,
250            tree: self,
251        }
252    }
253}
254
255/** A cursor over mutable `Node` data with safe, reference-counted `Position` handles.
256
257This struct represents the majority of major operations for the [GenTree] structure.
258All operations run in `O(1)` time unless otherwise noted. */
259pub struct CursorMut<'a, T> {
260    node: Position<T>,
261    tree: &'a mut GenTree<T>,
262}
263impl<'a, T> CursorMut<'a, T> {
264    // METADATA
265    ///////////
266
267    /** Returns `true` if the `Node` under the curosr is the tree's root */
268    pub fn is_root(&self) -> bool {
269        self.node.clone() == self.tree.root()
270    }
271
272    /** Returns `true` if the `Node` under the curosr has data */
273    pub fn is_some(&self) -> bool {
274        let val = self.node.get_data();
275        val.is_some()
276    }
277
278    /** Returns `true` if the `Node` under the cursor is empty */
279    pub fn is_none(&self) -> bool {
280        let val = self.node.get_data();
281        val.is_none()
282    }
283
284    /** Returns the number of children for the `Node` under the cursor as usize */
285    pub fn num_children(&self) -> usize {
286        if let Some(val) = self.node.ptr.clone() {
287            (*val).borrow().children.len()
288        } else {
289            0
290        }
291    }
292
293    /** Returns the depth of the cursor from the tree's root */
294    //pub fn depth(&mut self) -> usize {
295    //    let mut depth = 0;
296    //    let current = self.current().clone();
297    //    while !self.is_root() {
298    //        self.ascend().ok();
299    //        depth += 1;
300    //    }
301    //    self.jump(&current);
302    //    depth
303    //}
304    pub fn depth(&self) -> usize {
305        let mut depth = 0;
306        let mut current_ptr = self.node.clone().ptr;
307        //while let Some(pos) = current.ptr {
308        while let Some(pos) = current_ptr {
309            let node_ref = pos.borrow();
310            if let Some(parent_weak) = &node_ref.parent {
311                //current = Position { ptr: parent_weak.upgrade() };
312                current_ptr = parent_weak.upgrade();
313                depth += 1;
314            } else {
315                break;
316            }
317        }
318        depth
319    }
320
321    /** Returns the height of the tallest sub-tree for the current position */
322    //pub fn height(&self) -> usize {
323    //    let current = self.current();
324    //    self.height_rec(current.clone())
325    //}
326    ///** The recursive guts of the height function */
327    //#[allow(clippy::only_used_in_recursion)]
328    //fn height_rec(&self, node: Position<T>) -> usize {
329    //    let mut h = 0;
330    //    if let Some(n) = node.ptr.clone() {
331    //        for e in &(*n).borrow().children {
332    //            h = std::cmp::max(h, self.height_rec(e.clone()))
333    //        }
334    //    }
335    //    h + 1
336    //}
337    pub fn height(&self) -> usize {
338        let current = self.current();
339        fn height_rec<T>(node: &Position<T>) -> usize {
340            let mut h = 0;
341            if let Some(n) = node.ptr.clone() {
342                for e in &(*n).borrow().children {
343                    h = std::cmp::max(h, height_rec(&e.clone()))
344                }
345            }
346            h + 1
347        }
348        height_rec(current)
349    }
350
351    // ACCESSORS AND MUTATORS
352    /////////////////////////
353
354    /** Returns an _immutable_ reference to the data under the cursor, if `Some` */
355    pub fn get_data(&self) -> Option<Ref<'_, T>> {
356        let node_ref: Ref<Node<T>> = self.node.get_node()?;
357        Ref::filter_map(node_ref, |node| node.data.as_ref()).ok()
358    }
359
360    /** Returns an _immutable_ reference to the data for a supplied `Position` */
361    pub fn get_for_pos(&'a self, pos: &'a Position<T>) -> Option<Ref<'a, T>> {
362        let node_ref: Ref<Node<T>> = pos.get_node()?;
363        Ref::filter_map(node_ref, |node| node.data.as_ref()).ok()
364    }
365
366    // /** Overwrites the data for the current Node without affecting its position,
367    // returns the old data, if Some */
368    //pub fn set(&mut self, data: T) -> Option<T> {
369    //    if let Ok(n) = self.node.as_ptr() {
370    //        unsafe {
371    //            let old = (*n).data.take();
372    //            (*n).data = Some(data);
373    //            return old;
374    //        }
375    //    } else {
376    //        None
377    //    }
378    //}
379
380    /** Adds a new child `Node` under the current cursor and advances the cursor
381    to the new child */
382    pub fn add_child(&mut self, data: T) {
383        let parent = self.node.clone();
384
385        // Create the new child node and give it a Position
386        let new_node = Node::new(&parent, data);
387        let new_pos = Position::new(new_node);
388
389        // Add the new child to the parent's child list
390        let kids = parent.ptr.unwrap();
391        (*kids).borrow_mut().children.push(new_pos.clone());
392
393        // Mutates self to be the Position of the new node
394        self.node = new_pos;
395
396        // Increment the size of the tree
397        self.tree.size += 1;
398    }
399
400    /** Returns a list of owned descendant (child) `Position`s for the `Node`
401    under the cursor in `O(c)` time where `c` is the number of children; The
402    clone used here is a cheap pointer copy, not an underlying data copy */
403    //pub fn children(&self) -> Vec<Position<T>> {
404    //    self.node
405    //        .get_node()
406    //        .unwrap()
407    //        .children
408    //        .iter()
409    //        .cloned()
410    //        .collect::<Vec<_>>()
411    //}
412    // Allocates a new Vec and clones Positions in O(n) time
413    pub fn children(&self) -> Vec<Position<T>> {
414        self.node
415            .get_node()
416            //.map(|node| node.children.iter().cloned().collect())
417            .map(|node| node.children.to_vec())
418            .unwrap_or_default()
419    }
420
421    /// Warning: Broken! Does not handle root deletion properly.
422    ///
423    /// Removes the node at the current cursor position and returns its data,
424    /// if Some. Operation executes in `O(c)` time where `c` is the number of
425    /// children for the given node; Adds all children to the parent
426    /// (if `Some`), and returns the deleted `Node`; If the cursor is at the tree's
427    /// root, this just deletes the `Node`'s data, leaving `None`; Moves the cursor
428    /// to the parent, if `Some` */
429    pub fn delete(&mut self) -> Option<T> {
430        let self_pos = self.node.clone();
431        let self_rc = self_pos.ptr.clone()?;
432
433        // Check and get parent
434        let parent_pos = self_rc.borrow().parent.as_ref()?.upgrade()?;
435        let parent_pos = Position {
436            ptr: Some(parent_pos),
437        };
438        let parent_rc = parent_pos.ptr.clone().unwrap();
439
440        // 1. Remove self from parent.children
441        {
442            let mut parent_node = parent_rc.borrow_mut();
443            if let Some(index) = parent_node.children.iter().position(|c| *c == self.node) {
444                parent_node.children.remove(index);
445            }
446        }
447
448        // 2. Take self's children (detach them)
449        let mut self_children = {
450            let mut self_node = self_rc.borrow_mut();
451            std::mem::take(&mut self_node.children)
452        };
453
454        // 3. Reparent each child and move them to parent's children
455        {
456            let mut parent_node = parent_rc.borrow_mut();
457            for child in &mut self_children {
458                if let Some(child_rc) = child.ptr.clone() {
459                    child_rc.borrow_mut().parent = Some(Rc::downgrade(&parent_rc));
460                }
461                parent_node.children.push(child.clone());
462            }
463        }
464
465        // 4. Move cursor to parent
466        self.jump(&parent_pos);
467
468        // 5. Take and return data from the deleted node
469        let mut self_node = self_rc.borrow_mut();
470        self_node.data.take()
471    }
472
473    // NAVIGATION
474    /////////////
475
476    /** Returns a reference to the current `Position` */
477    pub fn current(&self) -> &Position<T> {
478        &self.node
479    }
480
481    /** Jump the cursor to the given `Position` */
482    pub fn jump(&mut self, new: &Position<T>) {
483        self.node = (*new).clone();
484    }
485
486    /** Moves the cursor up a generation, if `Some`; Trying to ascend past the root results in an error */
487    pub fn ascend(&mut self) -> Result<(), String> {
488        if let Some(parent) = self.node.get_parent_pos() {
489            self.node = parent;
490            Ok(())
491        } else {
492            Err("Error: Cannot ascend past root".to_string())
493        }
494    }
495}
496
497#[cfg(test)]
498mod tests {
499
500    // Both basic and dangle tests use the tree builder
501    use super::{GenTree, Position};
502    use crate::hierarchies::safe_linked_gentree_builder::{construct, Heading};
503
504    #[test]
505    /** Creates this tree to test properties
506        []
507        ├── Landlocked
508        │   ├── Switzerland
509        │   │   └── Geneva
510        │   │       └── Old Town
511        │   │           └── Cathédrale Saint-Pierre
512        │   └── Bolivia
513        │       └── []
514        │           └── []
515        │               ├── Puerta del Sol
516        │               └── Puerta de la Luna
517        └── Islands
518            ├── Marine
519            │   └── Australia
520            └── Fresh Water
521    */
522    fn basic() {
523        let tree_vec = vec![
524            Heading {
525                level: 2,
526                title: "Landlocked".to_string(),
527            },
528            Heading {
529                level: 3,
530                title: "Switzerland".to_string(),
531            },
532            Heading {
533                level: 4,
534                title: "Geneva".to_string(),
535            },
536            Heading {
537                level: 5,
538                title: "Old Town".to_string(),
539            },
540            Heading {
541                level: 6,
542                title: "Cathédrale Saint-Pierre".to_string(),
543            },
544            Heading {
545                level: 3,
546                title: "Bolivia".to_string(),
547            },
548            Heading {
549                level: 6,
550                title: "Puerta del Sol".to_string(),
551            },
552            Heading {
553                level: 6,
554                title: "Puerta de la Luna".to_string(),
555            },
556            Heading {
557                level: 2,
558                title: "Islands".to_string(),
559            },
560            Heading {
561                level: 3,
562                title: "Marine".to_string(),
563            },
564            Heading {
565                level: 4,
566                title: "Australia".to_string(),
567            },
568            Heading {
569                level: 3,
570                title: "Fresh Water".to_string(),
571            },
572        ];
573
574        // Constructs tree ignoring the first heading
575        let mut tree: GenTree<Heading> = construct(1, tree_vec);
576
577        assert!(tree.root.get_parent_pos().is_none());
578        assert!(tree.root().ptr.is_some());
579        let p = tree.root();
580        let _ = p.get_data();
581
582        // Tests root() -> Position<T>
583        // By identity (using custom PartialEq ipml)
584        assert!(tree.cursor_mut().node == tree.root);
585        // By assert_eq!'s default Debug route
586        let cursor = tree.cursor_mut();
587        assert_eq!(cursor.node, tree.root());
588
589        let mut cursor = tree.cursor_mut();
590        // Tests that root is empty with is_some() and is_none()
591        assert!(!cursor.is_some());
592        assert!(cursor.is_none());
593        // tests height and depth
594        assert_eq!(cursor.depth(), 0);
595        assert_eq!(cursor.height(), 6);
596
597        // Tests num_children()
598        assert_eq!(cursor.num_children(), 2); // Root has [Landlocked, Islands]
599
600        // Tests children(), jump(), and get_data()
601        let kids = cursor.children();
602        let mut kids_iter = kids.iter();
603
604        // Moves to first child "Landlocked"
605        cursor.jump(kids_iter.next().unwrap());
606        {
607            let data = cursor.get_data().unwrap();
608            assert_eq!(*data.title, "Landlocked".to_string());
609        }
610        assert_eq!(cursor.depth(), 1);
611        assert_eq!(cursor.height(), 5);
612
613        // Moves to second child "Islands"
614        cursor.jump(kids_iter.next().unwrap());
615        let curr: Position<Heading> = cursor.current().clone(); // Passes the torch
616        {
617            let data = cursor.get_data().unwrap();
618            assert_eq!(*data.title, "Islands".to_string());
619        }
620        assert_eq!(cursor.depth(), 1);
621        assert_eq!(cursor.height(), 3);
622
623        // Jumps down a generation to [Marine, Fresh Water]
624        cursor.jump(&curr);
625        {
626            let new_kids = cursor.children();
627            let mut kids_iter = new_kids.iter();
628            cursor.jump(kids_iter.next().unwrap()); // Moves to first child
629            let data = cursor.get_data().unwrap();
630            assert_eq!(*data.title, "Marine".to_string());
631        }
632        // tests height and depth
633        assert_eq!(cursor.depth(), 2);
634        assert_eq!(cursor.height(), 2);
635
636        // Jumps down a generation, for fun
637        let new_kids = cursor.children(); // Gets cursor's chidlren
638        let mut kids_iter = new_kids.iter(); // Creates an iterator
639        cursor.jump(kids_iter.next().unwrap()); // Moves to first child
640        {
641            let data = cursor.get_data().unwrap();
642            assert_eq!(*data.title, "Australia".to_string());
643        }
644        assert_eq!(cursor.depth(), 3);
645        assert_eq!(cursor.height(), 1);
646
647        // Tests ascend()
648        assert!(cursor.ascend().is_ok()); // Marine
649        assert!(cursor.ascend().is_ok()); // Islands
650        {
651            let data = cursor.get_data().unwrap();
652            assert_eq!(*data.title, "Islands".to_string());
653        }
654        assert!(cursor.ascend().is_ok()); // []
655        assert!(cursor.ascend().is_err()); // Cannot ascend() past root
656        assert!(cursor.is_root()); // Double checks, just in case
657        assert_eq!(cursor.depth(), 0);
658        assert_eq!(cursor.height(), 6);
659
660        // Descends to Islands to test delete()
661        let kids = cursor.children(); // Gets cursor's chidlren
662        let mut kids_iter = kids.iter(); // Creates an iterator
663        cursor.jump(kids_iter.next().unwrap()); // Moves to Landlocked
664        cursor.jump(kids_iter.next().unwrap()); // Moves to Islands
665        {
666            let data = cursor.get_data().unwrap();
667            assert_eq!(*data.title, "Islands".to_string());
668        }
669
670        // Tests delete()
671        // Creates placeholder Heading
672        let mut deleted = Heading {
673            title: String::new(),
674            level: 0,
675        };
676        // Iterates through the child position's under the cursor
677        // looking for a matching Heading; Once found, jumps to that position,
678        // and deletes the Heading; The delete() operation automatically jumps
679        // the cursor to the parent of the deleted position
680        for position in cursor.children().iter() {
681            if position.get_data().unwrap().title == "Marine" {
682                cursor.jump(position);
683                deleted = cursor.delete().unwrap();
684            }
685        }
686        // Tests that the correct Heading was deleted
687        assert_eq!(deleted.level, 3);
688        assert_eq!(deleted.title, "Marine".to_string());
689
690        // Tests that the cursor got bumped up to Islands
691        let data = cursor.get_data().unwrap();
692        assert_eq!(data.title, "Islands".to_string());
693
694        // Tests that the Islands node has the correct children
695        let mut kids = Vec::new();
696        assert_eq!(cursor.children().len(), 2);
697        for child in cursor.children().iter() {
698            let title = child.get_data().unwrap().title.clone();
699            kids.push(title)
700        }
701        assert_eq!(kids, ["Fresh Water".to_string(), "Australia".to_string()]);
702    }
703
704    #[test]
705    fn dangle() {
706        use super::{GenTree, Position};
707        let one = vec![
708            Heading {
709                level: 1,
710                title: "Landlocked".to_string(),
711            },
712            Heading {
713                level: 2,
714                title: "Switzerland".to_string(),
715            },
716        ];
717        let two = vec![
718            Heading {
719                level: 1,
720                title: "Bolivia".to_string(),
721            },
722            Heading {
723                level: 2,
724                title: "Zimbabwe".to_string(),
725            },
726        ];
727
728        // Creates a tree, Position, and CursorMut
729        let mut outer_tree: GenTree<Heading> = construct(0, one.clone());
730        let mut _pos: Position<Heading> = outer_tree.root();
731        let mut cursor = outer_tree.cursor_mut();
732
733        {
734            let inner_tree: GenTree<Heading> = construct(0, two.clone());
735            _pos = inner_tree.root();
736            cursor.jump(&_pos);
737        }
738
739        // No more UB!!
740        cursor.get_data();
741        _pos.get_data();
742
743        // Creates a tree, Position, and CursorMut
744        let mut outer_tree: GenTree<Heading> = construct(0, one);
745        let mut pos: Position<Heading> = outer_tree.root();
746        let mut cursor = outer_tree.cursor_from(pos);
747
748        {
749            let inner_tree: GenTree<Heading> = construct(0, two);
750            pos = inner_tree.root();
751            cursor.jump(&pos);
752        }
753
754        // No more UB!!
755        cursor.get_data();
756        _pos.get_data();
757    }
758}