1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
//! # Some utilities to ease the implementation of Visitor / Acceptor in rust
//!
//! Visited structure do not have to be trees, they can be simple Directed Acyclic Graphs (DAGs).
//! The `accept` code will make sure the same node is not visited more than once.
//!
//! Use this code whenever possible.
//!

use std::{
    cmp::{Eq, PartialEq},
    collections::HashMap,
    fmt::Debug,
    hash::Hash,
    iter,
    ops::{Deref, DerefMut},
    vec::Vec,
};

/// The list of other acceptors an acceptor is depending on
pub struct Dependencies<'a, A>(Vec<&'a A>);

impl<'a, A> Dependencies<'a, A> {
    pub fn new(dependencies: Vec<&'a A>) -> Self {
        Dependencies(dependencies)
    }

    pub fn empty() -> Self {
        Dependencies(vec![])
    }
}

impl<'a, A> Deref for Dependencies<'a, A> {
    type Target = Vec<&'a A>;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl<'a, A> DerefMut for Dependencies<'a, A> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}

impl<'a, A> IntoIterator for Dependencies<'a, A> {
    type Item = <Vec<&'a A> as IntoIterator>::Item;
    type IntoIter = <Vec<&'a A> as IntoIterator>::IntoIter;

    fn into_iter(self) -> Self::IntoIter {
        self.0.into_iter()
    }
}

impl<'a, A, B: AsRef<[&'a A]>> From<B> for Dependencies<'a, A> {
    fn from(value: B) -> Self {
        value.as_ref().iter().cloned().collect()
    }
}

impl<'a, A> FromIterator<&'a A> for Dependencies<'a, A> {
    fn from_iter<T: IntoIterator<Item = &'a A>>(iter: T) -> Self {
        let dependencies: Vec<&'a A> = iter.into_iter().collect();
        Dependencies::new(dependencies)
    }
}

/// The list of other acceptors an acceptor is depending on, with their visited values
pub struct Visited<'a, A: PartialEq, O>(Vec<(&'a A, O)>);

impl<'a, A: PartialEq, O> Visited<'a, A, O> {
    pub fn new() -> Self {
        Visited(vec![])
    }

    fn push(&mut self, acceptor: &'a A, output: O) {
        self.0.push((acceptor, output))
    }

    pub fn get(&self, acceptor: &'a A) -> &O {
        &self.iter().find(|(a, _)| a == &acceptor).unwrap().1
    }

    pub fn pop(&mut self, acceptor: &'a A) -> O {
        let index = self.0.iter().position(|(a, _)| a == &acceptor).unwrap();
        self.0.swap_remove(index).1
    }

    pub fn find<P: Fn(&'a A) -> bool>(&self, predicate: P) -> Option<&O> {
        self.iter().find(|(a, _)| predicate(a)).map(|(_, o)| o)
    }
}

impl<'a, A: PartialEq, O> Deref for Visited<'a, A, O> {
    type Target = Vec<(&'a A, O)>;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl<'a, A: PartialEq, O> DerefMut for Visited<'a, A, O> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}

impl<'a, A: PartialEq, O> IntoIterator for Visited<'a, A, O> {
    type Item = <Vec<(&'a A, O)> as IntoIterator>::Item;
    type IntoIter = <Vec<(&'a A, O)> as IntoIterator>::IntoIter;

    fn into_iter(self) -> Self::IntoIter {
        self.0.into_iter()
    }
}

/// A generic visitor
pub trait Visitor<'a, A: Acceptor<'a>, O: Clone> {
    /// A function called on each node of a structured object with its dependencies already visited
    fn visit(&self, acceptor: &'a A, dependencies: Visited<'a, A, O>) -> O;
    /// Describe the dependencies of the acceptor
    /// The dependencies can be customized
    fn dependencies(&self, acceptor: &'a A) -> Dependencies<'a, A> {
        acceptor.dependencies()
    }
}
/// The identity Visitor
pub struct Identity;

impl<'a, A: Acceptor<'a>> Visitor<'a, A, &'a A> for Identity {
    fn visit(&self, acceptor: &'a A, _dependencies: Visited<'a, A, &'a A>) -> &'a A {
        acceptor
    }
}

pub type Iter<'a, A> =
    iter::FilterMap<Iterator<'a, &'a A, Identity, A>, fn((&'a A, State<&'a A>)) -> Option<&'a A>>;

pub type IterWith<'a, O, A, V> =
    iter::FilterMap<Iterator<'a, O, V, A>, fn((&'a A, State<O>)) -> Option<(&'a A, O)>>;

/// A generic acceptor trait
pub trait Acceptor<'a>: 'a + Sized + Debug + Eq + Hash {
    /// All the sub-objects to visit
    fn dependencies(&'a self) -> Dependencies<'a, Self>;

    fn accept<O: Clone, V: Visitor<'a, Self, O>>(&'a self, visitor: V) -> O {
        let mut state = State::Push;
        for (_a, s) in Iterator::new(visitor, self) {
            state = s
        }
        if let State::Accept(output) = state {
            output.clone()
        } else {
            panic!()
        }
    }

    fn iter(&'a self) -> Iter<'a, Self> {
        Iterator::new(Identity, self).filter_map(|(_a, s)| match s {
            State::Accept(o) => Some(o),
            _ => None,
        })
    }

    fn iter_with<O: Clone, V: Visitor<'a, Self, O>>(
        &'a self,
        visitor: V,
    ) -> IterWith<'a, O, Self, V> {
        Iterator::new(visitor, self).filter_map(|(a, s)| match s {
            State::Accept(o) => Some((a, o)),
            _ => None,
        })
    }
}

#[derive(Clone, Debug, PartialEq)]
pub enum State<O> {
    Push,
    Visit,
    Accept(O),
}

pub struct Iterator<'a, O: Clone, V: Visitor<'a, A, O>, A: Acceptor<'a>> {
    stack: Vec<&'a A>,
    state: HashMap<&'a A, State<O>>,
    visitor: V,
}

/// A visitor iterator implements roughly [DFS](https://en.wikipedia.org/wiki/Topological_sorting)
/// Acceptor, when submitted for visit are checked:
/// - if already accepted, nothing happens
/// - if already visited, fails because of cyclic graph
/// - if unknown, add as visited and visit its requirements.
impl<'a, O: Clone, V: Visitor<'a, A, O>, A: Acceptor<'a>> Iterator<'a, O, V, A> {
    pub fn new(visitor: V, acceptor: &'a A) -> Iterator<'a, O, V, A> {
        // Init the stack and state
        let stack = Vec::from([acceptor]);
        let state: HashMap<&'a A, State<O>> = HashMap::from([(acceptor, State::Push)]);
        Iterator {
            stack,
            state,
            visitor,
        }
    }
}

impl<'a, O: Clone, V: Visitor<'a, A, O>, A: Acceptor<'a>> iter::Iterator for Iterator<'a, O, V, A> {
    type Item = (&'a A, State<O>);

    fn next(&mut self) -> Option<(&'a A, State<O>)> {
        let acceptor = self.stack.pop()?;
        match self.state.get(&acceptor)? {
            // Get the status of the current acceptor
            State::Push => {
                // The acceptor node was just added
                self.state.insert(acceptor, State::Visit);
                self.stack.push(acceptor); // Push for visit
                for dependency in self.visitor.dependencies(acceptor).0 {
                    // Push its dependencies
                    match self.state.get(&dependency) {
                        Some(State::Push) => (),           // Process next
                        Some(State::Visit) => return None, // The node is already being taken care of
                        Some(State::Accept(_)) => (),      // The node has been processed
                        None => {
                            self.state.insert(dependency, State::Push);
                        }
                    }
                    self.stack.push(dependency);
                }
                Some((acceptor, State::Visit))
            }
            State::Visit => {
                // The acceptor node pushed its dependencies and is ready to run the visitor
                let mut dependencies = Visited::new();
                for dependency in self.visitor.dependencies(acceptor).0 {
                    // Push its dependencies
                    if let Some(State::Accept(o)) = self.state.get(&dependency) {
                        dependencies.push(dependency, o.clone());
                    } else {
                        return None;
                    }
                }
                let output = self.visitor.visit(acceptor, dependencies);
                self.state.insert(acceptor, State::Accept(output.clone()));
                Some((acceptor, State::Accept(output)))
            }
            State::Accept(_) => Some((acceptor, State::Push)),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::{fmt, sync::Arc};

    #[derive(Clone, Debug, Hash, PartialEq, Eq)]
    struct Node(&'static str, Vec<Arc<Node>>);

    impl fmt::Display for Node {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            write!(f, "{} ({:?})", self.0, self as *const _)
        }
    }

    impl<'a> Acceptor<'a> for Node {
        fn dependencies(&'a self) -> Dependencies<'a, Self> {
            self.1.iter().map(|node| node.as_ref()).collect()
        }
    }

    struct DisplayVisitor;

    impl<'a> Visitor<'a, Node, String> for DisplayVisitor {
        fn visit(&self, acceptor: &'a Node, _dependencies: Visited<'a, Node, String>) -> String {
            format!("{acceptor}")
        }
    }

    fn build_diamond() -> Node {
        let a = Arc::new(Node("A", vec![]));
        let b = Arc::new(Node("B", vec![a.clone()]));
        let c = Arc::new(Node("C", vec![a]));
        Node("D", vec![b, c])
    }

    fn build_open_diamond() -> Node {
        let a = Node("A", vec![]);
        let b = Node("B", vec![Arc::new(a.clone())]);
        let c = Node("C", vec![Arc::new(a)]);
        Node("D", vec![Arc::new(b), Arc::new(c)])
    }

    #[test]
    fn test_diamond() {
        let open_diamond = build_open_diamond();
        for (_n, s) in open_diamond.iter_with(DisplayVisitor) {
            println!("{s}");
        }
        assert_eq!(open_diamond.iter_with(DisplayVisitor).count(), 4);
        println!("The labelling of processed nodes is based on their content, 2 copies of an object are considered the same");
        let diamond = build_diamond();
        for (_n, s) in diamond.iter_with(DisplayVisitor) {
            println!("{s}");
        }
        assert_eq!(diamond.iter_with(DisplayVisitor).count(), 4);
        println!("The labelling of processed nodes is based on their content, 2 copies of an object are considered the same");
    }

    fn build_semi_diamond() -> Node {
        let a = Arc::new(Node("A", vec![]));
        let b = Arc::new(Node("B", vec![a.clone()]));
        let c = Arc::new(Node("C", vec![a.clone(), b.clone()]));
        (*c).clone()
    }

    #[test]
    fn test_semi_diamond() {
        let semi_diamond = build_semi_diamond();
        for (_n, s) in semi_diamond.iter_with(DisplayVisitor) {
            println!("{s}");
        }
        // assert_eq!(double_diamond.iter_with(DisplayVisitor).count(), 4);
        println!("The half diamond")
    }
}