1pub mod error;
58pub use error::SolventError;
59
60#[cfg(feature = "deterministic")]
61use indexmap::{map::IndexMap as HashMap, set::IndexSet as HashSet};
62#[cfg(not(feature = "deterministic"))]
63use std::collections::{HashMap, HashSet};
64
65use std::iter::Iterator;
66
67#[derive(Debug, Clone)]
71pub struct DepGraph<T: Eq> {
72 nodes: Vec<T>,
74
75 dependencies: HashMap<usize, HashSet<usize>>,
79
80 satisfied: HashSet<usize>,
82}
83
84impl<T: Eq> Default for DepGraph<T> {
85 fn default() -> Self {
86 Self {
87 nodes: Vec::new(),
88 dependencies: HashMap::new(),
89 satisfied: HashSet::new(),
90 }
91 }
92}
93
94impl<T: Eq> DepGraph<T> {
95 pub fn new() -> DepGraph<T> {
97 Self::default()
98 }
99
100 fn _pos(&self, node: &T) -> Option<usize> {
101 self.nodes.iter().position(|x| x == node)
102 }
103
104 fn _register_node(&mut self, node: T) -> usize {
105 match self._pos(&node) {
106 Some(pos) => pos,
107 None => {
108 self.nodes.push(node);
109 self.nodes.len() - 1
110 }
111 }
112 }
113
114 pub fn register_nodes(&mut self, mut nodes: Vec<T>) {
117 for node in nodes.drain(..) {
118 self.register_node(node);
119 }
120 }
121
122 pub fn register_node(&mut self, node: T) {
125 self._register_node(node);
126 }
127
128 pub fn register_dependency(&mut self, node: T, depends_on: T) {
132 let node_pos = self._register_node(node);
133 let dep_pos = self._register_node(depends_on);
134
135 self.dependencies
136 .entry(node_pos)
137 .and_modify(|entry| {
138 entry.insert(dep_pos);
139 })
140 .or_insert_with(|| {
141 let mut deps = HashSet::with_capacity(1);
142 deps.insert(dep_pos);
143 deps
144 });
145 }
146
147 pub fn register_dependencies(&mut self, node: T, mut depends_on: Vec<T>) {
152 let node_pos = self._register_node(node);
153
154 let dep_poses = depends_on
155 .drain(..)
156 .map(|dp| self._register_node(dp))
157 .collect::<Vec<_>>();
158
159 self.dependencies
160 .entry(node_pos)
161 .and_modify(|entry| {
162 entry.extend(dep_poses.iter());
163 })
164 .or_insert_with(|| dep_poses.iter().cloned().collect::<HashSet<_>>());
165 }
166
167 pub fn mark_as_satisfied(&mut self, nodes: &[T]) -> Result<(), SolventError> {
170 for node in nodes.iter() {
171 let node_pos = self._pos(node).ok_or(SolventError::NoSuchNode)?;
172 self.satisfied.insert(node_pos);
173 }
174
175 Ok(())
176 }
177
178 pub fn dependencies_of<'a>(
181 &'a self,
182 target: &T,
183 ) -> Result<DepGraphIterator<'a, T>, SolventError> {
184 let pos = self._pos(target).ok_or(SolventError::NoSuchNode)?;
185
186 Ok(DepGraphIterator {
187 depgraph: self,
188 target: pos,
189 satisfied: self.satisfied.clone(),
190 curpath: HashSet::new(),
191 halted: false,
192 })
193 }
194}
195
196pub struct DepGraphIterator<'a, T: Eq + 'a> {
198 depgraph: &'a DepGraph<T>,
199
200 target: usize,
202
203 satisfied: HashSet<usize>,
205
206 curpath: HashSet<usize>,
208
209 halted: bool,
211}
212
213impl<'a, T: Eq> DepGraphIterator<'a, T> {
214 fn get_next_dependency(&mut self, pos: usize) -> Result<usize, SolventError> {
215 if self.curpath.contains(&pos) {
216 return Err(SolventError::CycleDetected);
217 }
218 self.curpath.insert(pos);
219
220 let deplist = match self.depgraph.dependencies.get(&pos) {
221 None => return Ok(pos),
222 Some(deplist) => deplist,
223 };
224
225 for n in deplist.iter() {
226 if self.satisfied.contains(n) {
228 continue;
229 }
230 return self.get_next_dependency(*n);
231 }
232
233 Ok(pos)
235 }
236}
237
238impl<'a, T: Eq> Iterator for DepGraphIterator<'a, T> {
239 type Item = Result<&'a T, SolventError>;
240
241 fn next(&mut self) -> Option<Result<&'a T, SolventError>> {
244 if self.halted {
245 return None;
246 }
247
248 let npos = self.target;
249 if self.satisfied.contains(&npos) {
250 self.halted = true;
251 return None;
252 }
253
254 self.curpath.clear();
255 let next = match self.get_next_dependency(npos) {
256 Ok(d) => d,
257 Err(e) => {
258 self.halted = true;
259 return Some(Err(e));
260 }
261 };
262 self.satisfied.insert(next);
263 Some(Ok(&self.depgraph.nodes[next]))
264 }
265}
266
267#[cfg(test)]
268mod test {
269 use super::DepGraph;
270 use super::HashSet;
271 use super::SolventError;
272
273 #[test]
274 fn solvent_test_branching() {
275 let mut depgraph: DepGraph<&str> = DepGraph::new();
276
277 depgraph.register_nodes(vec![
278 "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n",
279 ]);
280
281 depgraph.register_dependencies("a", vec!["b", "c", "d"]);
282 depgraph.register_dependency("b", "d");
283 depgraph.register_dependencies("c", vec!["e", "m", "g"]);
284 depgraph.register_dependency("e", "f");
285 depgraph.register_dependency("g", "h");
286 depgraph.register_dependency("h", "i");
287 depgraph.register_dependencies("i", vec!["j", "k"]);
288 depgraph.register_dependencies("k", vec!["l", "m"]);
289 depgraph.register_dependency("m", "n");
290
291 let mut results = Vec::new();
292
293 for node in depgraph.dependencies_of(&"a").unwrap() {
294 assert!(results.len() < 30);
296
297 let n = match node {
298 Err(e) => panic!("Solvent error detected: {:?}", e),
299 Ok(n) => n,
300 };
301
302 let pos = depgraph._pos(&n).unwrap();
304 let deps: Option<&HashSet<usize>> = depgraph.dependencies.get(&pos);
305 if let Some(deps) = deps {
306 for dep in deps.iter() {
307 assert!(results.contains(&depgraph.nodes[*dep]));
308 }
309 }
310
311 results.push(*n);
312 }
313
314 assert!(results.len() == 14);
316
317 for result in results.iter() {
319 let mut count: usize = 0;
320 for result2 in results.iter() {
321 if result == result2 {
322 count += 1;
323 }
324 }
325 assert!(count == 1);
326 }
327 }
328
329 #[test]
330 fn solvent_test_updating_dependencies() {
331 let mut depgraph: DepGraph<&str> = DepGraph::new();
332
333 depgraph.register_dependencies("a", vec!["b", "c"]);
334 depgraph.register_dependency("a", "d");
335 assert!(depgraph.dependencies.get(&0).unwrap().contains(&1));
336 assert!(depgraph.dependencies.get(&0).unwrap().contains(&2));
337 assert!(depgraph.dependencies.get(&0).unwrap().contains(&3));
338 }
339
340 #[test]
341 fn solvent_test_circular() {
342 let mut depgraph: DepGraph<&str> = DepGraph::new();
343 depgraph.register_dependency("a", "b");
344 depgraph.register_dependency("b", "c");
345 depgraph.register_dependency("c", "a");
346
347 for node in depgraph.dependencies_of(&"a").unwrap() {
348 assert!(node.is_err());
349 assert!(node.unwrap_err() == SolventError::CycleDetected);
350 }
351 }
352
353 #[test]
354 fn solvent_test_satisfied_stoppage() {
355 let mut depgraph: DepGraph<&str> = DepGraph::new();
356 depgraph.register_dependencies("superconn", vec![]);
357 depgraph.register_dependencies("owneruser", vec!["superconn"]);
358 depgraph.register_dependencies("appuser", vec!["superconn"]);
359 depgraph.register_dependencies("database", vec!["owneruser"]);
360 depgraph.register_dependencies("ownerconn", vec!["database", "owneruser"]);
361 depgraph.register_dependencies("adminconn", vec!["database"]);
362 depgraph.register_dependencies("extensions", vec!["database", "adminconn"]);
363 depgraph.register_dependencies("schema_table", vec!["database", "ownerconn"]);
364 depgraph.register_dependencies(
365 "schemas",
366 vec!["ownerconn", "extensions", "schema_table", "appuser"],
367 );
368 depgraph.register_dependencies("appconn", vec!["database", "appuser", "schemas"]);
369
370 depgraph
371 .mark_as_satisfied(&["owneruser", "appuser"])
372 .unwrap();
373 assert_eq!(depgraph.satisfied.len(), 2);
374
375 let mut results: Vec<&str> = Vec::new();
376
377 for node in depgraph.dependencies_of(&"appconn").unwrap() {
378 assert!(results.len() < 30);
379 match node {
380 Ok(n) => results.push(n),
381 Err(e) => panic!("Solvent error detected: {:?}", e),
382 };
383 }
384
385 assert!(!results.contains(&"appuser"));
387 assert!(!results.contains(&"owneruser"));
388 assert!(!results.contains(&"superconn"));
389
390 assert!(results.len() == 7);
392
393 for result in results.iter() {
395 let mut count: usize = 0;
396 for result2 in results.iter() {
397 if result == result2 {
398 count += 1;
399 }
400 }
401 assert!(count == 1);
402 }
403 }
404}