1
//#![cfg(feature = "unstable")]
2

            
3
#![allow(clippy::type_complexity)]
4

            
5
use std::sync::Arc;
6

            
7
pub use super::Tree;
8
use im;
9
use im::vector;
10

            
11
pub trait Biplate<To>
12
where
13
    Self: Sized + Clone + Eq + Uniplate + 'static,
14
    To: Sized + Clone + Eq + Uniplate + 'static,
15
{
16
    /// Returns all the top most children of type to within from.
17
    ///
18
    /// If from == to then this function should return the root as the single child.
19
    fn biplate(&self) -> (Tree<To>, Box<dyn Fn(Tree<To>) -> Self>);
20

            
21
    /// Like descend but with more general types.
22
    ///
23
    /// If from == to then this function does not descend. Therefore, when writing definitions it
24
    /// is highly unlikely that this function should be used in the recursive case. A common
25
    /// pattern is to first match the types using descendBi, then continue the recursion with
26
    /// descend.
27

            
28
    fn descend_bi(&self, op: Arc<dyn Fn(To) -> To>) -> Self {
29
        let (children, ctx) = self.biplate();
30
        ctx(children.map(op))
31
    }
32

            
33
    // NOTE (niklasdewally): Uniplate does something different here, and  I don't know why. In
34
    // particular, it doesn't use structure (its version of tree.list()) at all here, and uses some
35
    // builder thing I don't understand. My children_bi and universe_bi work though, so this might
36
    // just be performance and Haskell related.
37
    //
38
    // https://github.com/ndmitchell/uniplate/blob/66a2c55a7de0f5d8b0e437479719469244e00fa4/Data/Generics/Uniplate/Internal/OperationsInc.hs#L189
39

            
40
    fn universe_bi(&self) -> im::Vector<To> {
41
        self.children_bi()
42
            .into_iter()
43
            .flat_map(|child| child.universe())
44
            .collect()
45
    }
46

            
47
    /// Returns the children of a type. If to == from then it returns the original element (in contrast to children).
48
    fn children_bi(&self) -> im::Vector<To> {
49
        self.biplate().0.list().0
50
    }
51

            
52
    fn transform_bi(&self, op: Arc<dyn Fn(To) -> To>) -> Self {
53
        let (children, ctx) = self.biplate();
54
        ctx(children.map(Arc::new(move |child| child.transform(op.clone()))))
55
    }
56
}
57

            
58
pub trait Uniplate
59
where
60
    Self: Sized + Clone + Eq + 'static,
61
{
62
    fn uniplate(&self) -> (Tree<Self>, Box<dyn Fn(Tree<Self>) -> Self>);
63

            
64
    fn descend(&self, op: Arc<dyn Fn(Self) -> Self>) -> Self {
65
        let (children, ctx) = self.uniplate();
66
        ctx(children.map(op))
67
    }
68

            
69
    /// Gest all children of a node, including itself and all children.
70
    fn universe(&self) -> im::Vector<Self> {
71
        let mut results = vector![self.clone()];
72
        for child in self.children() {
73
            results.append(child.universe());
74
        }
75
        results
76
    }
77

            
78
    /// Gets the direct children (maximal substructures) of a node.
79
    fn children(&self) -> im::Vector<Self> {
80
        let (children, _) = self.uniplate();
81
        children.list().0.clone()
82
    }
83

            
84
    /// Reconstructs the node with the given children.
85
    ///
86
    /// # Panics
87
    ///
88
    /// If there are a different number of children given as there were originally returned by
89
    /// children().
90
    fn with_children(&self, children: im::Vector<Self>) -> Self {
91
        // 1. Turn old tree into list.
92
        // 2. Check lists are same size.
93
        // 3. Use the reconstruction function given by old_children.list() to
94
        //   create a tree with the same structure but the new lists' elements .
95

            
96
        let (old_children, ctx) = self.uniplate();
97
        let (old_children_lst, rebuild) = old_children.list();
98
        if old_children_lst.len() != children.len() {
99
            panic!("with_children() given an unexpected amount of children");
100
        } else {
101
            ctx(rebuild(children))
102
        }
103
    }
104

            
105
    /// Applies the given rule to all nodes bottom up.
106
    fn transform(&self, f: Arc<dyn Fn(Self) -> Self>) -> Self {
107
        let (children, ctx) = self.uniplate();
108
        let f2 = f.clone(); // make another pointer to f for map.
109
        f(ctx(
110
            children.map(Arc::new(move |child| child.transform(f2.clone())))
111
        ))
112
    }
113

            
114
    /// Rewrites by applying a rule everywhere it can.
115
    fn rewrite(&self, f: Arc<dyn Fn(Self) -> Option<Self>>) -> Self {
116
        let (children, ctx) = self.uniplate();
117

            
118
        let f2 = f.clone(); // make another pointer to f for map.
119
        let new_children = children.map(Arc::new(move |child| child.rewrite(f2.clone())));
120

            
121
        match f(ctx(new_children.clone())) {
122
            None => ctx(new_children),
123
            Some(n) => n,
124
        }
125
    }
126
    /// Performs a fold-like computation on each value.
127
    ///
128
    /// Working from the bottom up, this applies the given callback function to each nested
129
    /// component.
130
    ///
131
    /// Unlike [`transform`](Uniplate::transform), this returns an arbitrary type, and is not
132
    /// limited to T -> T transformations. In other words, it can transform a type into a new
133
    /// one.
134
    ///
135
    /// The meaning of the callback function is the following:
136
    ///
137
    ///   f(element_to_fold, folded_children) -> folded_element
138
    fn cata<T>(&self, op: Arc<dyn Fn(Self, Vec<T>) -> T>) -> T {
139
        let children = self.children();
140
        (*op)(
141
            self.clone(),
142
            children.into_iter().map(|c| c.cata(op.clone())).collect(),
143
        )
144
    }
145
}