1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
//! # Summary //! //! This crate provides a simple, non-intrusive tree cursor that supports node //! mutation without [`Cell`]/[`RefCell`]. //! //! # Soundness //! //! **In a nutshell: I don't know if this crate is sound. I *think* it is, but //! you should still check it yourself before using it.** //! //! The current implementation uses unsafe code to work around the borrow //! checker's strictness about lifetimes. So far, I haven't formally proven //! that it's memory-safe, especially in the presence of malicious code. I've //! done my best to write adversarial tests, and I'll continue poking at corner //! cases until I'm personally satisfied that it's sound, but it's not likely //! I'll get around to formally proving it until I better understand the borrow //! checker. //! //! # Concepts //! //! For the purposes of this crate... //! - a tree has exactly one root node (no tree is empty) //! - each node has zero or more children //! - "up" is toward the root //! - "down" is away from the root //! - at any point in time, a cursor has exactly one *active* node, also called //! the cursor's *position* //! //! # Guided tour //! //! Let's look at a simple tree and how you might use a cursor to traverse it. //! //! ``` //! use tree_cursor::cursor::TreeCursor; //! use tree_cursor::prelude::*; //! //! struct Node(&'static str, Vec<Node>); //! //! // This trait impl is used by TreeCursor::down to determine the next child //! // to visit. You can create a TreeCursor for something that doesn't //! // implement Down; you just won't be able to call TreeCursor::down. //! impl Down for Node { //! fn down(&self, idx: usize) -> Option<&Self> { //! // idx starts at 0 when we visit this node going downward and //! // increments every time we visit it going upward. This allows us //! // to visit each child in order by going back up to this node after //! // each one. //! self.1.get(idx) //! } //! } //! //! let foobar = Node("foo", vec![ //! Node("bar", vec![]), //! Node("zup", vec![]), //! ]); //! // foobar is a tree; its root, "foo", has two children, named "bar" and //! // "zup". //! //! let mut cur = TreeCursor::new(&foobar); //! assert_eq!(cur.get().0, "foo"); // The cursor starts at the root, "foo". //! // TreeCursor::get() returns a reference to the active node. //! //! assert!(cur.down()); //! // TreeCursor::down returns true if the position actually moved. //! assert_eq!(cur.get().0, "bar"); //! //! assert!(!cur.down()); //! // "bar" has no children so we can't move the cursor down. //! //! assert!(cur.up()); //! assert_eq!(cur.get().0, "foo"); // The cursor is at the root again. //! //! assert!(cur.down()); //! assert_eq!(cur.get().0, "zup"); //! //! assert!(cur.up()); //! assert_eq!(cur.get().0, "foo"); // Back at the root. //! //! assert!(!cur.down()); // No more children to visit. //! assert!(!cur.up()); // The root has no parent. //! ``` //! //! When the cursor is created, its initial position is at the root of the //! tree. [`down`] and [`up`] are two methods for repositioning the cursor. //! There are several methods besides [`down`] for moving down a tree; //! typically [`down`] is used when fully traversing a tree, as we just saw. //! Here are two ways you might do a full traversal if you don't know the //! tree's exact shape ahead of time: //! //! ``` //! # use tree_cursor::cursor::TreeCursor; //! # use tree_cursor::prelude::*; //! # //! # struct Node(&'static str, Vec<Node>); //! # //! # impl Down for Node { //! # fn down(&self, idx: usize) -> Option<&Self> { //! # self.1.get(idx) //! # } //! # } //! # //! # fn process_node(_: &Node) { } //! # //! fn process_tree_pre_order(root: &Node) { //! let mut cur = TreeCursor::new(root); //! 'outer: loop { //! process_node(cur.get()); //! while !cur.down() { //! if !cur.up() { break 'outer; } //! } //! } //! } //! //! fn process_tree_post_order(root: &Node) { //! let mut cur = TreeCursor::new(root); //! loop { //! while cur.down() { } //! process_node(cur.get()); //! if !cur.up() { break; } //! } //! } //! ``` //! //! When you need more complex behavior or when there's no particular order to //! a node's children, you can use the [`down_map`] method instead, passing it //! a closure that determines the next child to visit. //! //! # Mutability and node references //! //! [`TreeCursor`] is the immutable version of the tree cursor, meaning it //! holds a shared reference to the tree, preventing you from modifying the //! tree until the cursor goes out of scope. If you need to modify the tree, use //! [`TreeCursorMut`] instead, which gives you access to a mutable reference to //! the active node. //! //! By design, neither version of the tree cursor allows you to reposition it //! while you hold a reference to the active node. If this were allowed (by //! changing the lifetime of the return value of [`get`] and [`get_mut`]), a //! node that held its children in a [`Cell`] or [`RefCell`] could drop a child //! that still had live references, violating memory safety. //! //! [`Cell`]: std::cell::Cell //! [`RefCell`]: std::cell::RefCell //! //! [`TreeCursor`]: cursor::TreeCursor //! [`TreeCursorMut`]: cursor::TreeCursorMut //! [`down`]: cursor::TreeCursor::down //! [`down_map`]: cursor::TreeCursor::down_map //! [`up`]: cursor::TreeCursor::up //! [`get`]: cursor::TreeCursor::get //! [`get_mut`]: cursor::TreeCursorMut::get_mut pub mod cursor; pub mod prelude { pub use super::{Down, DownMut}; } #[cfg(test)] mod tests; pub trait Down { fn down(&self, idx: usize) -> Option<&Self>; } pub trait DownMut { fn down_mut(&mut self, idx: usize) -> Option<&mut Self>; }