uniplate/zipper.rs
1//! Cursors into Uniplate types.
2//!
3//! A zipper is a cursor into a functional data structure. The cursor can be moved around the data
4//! structure, and the value at the cursor can be quickly updated.
5//!
6//! Zippers are particularly useful for mutating self-referential data structures. Updating the
7//! value at the cursor is O(1), regardless of its position inside the data structure.
8//!
9//! For this reason, Zippers should be used instead of [`contexts`](super::Uniplate::contexts) or
10//! [`contexts_bi`](super::Biplate::contexts_bi) if you plan to do a lot of mutation during
11//! traversal. These functions recreate the root node each time the context function is called,
12//! which has a logarithmic complexity.
13//!
14//! For more information, see:
15//!
16//! - [the original paper by Huet](https://www.st.cs.uni-saarland.de/edu/seminare/2005/advanced-fp/docs/huet-zipper.pdf)
17//!
18//! - [this explanatory blog post](https://pavpanchekha.com/blog/zippers/huet.html)
19
20use std::{collections::VecDeque, sync::Arc};
21
22use crate::{Biplate, Tree, Uniplate};
23
24/// A Zipper over `Uniplate` types.
25///
26/// See the module-level documentation.
27#[derive(Clone)]
28pub struct Zipper<T: Uniplate> {
29 /// The current node
30 focus: T,
31
32 /// The path back to the top, immediate parent last.
33 ///
34 /// If empty, the focus is the top level node.
35 path: Vec<PathSegment<T>>,
36}
37
38#[derive(Clone)]
39struct PathSegment<T: Uniplate> {
40 /// Left siblings of the node
41 left: VecDeque<T>,
42
43 /// Right siblings of the node
44 right: VecDeque<T>,
45
46 // A possibility was to store parent and use with_children instead of doing it by hand this
47 // way. However, that would store an old copy of the subtree we are currently in, which is
48 // unnecessary.
49 //
50 /// Function to convert this layer back into a tree given a full list of children
51 rebuild_tree: Arc<dyn Fn(VecDeque<T>) -> Tree<T>>,
52
53 // Function to create the parent node, given its children as a tree
54 ctx: Arc<dyn Fn(Tree<T>) -> T>,
55}
56
57impl<T: Uniplate> Zipper<T> {
58 /// Creates a new [`Zipper`] with `root` as the root node.
59 ///
60 /// The focus is initially the root node.
61 pub fn new(root: T) -> Self {
62 Zipper {
63 focus: root,
64 path: Vec::new(),
65 }
66 }
67
68 /// Borrows the current focus.
69 pub fn focus(&self) -> &T {
70 &self.focus
71 }
72
73 /// Mutably borrows the current focus.
74 pub fn focus_mut(&mut self) -> &mut T {
75 &mut self.focus
76 }
77
78 /// Replaces the focus of the [Zipper], returning the old focus.
79 pub fn replace_focus(&mut self, new_focus: T) -> T {
80 std::mem::replace(&mut self.focus, new_focus)
81 }
82
83 /// Rebuilds the root node, consuming the [`Zipper`].
84 pub fn rebuild_root(mut self) -> T {
85 while self.go_up().is_some() {}
86 self.focus
87 }
88
89 /// Returns the depth of the focus from the root.
90 pub fn depth(&self) -> usize {
91 self.path.len()
92 }
93
94 /// Returns the index of the focus among its siblings from left to right.
95 ///
96 /// Returns `None` if the focus is the root node.
97 pub(crate) fn siblings_index(&self) -> Option<usize> {
98 let path_segment = self.path.last()?;
99 Some(path_segment.left.len())
100 }
101
102 /// Sets the focus to the parent of the focus (if it exists).
103 pub fn go_up(&mut self) -> Option<()> {
104 let mut path_seg = self.path.pop()?;
105
106 // TODO: get rid of the clone if possible
107 path_seg.left.push_back(self.focus.clone());
108 path_seg.left.append(&mut path_seg.right);
109
110 let tree = (path_seg.rebuild_tree)(path_seg.left);
111
112 self.focus = (path_seg.ctx)(tree);
113
114 Some(())
115 }
116
117 /// Sets the focus to the left-most child of the focus (if it exists).
118 pub fn go_down(&mut self) -> Option<()> {
119 let (children, ctx) = self.focus.uniplate();
120 let (mut siblings, rebuild_tree) = children.list();
121 let new_focus = siblings.pop_front()?;
122 let new_segment = PathSegment {
123 left: VecDeque::new(),
124 right: siblings,
125 rebuild_tree: rebuild_tree.into(),
126 ctx: ctx.into(),
127 };
128
129 self.path.push(new_segment);
130 self.focus = new_focus;
131 Some(())
132 }
133
134 /// Sets the focus to the left sibling of the focus (if it exists).
135 pub fn go_left(&mut self) -> Option<()> {
136 let path_segment = self.path.last_mut()?;
137 let new_focus = path_segment.left.pop_front()?;
138 let old_focus = std::mem::replace(&mut self.focus, new_focus);
139 path_segment.right.push_back(old_focus);
140 Some(())
141 }
142
143 /// Sets the focus to the right sibling of the focus (if it exists).
144 pub fn go_right(&mut self) -> Option<()> {
145 let path_segment = self.path.last_mut()?;
146 let new_focus = path_segment.right.pop_front()?;
147 let old_focus = std::mem::replace(&mut self.focus, new_focus);
148 path_segment.left.push_back(old_focus);
149 Some(())
150 }
151
152 /// Returns an iterator over the left siblings of the focus, in left-right order.
153 pub fn iter_left_siblings(&self) -> impl Iterator<Item = &T> {
154 self.path
155 .last()
156 .map(|seg| seg.left.iter())
157 .into_iter()
158 .flatten()
159 }
160
161 /// Returns an iterator over the right siblings of the focus, in left-right order.
162 pub fn iter_right_siblings(&self) -> impl Iterator<Item = &T> {
163 self.path
164 .last()
165 .map(|seg| seg.right.iter())
166 .into_iter()
167 .flatten()
168 }
169
170 /// Returns an iterator over all nodes with the same parent as the focus, in left-right order.
171 ///
172 /// The iterator will yield left siblings first, then the focus, then right siblings.
173 pub fn iter_siblings(&self) -> impl Iterator<Item = &T> {
174 self.iter_left_siblings()
175 .chain(std::iter::once(self.focus()))
176 .chain(self.iter_right_siblings())
177 }
178
179 /// Returns an iterator over all ancestors of the focus, going upwards (parent to root).
180 ///
181 /// This is an expensive operation as it rebuilds each ancestor in sequence.
182 /// The returned ancestors will reflect any changes made so far during traversal in their subtrees.
183 pub fn iter_ancestors<'a>(&'a self) -> impl Iterator<Item = T> + 'a {
184 AncestorsIter {
185 zipper: self.clone(),
186 }
187 }
188}
189
190struct AncestorsIter<T: Uniplate> {
191 zipper: Zipper<T>,
192}
193
194impl<T: Uniplate> Iterator for AncestorsIter<T> {
195 type Item = T;
196
197 fn next(&mut self) -> Option<Self::Item> {
198 self.zipper.go_up().map(|_| self.zipper.focus.clone())
199 }
200}
201
202/// A Zipper over `Biplate` types.
203///
204/// A `ZipperBi<To,From>` traverses through all values of type `To` in a value of type `From`.
205///
206/// Unlike [`Zipper`], the root node can never be focused on (as it is not of type `To`). Instead,
207/// the initial node is the left-most child.
208///
209/// See the module-level documentation.
210#[derive(Clone)]
211pub struct ZipperBi<To: Uniplate, From: Biplate<To>> {
212 /// The current node
213 focus: To,
214
215 /// The path back to the top, immediate parent last.
216 ///
217 /// If empty, the focus is the top level node.
218 path: Vec<PathSegmentBi<To, From>>,
219}
220
221#[derive(Clone)]
222enum PathSegmentBi<To: Uniplate, From: Biplate<To>> {
223 /// The parent node is of type U, so need some slightly different types
224 Top {
225 /// Left siblings of the node
226 left: VecDeque<To>,
227
228 /// Right siblings of the node
229 right: VecDeque<To>,
230
231 /// Function to convert this layer back into a tree given a full list of children
232 rebuild_tree: Arc<dyn Fn(VecDeque<To>) -> Tree<To>>,
233
234 // Function to create the parent node, given its children as a tree
235 ctx: Arc<dyn Fn(Tree<To>) -> From>,
236 },
237
238 /// After the first level of the tree (where we call biplate), we use uniplate to traverse the
239 /// tree deeper.
240 ///
241 /// Same as [`PathSegment`]
242 Node {
243 /// Left siblings of the node
244 left: VecDeque<To>,
245
246 /// Right siblings of the node
247 right: VecDeque<To>,
248
249 /// Function to convert this layer back into a tree given a full list of children
250 rebuild_tree: Arc<dyn Fn(VecDeque<To>) -> Tree<To>>,
251
252 // Function to create the parent node, given its children as a tree
253 ctx: Arc<dyn Fn(Tree<To>) -> To>,
254 },
255}
256
257impl<To: Uniplate, From: Biplate<To>> ZipperBi<To, From> {
258 /// Creates a new [`ZipperBi`] with `root` as the root node.
259 ///
260 /// The focus is set to the left-most child of `root`.
261 ///
262 /// Returns `None` if the root node has no children of type `To`.
263 pub fn new(top: From) -> Option<Self> {
264 // we can never focus on the top level node, just its immediate children.
265
266 let (children, ctx) = top.biplate();
267 let (mut siblings, rebuild_tree) = children.list();
268 let focus = siblings.pop_front()?;
269 let segment = PathSegmentBi::Top {
270 left: VecDeque::new(),
271 right: siblings,
272 rebuild_tree: rebuild_tree.into(),
273 ctx: ctx.into(),
274 };
275
276 Some(ZipperBi {
277 focus,
278 path: vec![segment],
279 })
280 }
281
282 /// Borrows the current focus.
283 pub fn focus(&self) -> &To {
284 &self.focus
285 }
286
287 /// Mutably borrows the current focus.
288 pub fn focus_mut(&mut self) -> &mut To {
289 &mut self.focus
290 }
291
292 /// Replaces the focus, returning the old focus.
293 pub fn replace_focus(&mut self, new_focus: To) -> To {
294 std::mem::replace(&mut self.focus, new_focus)
295 }
296
297 /// Rebuilds the root node, consuming the [`ZipperBi`]
298 pub fn rebuild_root(mut self) -> From {
299 while self.go_up().is_some() {}
300
301 let Some(PathSegmentBi::Top {
302 mut left,
303 mut right,
304 rebuild_tree,
305 ctx,
306 }) = self.path.pop()
307 else {
308 // go_up should leave us with a single PathSegmentBi::Top in the path
309 unreachable!();
310 };
311
312 left.push_back(self.focus.clone());
313 left.append(&mut right);
314
315 let tree = (rebuild_tree)(left);
316
317 (ctx)(tree)
318 }
319
320 /// Returns the depth of the focus from the root.
321 pub fn depth(&self) -> usize {
322 self.path.len()
323 }
324
325 /// Sets the focus to the parent of the focus, if it exists and is of type `To.
326 ///
327 /// To get the topmost node (of type `From`), use [`rebuild_root`](ZipperBi::rebuild_root).
328 pub fn go_up(&mut self) -> Option<()> {
329 let Some(PathSegmentBi::Node {
330 left: _,
331 right: _,
332 rebuild_tree: _,
333 ctx: _,
334 }) = self.path.last()
335 else {
336 return None;
337 };
338
339 // the above ensures that we do not commit to the pop unless the let passes
340 let Some(PathSegmentBi::Node {
341 mut left,
342 mut right,
343 rebuild_tree,
344 ctx,
345 }) = self.path.pop()
346 else {
347 unreachable!();
348 };
349
350 // TODO: get rid of the clone if possible
351 left.push_back(self.focus.clone());
352 left.append(&mut right);
353
354 let tree = (rebuild_tree)(left);
355
356 self.focus = (ctx)(tree);
357
358 Some(())
359 }
360
361 /// Sets the focus to the left-most child of the focus (if it exists).
362 pub fn go_down(&mut self) -> Option<()> {
363 let (children, ctx) = self.focus.uniplate();
364 let (mut siblings, rebuild_tree) = children.list();
365 let new_focus = siblings.pop_front()?;
366 let new_segment = PathSegmentBi::Node {
367 left: VecDeque::new(),
368 right: siblings,
369 rebuild_tree: rebuild_tree.into(),
370 ctx: ctx.into(),
371 };
372
373 self.path.push(new_segment);
374 self.focus = new_focus;
375 Some(())
376 }
377
378 /// Sets the focus to the left sibling of the focus (if it exists).
379 pub fn go_left(&mut self) -> Option<()> {
380 let (left, right) = match self.path.last_mut()? {
381 PathSegmentBi::Top {
382 left,
383 right,
384 rebuild_tree: _,
385 ctx: _,
386 } => (left, right),
387 PathSegmentBi::Node {
388 left,
389 right,
390 rebuild_tree: _,
391 ctx: _,
392 } => (left, right),
393 };
394 let new_focus = left.pop_front()?;
395 let old_focus = std::mem::replace(&mut self.focus, new_focus);
396 right.push_back(old_focus);
397 Some(())
398 }
399
400 /// Sets the focus to the right sibling of the focus (if it exists).
401 pub fn go_right(&mut self) -> Option<()> {
402 let (left, right) = match self.path.last_mut()? {
403 PathSegmentBi::Top {
404 left,
405 right,
406 rebuild_tree: _,
407 ctx: _,
408 } => (left, right),
409 PathSegmentBi::Node {
410 left,
411 right,
412 rebuild_tree: _,
413 ctx: _,
414 } => (left, right),
415 };
416 let new_focus = right.pop_front()?;
417 let old_focus = std::mem::replace(&mut self.focus, new_focus);
418 left.push_back(old_focus);
419 Some(())
420 }
421}