Skip to main content

module_util/evaluator/acyclic/
mod.rs

1//! [`Evaluator`] adapter for preventing infinite evaluation due to cyclic imports.
2
3use std::collections::HashSet;
4use std::hash::Hash;
5
6use super::{Evaluator, Imports};
7
8///////////////////////////////////////////////////////////////////////////////
9
10/// An [`Evaluator`] adapter that prevents infinite evaluation from cyclic
11/// imports.
12#[derive(Debug, Clone)]
13pub struct Acyclic<E>
14where
15    E: Evaluator,
16{
17    evaluator: E,
18    evaluated: HashSet<E::Id>,
19}
20
21impl<E> Acyclic<E>
22where
23    E: Evaluator,
24{
25    /// Create a new [`Acyclic`].
26    pub fn new(evaluator: E) -> Self {
27        Self {
28            evaluator,
29            evaluated: HashSet::new(),
30        }
31    }
32}
33
34impl<E> Default for Acyclic<E>
35where
36    E: Evaluator + Default,
37{
38    fn default() -> Self {
39        Self::new(Default::default())
40    }
41}
42
43impl<E> Acyclic<E>
44where
45    E: Evaluator,
46    E::Id: Eq + Hash,
47{
48    /// Check whether `id` was evaluated.
49    ///
50    /// A module is marked as "evaluated" when [`Evaluator::eval`] succeeds
51    /// on it.
52    pub fn evaluated(&self, id: &E::Id) -> bool {
53        self.evaluated.contains(id)
54    }
55
56    /// Get a reference to the inner evaluator.
57    pub fn get(&self) -> &E {
58        &self.evaluator
59    }
60
61    /// Get a mutable reference to the inner evaluator.
62    pub fn get_mut(&mut self) -> &mut E {
63        &mut self.evaluator
64    }
65}
66
67impl<E> Evaluator for Acyclic<E>
68where
69    E: Evaluator,
70    E::Id: Clone + Eq + Hash,
71{
72    type Id = E::Id;
73    type Module = E::Module;
74    type Error = E::Error;
75
76    fn is_empty(&self) -> bool {
77        self.evaluator.is_empty()
78    }
79
80    fn next(&mut self) -> Option<Self::Id> {
81        loop {
82            match self.evaluator.next() {
83                Some(x) if self.evaluated(&x) => continue,
84                Some(x) => break Some(x),
85                None => break None,
86            }
87        }
88    }
89
90    fn eval(
91        &mut self,
92        id: Self::Id,
93        imports: Imports<Self::Id>,
94        module: Self::Module,
95    ) -> Result<(), Self::Error> {
96        if self.evaluated(&id) {
97            return Ok(());
98        }
99
100        let r = self.evaluator.eval(id.clone(), imports, module);
101        if r.is_ok() {
102            self.evaluated.insert(id);
103        }
104
105        r
106    }
107
108    fn finish(self) -> Option<Self::Module> {
109        self.evaluator.finish()
110    }
111}