uniplate/traits/
context.rs

1//! The underlying iterator for `Uniplate::context()`
2
3use std::sync::Arc;
4
5use crate::zipper::{Zipper, ZipperBi};
6
7use super::{Biplate, Uniplate};
8
9/// Iterator for `context`
10pub(super) struct ContextIter<T: Uniplate> {
11    zipper: Zipper<T>,
12    done: bool,
13}
14
15impl<T: Uniplate> ContextIter<T> {
16    pub(super) fn new(root: T) -> ContextIter<T> {
17        ContextIter {
18            zipper: Zipper::new(root),
19            done: false,
20        }
21    }
22}
23
24impl<T: Uniplate> Iterator for ContextIter<T> {
25    type Item = (T, Arc<dyn Fn(T) -> T>);
26
27    fn next(&mut self) -> Option<Self::Item> {
28        if self.done {
29            return None;
30        };
31        let node = self.zipper.focus().clone();
32        let zipper1 = self.zipper.clone();
33        let hole_fn = Arc::new(move |x| {
34            // TODO: if performance is still an issue, maybe we could make this a single call function
35            // (FnOnce) then we wouldn't need to clone as much?
36            let mut zipper2 = zipper1.clone();
37            zipper2.replace_focus(x);
38            zipper2.rebuild_root()
39        });
40
41        // prepare iterator for next element.
42        // try moving down or right. if we can't move up the tree until we can move right.
43        if self.zipper.go_down().is_none() {
44            while self.zipper.go_right().is_none() {
45                if self.zipper.go_up().is_none() {
46                    // at the top again, so this will be the last time we return a node
47                    self.done = true;
48                    break;
49                };
50            }
51        }
52
53        Some((node, hole_fn))
54    }
55}
56
57/// Iterator for `context_bi`
58pub(super) struct ContextIterBi<T: Uniplate, U: Biplate<T>> {
59    zipper: Option<ZipperBi<T, U>>,
60    done: bool,
61}
62
63impl<T: Uniplate, U: Biplate<T>> ContextIterBi<T, U> {
64    pub(super) fn new(root: U) -> ContextIterBi<T, U> {
65        ContextIterBi {
66            zipper: ZipperBi::new(root),
67            done: false,
68        }
69    }
70}
71
72impl<T: Uniplate, U: Biplate<T>> Iterator for ContextIterBi<T, U> {
73    type Item = (T, Arc<dyn Fn(T) -> U>);
74
75    fn next(&mut self) -> Option<Self::Item> {
76        if self.done {
77            return None;
78        };
79
80        let Some(zipper) = &mut self.zipper else {
81            return None;
82        };
83
84        let node = zipper.focus().clone();
85
86        let zipper1 = zipper.clone();
87        let hole_fn = Arc::new(move |x| {
88            // TODO: if performance is still an issue, maybe we could make this a single call function
89            // (FnOnce) then we wouldn't need to clone as much?
90            let mut zipper1 = zipper1.clone();
91            zipper1.replace_focus(x);
92            zipper1.rebuild_root()
93        });
94
95        // prepare iterator for next element.
96        // try moving down or right. if we can't move up the tree until we can move right.
97        if zipper.go_down().is_none() {
98            while zipper.go_right().is_none() {
99                if zipper.go_up().is_none() {
100                    // at the top again, so this will be the last time we return a node
101                    self.done = true;
102                    break;
103                };
104            }
105        }
106
107        Some((node, hole_fn))
108    }
109}