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}