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