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//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(¤t);
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}