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>;
}