1
pub trait Uniplate
2
where
3
    Self: Sized + Clone + Eq,
4
{
5
    #[allow(clippy::type_complexity)]
6
    fn uniplate(&self) -> (Vec<Self>, Box<dyn Fn(Vec<Self>) -> Self + '_>);
7

            
8
    /// Get all children of a node, including itself and all children.
9
    fn universe(self) -> Vec<Self> {
10
        let mut results = vec![self.clone()];
11
        for child in self.children() {
12
            results.append(&mut child.universe());
13
        }
14
        results
15
    }
16

            
17
    /// Get the DIRECT children of a node.
18
    fn children(self) -> Vec<Self> {
19
        self.uniplate().0
20
    }
21

            
22
    /// Apply the given rule to all nodes bottom up.
23
    fn transform(self, f: fn(Self) -> Self) -> Self {
24
        let (children, context) = self.uniplate();
25
        f(context(
26
            children.into_iter().map(|a| a.transform(f)).collect(),
27
        ))
28
    }
29

            
30
    /// Rewrite by applying a rule everywhere you can.
31
    fn rewrite(self, f: fn(Self) -> Option<Self>) -> Self {
32
        let (children, context) = self.uniplate();
33
        let node: Self = context(children.into_iter().map(|a| a.rewrite(f)).collect());
34

            
35
        f(node.clone()).unwrap_or(node)
36
    }
37

            
38
    /// Perform a transformation on all the immediate children, then combine them back.
39
    /// This operation allows additional information to be passed downwards, and can be used to provide a top-down transformation.
40
    fn descend(self, f: fn(Self) -> Self) -> Self {
41
        let (children, context) = self.uniplate();
42
        let children: Vec<Self> = children.into_iter().map(f).collect();
43

            
44
        context(children)
45
    }
46

            
47
    /// Perform a fold-like computation on each value.
48
    ///
49
    /// Working from the bottom up, this applies the given callback function to each nested
50
    /// component.
51
    ///
52
    /// Unlike [`transform`](Uniplate::transform), this returns an arbitrary type, and is not
53
    /// limited to T -> T transformations. In other words, it can transform a type into a new
54
    /// one.
55
    ///
56
    /// The meaning of the callback function is the following:
57
    ///
58
    ///   f(element_to_fold, folded_children) -> folded_element
59
    ///
60
    fn fold<T>(self, op: fn(Self, Vec<T>) -> T) -> T {
61
        op(
62
            self.clone(),
63
            self.children().into_iter().map(|c| c.fold(op)).collect(),
64
        )
65
    }
66

            
67
    /// Get the nth one holed context.
68
    ///
69
    /// A uniplate context for type T has holes where all the nested T's should be.
70
    /// This is encoded as a function Vec<T> -> T.
71
    ///
72
    /// On the other hand, the nth one-holed context has only one hole where the nth nested
73
    /// instance of T would be.
74
    ///
75
    /// Eg. for some type:
76
    /// ```ignore
77
    /// enum Expr {
78
    ///     F(A,Expr,A,Expr,A),
79
    ///     G(Expr,A,A)
80
    /// }
81
    /// ```
82
    ///
83
    /// The 1st one-holed context of `F` (using 0-indexing) would be:
84
    /// ```ignore
85
    /// |HOLE| F(a,b,c,HOLE,e)
86
    /// ```
87
    ///
88
    /// Used primarily in the implementation of Zippers.
89
    fn one_holed_context(&self, n: usize) -> Option<Box<dyn Fn(Self) -> Self + '_>> {
90
        let (children, context) = self.uniplate();
91
        let number_of_elems = children.len();
92

            
93
        if n >= number_of_elems {
94
            return None;
95
        }
96

            
97
        Some(Box::new(move |x| {
98
            let mut children = children.clone();
99
            children[n] = x;
100
            context(children)
101
        }))
102
    }
103
}