dsa_rust/hierarchies/
unsafe_linked_general_tree.rs

1#![allow(unused)]
2/*! An unsafe, linked, n-ary tree implementation
3
4# About
5Following classical DSA curricula, this implementation relies primarily on pointers for the structure's composition and navigation.
6
7See the module's companion [MD tree](`crate::hierarchies::unsafe_linked_general_tree::md_tree`) tool, which takes a Markdown document and prints a hierarchical tree diagram of its heading contents.
8
9# Design
10The base [GenTree] structure 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 raw pointers required to make the tree go brrr.
11
12The design makes heavy use of `unsafe` code via raw pointers. The module represents a two-fold exercise: writing recursive traversal functions and understanding Rust's ownership model well enough to avoid falling back on tricks such as reference counting ([std::rc::Rc]/[std::sync::Arc]) or arena-like allocation with safe indexing ([Vec]) to manage the structure's operations safely. 
13
14Notably, this structure enforces strict lifetime constraints on cursors and positions to lock them to the base tree allocation, utilizing Rust's variance rules to systematically prevent pointer dangling, cross-tree pointer smuggling, and use-after-free errors. 
15
16In addition to leveraging lifetimes for safety bounds, the module also uses [Cell] for interior mutability on [CursorMut]. This allows cursor navigation methods to retain immutable `&self` borrows for a more ergonomic API.
17*/
18
19use std::marker::PhantomData;
20use std::ptr::NonNull;
21
22/// Represents the actual data structure. Currently this struct only 
23/// has constructor methods to create a new tree and create new cursor 
24/// handles which provide the lion's share of tree operations.
25///
26/// See [module-level documentation](`crate::hierarchies::unsafe_linked_general_tree`) 
27/// for more details.
28pub struct GenTree<T> {
29    root: NonNull<Node<T>>, // Private for safety reasons
30}
31impl<T> Default for GenTree<T> {
32    fn default() -> Self {
33        Self::new()
34    }
35}
36impl<T> GenTree<T> {
37    /// Instantiates a new Tree with a default root
38    pub fn new() -> GenTree<T> {
39        // Allocate the root node on the heap and get a raw pointer to it
40        // SAFETY: Box::into_raw is guaranteed to return a valid,
41        // non-null pointer because Box::new panics rather than
42        // returning null on allocation failure.
43        let root_node = unsafe {
44            NonNull::new_unchecked(Box::into_raw(Box::new(Node {
45                //parent: std::ptr::null_mut(),
46                parent: None,
47                children: Vec::new(),
48                data: None, // Root starts empty
49            })))
50        };
51
52        GenTree { root: root_node }
53    }
54
55    pub fn is_empty(&self) -> bool {
56        // SAFETY: Even empty trees have an initialized root
57        unsafe { (*self.root.as_ptr()).children.len() == 0 }
58    }
59
60    /// Creates a `CursorMut<T>` starting at the tree's root
61    /// NOTE: The lifetime 'a is implicitly tied from `&'a mut self`
62    /// to the returned `CursorMut<'a, T>`
63    pub fn cursor_mut(&mut self) -> CursorMut<'_, T> {
64        // Safety: self.root was allocated in GenTree::new() and is guaranteed not to be null
65        //let non_null_root = unsafe { NonNull::new_unchecked(self.root) };
66        let non_null_root = self.root;
67
68        CursorMut {
69            node: Cell::new(non_null_root),
70            //tree: self,
71            _marker: PhantomData,
72        }
73    }
74
75    // SAFETY: Allows critical use-after-free errors!!
76    //pub fn cursor_mut_from(&mut self, node: NonNull<Node<T>>) -> CursorMut<'_, T> {
77    //    // Safety: self.root was allocated in GenTree::new() and is guaranteed not to be null
78    //    //let non_null_root = unsafe { NonNull::new_unchecked(self.root) };
79    //    let non_null_root = node;
80
81    //    CursorMut {
82    //        node: Cell::new(non_null_root),
83    //        tree: self,
84    //        _marker: PhantomData,
85    //    }
86    //}
87
88    /** Exposes a read-only Position at the root node */
89    fn root(&self) -> Position<'_, T> {
90        // Safety: self.root is guaranteed valid
91        //let non_null_root = unsafe { NonNull::new_unchecked(self.root) };
92        let non_null_root = self.root;
93        Position {
94            node: non_null_root,
95            _marker: PhantomData,
96        }
97    }
98}
99// Required because Rust doesn't automatically drop heap allocations for
100// raw pointers (NonNull<Node<T>>)
101impl<T> Drop for GenTree<T> {
102    fn drop(&mut self) {
103        // self.root: NonNull<Node<T>>
104        let mut stack = vec![];
105        let mut node = unsafe { Box::from_raw(self.root.as_ptr()) };
106        stack.append(&mut node.children);
107
108        // self.root: *mut T
109        //if self.root.is_null() {
110        //    return;
111        //}
112
113        //// Use an iterative stack-based teardown to prevent stack
114        //// overflows on deep trees
115        //let mut stack = vec![self.root];
116
117        while let Some(node_ptr) = stack.pop() {
118            unsafe {
119                // 1. Snatch the children vector out of the
120                // node before destroying it
121                //let mut current_node = Box::from_raw(node_ptr);
122                let mut current_node = Box::from_raw(node_ptr.as_ptr());
123
124                // 2. Push all child pointers onto our teardown stack
125                stack.append(&mut current_node.children);
126
127                // 3. current_node naturally goes out of scope
128                // here, freeing its allocation
129                // and dropping its inner data (T) safely.
130            }
131        }
132    }
133}
134
135/// Has no methods, but `Position` has methods to derive and create `Node`s.
136///
137/// See [module-level documentation](`crate::hierarchies::unsafe_linked_general_tree`) 
138/// for more details.
139#[derive(Clone)]
140pub struct Node<T> {
141    parent: Option<NonNull<Node<T>>>,
142    children: Vec<NonNull<Node<T>>>,
143    data: Option<T>,
144}
145
146/// The `Position` struct serves as the module's safe public handle to 
147/// individual nodes in the tree. This struct requires a shared 
148/// lifetime 'a tied to the underlying tree.
149///
150/// See [module-level documentation](`crate::hierarchies::unsafe_linked_general_tree`) 
151/// for more details.
152struct Position<'a, T> {
153    node: NonNull<Node<T>>,
154    _marker: PhantomData<&'a GenTree<T>>,
155}
156impl<'a, T> Position<'a, T> {
157    pub fn get_data(&self) -> Option<&T> {
158        unsafe { self.node.as_ref().data.as_ref() }
159    }
160
161    pub fn get_children(&self) -> Vec<Position<'a, T>> {
162        unsafe {
163            let v = &self.node.as_ref().children;
164            v.iter().map(|x| Position::from_ptr(*x)).collect()
165        }
166    }
167
168    // Internal utility for iterator
169    fn get_children_iter(&self) -> Vec<Position<'a, T>> {
170        unsafe {
171            let v = &self.node.as_ref().children;
172            v.iter().map(|x| Position::from_ptr(*x)).collect()
173        }
174    }
175
176    // Private for safety; aint nobody should have a NonNull ptr!
177    fn from_ptr(ptr: NonNull<Node<T>>) -> Position<'a, T> {
178        Position {
179            node: ptr,
180            _marker: PhantomData,
181        }
182    }
183
184    // SAFETY: Enables pointer smuggling
185    // A safe way to expose the underlying pointer for assert_eq!
186    //pub fn as_ptr(&self) -> NonNull<Node<T>> {
187    //    self.node
188    //}
189}
190// Implement Clone so "let curr = cursor.current().clone();" works
191impl<'a, T> Clone for Position<'a, T> {
192    fn clone(&self) -> Self {
193        Position {
194            node: self.node,
195            _marker: PhantomData,
196        }
197    }
198}
199
200use std::cell::Cell;
201
202/// CursorMut takes 'a to tie it to the tree's lifetime
203/// which prevents dangling pointers by gating scopes
204///
205/// See [module-level documentation](`crate::hierarchies::unsafe_linked_general_tree`) 
206/// for more details.
207pub struct CursorMut<'a, T> {
208    node: Cell<NonNull<Node<T>>>,
209    //tree: &'a mut GenTree<T>,
210    _marker: std::marker::PhantomData<&'a mut &'a ()>,
211}
212impl<'a, T> CursorMut<'a, T> {
213    // Utilities
214    ////////////
215
216    pub fn get_data(&self) -> Option<&T> {
217        //unsafe { self.node.as_ref().data.as_ref() }
218        unsafe { self.node.get().as_ref().data.as_ref() }
219    }
220
221    pub fn is_none(&self) -> bool {
222        //unsafe { self.node.as_ref().data.is_none() }
223        unsafe { self.node.get().as_ref().data.is_none() }
224    }
225
226    pub fn is_some(&self) -> bool {
227        !self.is_none()
228    }
229
230    pub fn num_children(&self) -> usize {
231        //unsafe { self.node.as_ref().children.len() }
232        unsafe { self.node.get().as_ref().children.len() }
233    }
234
235    fn current(&self) -> Position<'a, T> {
236        Position {
237            //node: self.node,
238            node: self.node.get(),
239            _marker: PhantomData,
240        }
241    }
242
243    //fn children(&self) -> Vec<Position<'a, T>> {
244    //    // SAFETY: All nodes should have a valid node.children()
245    //    unsafe {
246    //        //self.node.as_ref().children.iter()
247    //        self.node
248    //            .get()
249    //            .as_ref()
250    //            .children
251    //            .iter()
252    //            .map(|&ptr| Position {
253    //                //node: NonNull::new_unchecked(ptr),
254    //                node: ptr,
255    //                _marker: PhantomData,
256    //            })
257    //            .collect()
258    //    }
259    //}
260
261    // SAFETY: Breaks uniqueness invariants
262    //pub fn get_tree(&mut self) -> &mut GenTree<T> {
263    //    self.tree
264    //}
265
266    // Navigation
267    /////////////
268
269    // /// Uses Cell for interior mutability in order to retain signature semantics
270    // /// such that navigation methods retain &self borrows.
271    //pub fn jump(&self, pos: &Position<'a, T>) {
272    //    //self.node = pos.node;
273    //    self.node.update(|_| pos.node);
274    //}
275    // Updates to take mutable reference, for safety :)
276    //pub fn jump(&mut self, pos: &Position<'a, T>) {
277    //    //self.node = pos.node;
278    //    self.node.update(|_| pos.node);
279    //}
280
281    pub fn children_iter(&self) -> ChildIter<'a, T> {
282        ChildIter {
283            parent_ptr: self.node.get(),
284            index: 0,
285            _marker: PhantomData
286        }
287    }
288
289    /// Uses Cell for interior mutability in order to retain signature semantics
290    /// such that navigation methods retain &self borrows.
291    //pub fn ascend(&self) -> Result<(), &str> {
292    pub fn ascend(&mut self) -> Result<(), &str> {
293        unsafe {
294            //let parent_ptr = self.node.as_ref().parent;
295            let parent_ptr = self.node.get().as_ref().parent;
296            //if parent_ptr.is_none() {
297            //    Err("Cannot ascend past root")
298            //} else {
299            //    //self.node = NonNull::new_unchecked(parent_ptr);
300            //    //self.node = parent_ptr.unwrap();
301            //    self.node.update(|_| parent_ptr.unwrap());
302            //    Ok(())
303            //}
304            if let Some(val) = parent_ptr {
305                self.node.update(|_| val);
306                Ok(())
307            } else {
308                Err("Cannot ascend past root")
309            }
310        }
311    }
312
313    /// Uses a closure to descend to the correct child node.
314    /// Ex:
315    /// ```rust
316    /// ```
317    pub fn descend<F>(&mut self, predicate: F) -> Result<(), &str>
318    where
319        F: Fn(&T) -> bool,
320        T: 'a
321    {
322        // 1. Get the iterator of children
323        // 2. Find the first child that satisfies the predicate
324        // 3. Update 'self' (the cursor) to point to that child
325        
326        let target_child = self.children_iter()
327            .find(|&child| predicate(child));
328    
329        if let Some(node) = target_child {
330            // Here you update your internal cursor state.
331            // Assuming your cursor stores a pointer or reference:
332            //self.node = node; 
333            Ok(())
334        } else {
335            Err("No child found matching the criteria")
336        }
337    }
338    // Mutation
339    ///////////
340
341    /// Creates and adds a child `Node` to the position of the cursor, 
342    /// then moves the cursor to the new child `Node`.
343    pub fn add_child(&mut self, data: T) {
344        unsafe {
345            //let current_ptr = self.node.as_ptr();
346            let current_ptr = self.node.get();
347            //let new_node = Box::into_raw(Box::new(Node {
348            let new_node = NonNull::new_unchecked(Box::into_raw(Box::new(Node {
349                //parent: Some(current_ptr),
350                parent: Some(current_ptr),
351                children: Vec::new(),
352                data: Some(data),
353            })));
354            //self.node.as_mut().children.push(new_node);
355            self.node.get().as_mut().children.push(new_node);
356
357            // Sets the cursor to the new child node
358            self.node.set(new_node);
359        }
360    }
361
362    pub fn delete(&mut self) -> Option<T> {
363        unsafe {
364            //let current_ptr = self.node.as_ptr();
365            let current_ptr = self.node.get();
366            //let parent_ptr = self.node.as_ref().parent;
367            let parent_ptr = self.node.get().as_ref().parent;
368
369            //if parent_ptr.is_null() {
370            //if parent_ptr.is_none() {
371            //    return None;
372            //}
373            parent_ptr?;
374
375            //let parent = &mut *parent_ptr;
376            let parent = parent_ptr.unwrap().as_mut();
377
378            if let Some(pos) = parent.children.iter().position(|&x| x == current_ptr) {
379
380                parent.children.remove(pos);
381
382                //let mut orphans = std::mem::take(&mut self.node.as_mut().children);
383                let mut orphans = std::mem::take(&mut self.node.get().as_mut().children);
384                for &orphan in &orphans {
385                    //(*orphan).parent = parent_ptr;
386                    (*orphan.as_ptr()).parent = parent_ptr;
387                }
388                parent.children.append(&mut orphans);
389            }
390
391            //self.node = NonNull::new_unchecked(parent_ptr);
392            //self.node = parent_ptr.unwrap();
393            self.node = Cell::new(parent_ptr.unwrap());
394
395            //let boxed_node = Box::from_raw(current_ptr);
396            let boxed_node = Box::from_raw(current_ptr.as_ptr());
397            boxed_node.data
398        }
399    }
400}
401pub struct ChildIter<'a, T> {
402    // pub struct Node<T> {
403    //    parent: Option<NonNull<Node<T>>>,
404    //    children: Vec<NonNull<Node<T>>>,
405    //    data: Option<T>,
406    //}
407    parent_ptr: NonNull<Node<T>>,
408    index: usize,
409    // Ensures correct lifetime tracking
410    _marker: std::marker::PhantomData<&'a T>,
411}
412impl<'a, T> Iterator for ChildIter<'a, T> {
413
414    // Yields raw mutable pointers to the children so you can use them to move the cursor
415    type Item = &'a T;
416
417    fn next(&mut self) -> Option<Self::Item> {
418        unsafe {
419            let parent_ref = self.parent_ptr.as_ref();
420            let child = parent_ref.children.get(self.index).copied();
421            match child {
422                Some(val) => {
423                    self.index += 1;
424                    Some(val.as_ref().data.as_ref().unwrap())
425                }
426                None => None
427            }
428        }
429    }
430}
431
432#[cfg(test)]
433mod tests {
434
435    use super::*;
436
437    #[test]
438    /** Creates this tree to test properties
439        []
440        ├── Landlocked
441        │   ├── Switzerland
442        │   │   └── Geneva
443        │   │       └── Old Town
444        │   │           └── Cathédrale Saint-Pierre
445        │   └── Bolivia
446        │       └── []
447        │           └── []
448        │               ├── Puerta del Sol
449        │               └── Puerta de la Luna
450        └── Islands
451            ├── Marine
452            │   └── Australia
453            └── Fresh Water
454    */
455    fn basic() {
456        //use super::{md_tree, md_tree::Heading, GenTree, Position};
457        use crate::hierarchies::unsafe_linked_general_tree::{md_tree, md_tree::Heading};
458        use crate::hierarchies::unsafe_linked_general_tree::{GenTree, Position};
459        let tree_vec = vec![
460            Heading {
461                level: 2,
462                title: "Landlocked".to_string(),
463            },
464            Heading {
465                level: 3,
466                title: "Switzerland".to_string(),
467            },
468            Heading {
469                level: 4,
470                title: "Geneva".to_string(),
471            },
472            Heading {
473                level: 5,
474                title: "Old Town".to_string(),
475            },
476            Heading {
477                level: 6,
478                title: "Cathédrale Saint-Pierre".to_string(),
479            },
480            Heading {
481                level: 3,
482                title: "Bolivia".to_string(),
483            },
484            Heading {
485                level: 6,
486                title: "Puerta del Sol".to_string(),
487            },
488            Heading {
489                level: 6,
490                title: "Puerta de la Luna".to_string(),
491            },
492            Heading {
493                level: 2,
494                title: "Islands".to_string(),
495            },
496            Heading {
497                level: 3,
498                title: "Marine".to_string(),
499            },
500            Heading {
501                level: 4,
502                title: "Australia".to_string(),
503            },
504            Heading {
505                level: 3,
506                title: "Fresh Water".to_string(),
507            },
508        ];
509
510        // Constructs tree ignoring the first heading
511        let mut tree: GenTree<Heading> = md_tree::construct(1, tree_vec);
512
513        ////////////////////////////
514        // TESTS CURSOR FUNCTIONS //
515        ////////////////////////////
516
517//        let mut cursor = tree.cursor_mut();
518//        // Tests that root is empty with is_some() and is_none()
519//        assert!(!cursor.is_some());
520//        assert!(cursor.is_none());
521//        // Tests root() -> Position<T>
522//        assert_eq!(cursor.node.as_ptr().ok(), tree.root().as_ptr().ok());
523//        assert_eq!(cursor.node.as_ptr().ok(), tree.root().as_ptr().ok());
524//
525//        // Tests num_children()
526//        assert_eq!(cursor.num_children(), 2); // Root has [Landlocked, Islands]
527//        
528//        // Tests children(), jump(), and get_data()
529//        let kids = cursor.children();
530//        let mut kids_iter = kids.iter();
531//        let root: Option<&Heading> = cursor.children_iter().next();
532//        assert_eq!(*root.unwrap().title, "Landlocked".to_string());
533//
534//        //cursor.jump(kids_iter.next().unwrap()); // Moves to first child
535//        let curr: Position<Heading> = cursor.current().clone(); // Passes the torch
536//        let data = cursor.get_data().unwrap();
537//        assert_eq!(*data.title, "Islands".to_string());
538//
539//        // Jumps down a generation to [Marine, Fresh Water]
540//        cursor.jump(&curr);
541//        let new_kids = cursor.children();
542//        let mut kids_iter = new_kids.iter();
543//        cursor.jump(kids_iter.next().unwrap()); // Moves to first child
544//        let data = cursor.get_data().unwrap();
545//        assert_eq!(*data.title, "Marine".to_string());
546//
547//        // Jumps down a generation, for fun
548//        let new_kids = cursor.children(); // Gets cursor's chidlren
549//        let mut kids_iter = new_kids.iter(); // Creates an iterator
550//        cursor.jump(kids_iter.next().unwrap()); // Moves to first child
551//        let data = cursor.get_data().unwrap();
552//        assert_eq!(*data.title, "Australia".to_string());
553//
554//        // Tests ascend()
555//        assert!(cursor.ascend().is_ok()); // Marine
556//        assert!(cursor.ascend().is_ok()); // Islands
557//        let data = cursor.get_data().unwrap();
558//        assert_eq!(*data.title, "Islands".to_string());
559//        assert!(cursor.ascend().is_ok()); // []
560//        assert!(cursor.ascend().is_err()); // Cannot ascend() past root
561//                                           //assert!(cursor.is_root()); // Double checks, just in case
562//
563//        // Descends to Islands to test delete()
564//        let kids = cursor.children(); // Gets cursor's chidlren
565//        let mut kids_iter = kids.iter(); // Creates an iterator
566//        cursor.jump(kids_iter.next().unwrap()); // Moves to Landlocked
567//        cursor.jump(kids_iter.next().unwrap()); // Moves to Islands
568//        let data = cursor.get_data().unwrap();
569//        assert_eq!(*data.title, "Islands".to_string());
570//
571//        // Tests delete()
572//        // Creates placeholder Heading
573//        let mut deleted = Heading {
574//            title: String::new(),
575//            level: 0,
576//        };
577//        // Iterates through the child position's under the cursor
578//        // looking for a matching Heading; Once found, jumps to that position,
579//        // and deletes the Heading; The delete() operation automatically jumps
580//        // the cursor to the parent of the deleted position
581//        for position in cursor.children() {
582//            if position.get_data().unwrap().title == "Marine" {
583//                //cursor.jump(&position);
584//                deleted = cursor.delete().unwrap();
585//            }
586//        }
587//        // Tests that the correct Heading was deleted
588//        assert_eq!(deleted.level, 3);
589//        assert_eq!(deleted.title, "Marine".to_string());
590//
591//        // Tests that the cursor got bumped up to Islands
592//        let data = cursor.get_data().unwrap();
593//        assert_eq!(data.title, "Islands".to_string());
594//
595//        // Tests that the Islands node has the correct children
596//        let mut kids = Vec::new();
597//        assert_eq!(cursor.children().len(), 2);
598//        for child in cursor.children() {
599//            let title = child.get_data().unwrap().title.clone();
600//            kids.push(title)
601//        }
602//        assert_eq!(kids, ["Fresh Water".to_string(), "Australia".to_string()]);
603
604        // Print debug, uncomment panic to print
605        md_tree::pretty_print("TEST", &tree);
606        //panic!();
607    }
608
609    // Pointer smuggling & (lifetime) covariance holes
610    //////////////////////////////////////////////////
611
612    #[test]
613    #[allow(unused)]
614    fn test_use_after_free() {
615
616        // 1) 
617        // This test verifies that the `_marker: PhantomData<&'a mut &'a ()>`
618        // successfully enforces invariance on CursorMut.
619        // If your invariance fix works perfectly, THIS TEST MUST FAIL TO COMPILE.
620        use crate::hierarchies::unsafe_linked_general_tree::{md_tree, md_tree::Heading};
621        use crate::hierarchies::unsafe_linked_general_tree::{GenTree, Position};
622        let one = vec![
623            Heading {
624                level: 1,
625                title: "Landlocked".to_string(),
626            },
627            Heading {
628                level: 2,
629                title: "Switzerland".to_string(),
630            },
631        ];
632        let two = vec![
633            Heading {
634                level: 1,
635                title: "Bolivia".to_string(),
636            },
637            Heading {
638                level: 2,
639                title: "Zimbabwe".to_string(),
640            },
641        ];
642
643        let mut outer_tree: GenTree<Heading> = md_tree::construct(0, one);
644        let cursor = outer_tree.cursor_mut();
645        {
646            //let inner_tree: GenTree<String> = GenTree::new();
647            let inner_tree: GenTree<Heading> = md_tree::construct(0, two);
648            // COMPILER ERROR EXPECTED HERE:
649            // inner_tree does not live long enough. Invariance stops the compiler
650            // from shrinking `cursor`'s lifetime to match `inner_tree`.
651            let inner_pos = inner_tree.root();
652            //cursor.jump(&inner_pos); // Illegal with multiple mutable borrows
653        }
654        // If it compiled, this would be a use-after-free,
655        // but its illegal because CursorMut is invariant
656        cursor.get_data(); 
657
658        // CRITICAL ERROR: solved
659        let mut tree1: GenTree<&str> = GenTree::new();
660        let mut tree2: GenTree<&str> = GenTree::new();
661        let pos1: Position<'_, _> = tree1.cursor_mut().current();
662        //let ptr = pos1.as_ptr(); // Allows pointer smuggling
663        drop(tree1);
664        //let pos2 = tree2.cursor_mut_from(ptr); // Illegal pointer smuggling
665        let pos2 = tree2.cursor_mut(); // Legal
666        let _ = pos2.get_data(); // Avoided use-after-free
667
668        // CRITICAL ERROR: pending
669        let mut tree: GenTree<i32> = GenTree::new();
670        let mut cursor = tree.cursor_mut();
671        cursor.add_child(42);
672        // Navigate to child and capture its Position
673        //let child_pos = cursor.children()[0].clone();
674        //cursor.jump(&child_pos);
675        // Assert data is there
676        assert_eq!(cursor.get_data(), Some(&42));
677        //assert_eq!(child_pos.get_data(), Some(&42));
678        // Now drop/delete the current node using &mut self mutation
679        let deleted_data = cursor.delete();
680        assert_eq!(deleted_data, Some(42));
681        // cursor.delete() must internally reset cursor.node to a safe fallback
682        // such as the parent node or the tree's root. Otherwise this triggers UB
683        // by pointing to the freed node.
684        cursor.get_data();
685        // SAFETY: The borrow checker cannot protect child_pos from becoming stale
686        // because it has the same lifetime as the cursor and the tree itself. 
687        // This is an inherent risk of keeping long-lived Positions. 
688        // Consider removing Position or adding some reference counting?
689        //let _ = child_pos.get_data(); // Expected Miri error if unhandled
690    }
691
692    #[test]
693    fn test_ascend_past_deleted_parent() {
694        // Illegal out-of-bounds indexing!
695        //let i: usize = Vec::new()[0];
696        //assert_eq!(i, 0);
697
698        let mut tree: GenTree<&str> = GenTree::new();
699        let mut cursor = tree.cursor_mut();
700
701        cursor.add_child("parent");
702        //let parent_pos = cursor.children()[0].clone();
703        //cursor.jump(&parent_pos);
704
705        cursor.add_child("child");
706        //let child_pos = cursor.children()[0].clone();
707
708        // Delete parent node while cursor is aware
709        //cursor.jump(&parent_pos);
710        cursor.delete();
711
712        // Reposition cursor to the child (if it was preserved/re-linked)
713        // Verify that ascend safely handles situations where raw pointers are invalidated
714        //cursor.jump(&child_pos);
715        if let Err(e) = cursor.ascend() {
716            assert_eq!(e, "Cannot ascend past root"); // Or your custom orphan error handler
717        }
718    }
719
720    // Null pointer dereferences & bounds testing
721    /////////////////////////////////////////////
722
723    #[test]
724    fn test_ascend_past_root_error_handling() {
725        let mut tree: GenTree<f64> = GenTree::new();
726        let mut cursor = tree.cursor_mut();
727
728        // Verify root node has no parent and safely returns Err instead of null deref
729        let result = cursor.ascend(); // Illegal multiple mutable borrow
730        assert!(result.is_err());
731        assert_eq!(result.unwrap_err(), "Cannot ascend past root");
732    }
733
734    #[test]
735    fn test_empty_root_data_handling() {
736        let tree: GenTree<i32> = GenTree::new();
737        let root_pos = tree.root();
738
739        // Verify the un-initialized data option returns None safely without a null deref
740        assert_eq!(root_pos.get_data(), None);
741    }
742
743    // Memory aliasing & vector invalidations
744    /////////////////////////////////////////
745
746    #[test]
747    fn test_children_vector_reallocation_aliasing() {
748        let mut tree: GenTree<usize> = GenTree::new();
749        let mut cursor = tree.cursor_mut();
750
751        // Collect positions of children
752        cursor.add_child(1);
753        //let first_child_pos = cursor.children()[0].clone();
754
755        // Mass-push items to force the internal Vec<NonNull<Node<T>>> to reallocate
756        // its capacity, moving its backing buffer elsewhere in memory.
757        for i in 2..100 {
758            cursor.add_child(i);
759        }
760
761        // Verify that tracking pointers remain valid or that the tree layout
762        // does not break parental pointer linkage due to backing array growth.
763        //cursor.jump(&first_child_pos);
764        //assert_eq!(cursor.get_data(), Some(&1));
765        assert_eq!(cursor.get_data(), Some(&99));
766    }
767
768    #[test]
769    fn test_mut_exclusivity() {
770        // Enforces that structural adjustments cannot happen if read-only structures
771        // are actively interacting across restricted blocks.
772        let mut tree: GenTree<char> = GenTree::new();
773
774        {
775            let mut cursor = tree.cursor_mut();
776            cursor.add_child('A');
777        } // cursor drops here, relinquishing exclusive access to tree
778
779        let root_pos = tree.root();
780        assert_eq!(root_pos.get_data(), None);
781
782        // This line would fail to compile if root_pos held a mutable borrow,
783        // confirming that shared read-only states don't collide with subsequent allocations.
784        let mut _cursor_two = tree.cursor_mut();
785    }
786}
787
788pub mod md_tree {
789/*! A handy little tool to create tree diagrams from MD headings
790
791# About
792This module sits on top of the [GenTree](`crate::hierarchies::unsafe_linked_general_tree`) structure and contains five functions:
793- A top-level [navigator] function that takes a [Path] and a level setting to indicate the level that the output drawing should start at
794- A [parse] function that takes a [Path] and outputs a list of headings
795- A [construct] function that builds the `GenTree`
796- A [pretty_print] function that traverses the tree and prints the contents to terminal
797
798The overall output should look something like this,
799```text
800📄 /document.md
801802    ├── Landlocked
803    │    ├── Switzerland
804    │    │    └── Geneva
805    │    │        └── Old Town
806    │    │            └── Cathédrale Saint-Pierre
807    │    └── Bolivia
808    │        └── []
809    │            └── []
810    │                ├── Puerta del Sol
811    │                └── Puerta de la Luna
812    └── Islands
813        ├── Fresh Water
814        └── Australia
815```
816
817# Design
818This is mostly just an excuse to write recursive tree traversal functions. All functions but the parsing function utilize recursion.
819
820**/
821
822    use regex::Regex;
823    use std::fs::File;
824    use std::io::{BufRead, BufReader};
825
826    //use crate::hierarchies::unsafe_linked_general_tree::{CursorMut, GenTree};
827    use crate::hierarchies::unsafe_linked_general_tree::{GenTree, Position};
828    use std::path::Path;
829
830    #[derive(Debug, PartialEq)]
831    pub struct Heading {
832        pub level: usize,
833        pub title: String,
834    }
835    impl Heading {
836        /** Just a humble Heading md_tree */
837        fn new(title: String, level: usize) -> Heading {
838            Heading { level, title }
839        }
840    }
841
842    /** Takes a path to a Markdown file, parses it for title and headings,
843    and returns a tuple containing the document title and a vector of
844    headings.
845
846    Note: The document title portion of the tuple is specifically
847    designed for the Astro-formatted frontmatter of each MD document. */
848    fn parse(root: &Path) -> (String, Vec<Heading>) {
849        // Regex for capturing the title from front matter
850        let t = Regex::new(r"(?ms)^---.*?^title:\s*(.+?)\s*$.*?^---").unwrap();
851        let mut doc_title = String::new();
852        // Regex for capturing headings H1-H6 as #-######
853        let h = Regex::new(r"^(#{1,6})\s+(.*)").unwrap();
854        let mut headings: Vec<Heading> = Vec::new();
855
856        // Read input
857        let file_path = root;
858        let file = File::open(file_path).unwrap(); // TODO: Fix lazy error handling
859        let reader = BufReader::new(file);
860
861        // Read the entire file into a single string
862        // Imperative style
863        let mut content = String::new();
864        for line_result in reader.lines() {
865            let line = line_result.unwrap();
866            if !content.is_empty() {
867                content.push('\n');
868            }
869            content.push_str(&line);
870        }
871        // Functional style
872        //let content: String = reader
873        //    .lines()
874        //    .map(|l| l.unwrap())
875        //    .collect::<Vec<_>>()
876        //    .join("\n");
877
878        // Extract the document title
879        if let Some(captures) = t.captures(&content) {
880            let title = captures.get(1).unwrap().as_str();
881            doc_title.push_str(title);
882        }
883
884        // Parse headings line by line
885        for line in content.lines() {
886            if let Some(captures) = h.captures(line) {
887                let level = captures.get(1).unwrap().as_str().len();
888                let text = captures.get(2).unwrap().as_str().to_string();
889                headings.push(Heading { level, title: text });
890            }
891        }
892
893        (doc_title, headings)
894    }
895
896    /** Constructs a tree of Heading types */
897    pub fn construct(mut cur_level: usize, data: Vec<Heading>) -> GenTree<Heading> {
898        let mut tree: GenTree<Heading> = GenTree::<Heading>::new();
899        let mut cursor = tree.cursor_mut();
900
901        for node in data {
902            let data_level = node.level;
903
904            // Case 1: Add child directly (level increases by 1)
905            if data_level == cur_level + 1 {
906                cursor.add_child(node);
907
908                // Move the cursor to the new child
909                //let kids = cursor.children();
910                //cursor.jump(kids.last().unwrap());
911                cur_level += 1;
912            }
913            // Case 2: Add child for multi-generational skip downwards
914            // (level increses by n)
915            else if data_level > cur_level {
916                let diff = data_level - cur_level;
917                for _ in 1..diff {
918                    let empty = Heading::new("[]".to_string(), 0);
919                    cursor.add_child(empty);
920
921                    //let kids = cursor.children();
922                    //cursor.jump(kids.last().unwrap());
923                    cur_level += 1;
924                }
925                cursor.add_child(node);
926
927                //let kids = cursor.children();
928                //cursor.jump(kids.last().unwrap());
929                cur_level += 1;
930            }
931            // Case 3: Add sibling (level does not change)
932            else if data_level == cur_level {
933                cursor.ascend().ok(); // Back to parent
934                cursor.add_child(node);
935
936                // Move into new sibling to prepare for possible nested children
937                //let kids = cursor.children();
938                //cursor.jump(kids.last().unwrap());
939            }
940            // Case 4: Add child for multi-generational skip upwards
941            // (level decreases by n)
942            else {
943                let diff = cur_level - data_level;
944                // Ascend to the appropriate parent level (+1 for the current node itself)
945                for _ in 0..=diff {
946                    cursor.ascend().ok();
947                    cur_level -= 1;
948                }
949                cursor.add_child(node);
950
951                //let kids = cursor.children();
952                //cursor.jump(kids.last().unwrap());
953                cur_level += 1;
954            }
955        }
956        tree
957    }
958
959    // Dictates the print spacing for the tree drawing used in pretty_print
960    // and its recursive helper function
961    const SPACE: &str = "    ";
962
963    /// A wrapper for a recursive preorder(ish) traversal function;
964    /// Contains logic to print [] on empty trees for more appealing presentation
965    /// Takes a reference to the GenTree and pretty-prints its contents.
966    pub fn pretty_print(title: &str, tree: &GenTree<Heading>) {
967        // Grab a shared reference to the Position at the root node
968        let root_pos = tree.root();
969
970        if tree.is_empty() {
971            println!("📄 {title}\n{SPACE}[]\n"); // Empty trees
972        } else {
973            println!("📄 {title}\n{SPACE}│");
974            // Recursive helper function call
975            preorder(&root_pos, "");
976            println!();
977        }
978    }
979    /// Modified preorder traversal function that walks the tree
980    /// recursively printing each node's title and children with
981    /// appropriate box drawing components.
982    fn preorder(pos: &Position<'_, Heading>, prefix: &str) {
983        // Safely collect child positions. Because Position is Clone,
984        // this creates an array of independent pointers bound to the
985        // same tree lifetime.
986        let children = pos.get_children();
987
988        for (index, child_pos) in pos.get_children().iter().enumerate() {
989            if let Some(child_data) = child_pos.get_data() {
990                let (marker, next_prefix) = if index == children.len() - 1 {
991                    ("└── ", format!("{prefix}{SPACE}"))
992                } else {
993                    ("├── ", format!("{prefix}│{SPACE}"))
994                };
995                // Print the current node layout
996                println!("{SPACE}{}{}{}", prefix, marker, child_data.title);
997                // Safely recurse! No mutable re-borrows, no raw pointer
998                // smuggling. The compiler tracks the shared tree
999                // lifetime across the entire call stack.
1000                preorder(child_pos, &next_prefix);
1001            }
1002        }
1003    }
1004
1005    /** A recursive function that chains the module's utility functions to
1006    pretty-print a table of contents for each Markdown file in the specified
1007    directory; The is_file() path contains logic to build a tree from filtered
1008    values, skipping headers above the user-supplied level argument;
1009    The function also substitues the file name (if any) for all MD files
1010    not formatted with Astro's frontmatter */
1011    pub fn navigator(level: usize, path: &Path) {
1012        if path.is_dir() {
1013            for component in path.read_dir().expect("read_dir call failed") {
1014                let entry = component.expect("failure to deconstruct value");
1015                navigator(level, &entry.path()); // Recursive call
1016            }
1017        } else if path.is_file() {
1018            if let Some(ext) = path.extension() {
1019                match ext.to_str() {
1020                    Some("md") | Some("mdx") => {
1021                        println!("{}", path.display());
1022                        let parsed = parse(path);
1023                        let mut name: String = parsed.0;
1024                        if name.is_empty() {
1025                            if let Some(n) = path
1026                                .file_name()
1027                                .expect("Error extracting file name")
1028                                .to_str()
1029                            {
1030                                name = n.to_string()
1031                            }
1032                        }
1033                        let filtered = parsed.1.into_iter().filter(|h| h.level > level).collect();
1034                        let tree = construct(level, filtered);
1035                        pretty_print(&name, &tree);
1036                    }
1037                    _ => (),
1038                }
1039            }
1040        }
1041    }
1042}