use crate::error::{Result, SaferRingError};
use std::collections::{HashMap, HashSet};
pub struct DependencyValidator;
impl DependencyValidator {
pub fn has_circular_dependencies(dependencies: &HashMap<usize, Vec<usize>>) -> bool {
fn has_cycle(
node: usize,
graph: &HashMap<usize, Vec<usize>>,
visited: &mut HashSet<usize>,
rec_stack: &mut HashSet<usize>,
) -> bool {
visited.insert(node);
rec_stack.insert(node);
if let Some(neighbors) = graph.get(&node) {
for &neighbor in neighbors {
if (!visited.contains(&neighbor)
&& has_cycle(neighbor, graph, visited, rec_stack))
|| rec_stack.contains(&neighbor)
{
return true;
}
}
}
rec_stack.remove(&node);
false
}
let mut visited = HashSet::new();
for &node in dependencies.keys() {
if !visited.contains(&node) {
let mut rec_stack = HashSet::new();
if has_cycle(node, dependencies, &mut visited, &mut rec_stack) {
return true;
}
}
}
false
}
pub fn would_create_cycle(
dependencies: &HashMap<usize, Vec<usize>>,
dependent: usize,
new_dependency: usize,
) -> bool {
let mut visited = HashSet::new();
let mut stack = vec![new_dependency];
while let Some(current) = stack.pop() {
if current == dependent {
return true; }
if visited.contains(¤t) {
continue; }
visited.insert(current);
if let Some(deps) = dependencies.get(¤t) {
stack.extend(deps.iter().copied());
}
}
false
}
pub fn dependency_order(
dependencies: &HashMap<usize, Vec<usize>>,
operation_count: usize,
) -> Result<Vec<usize>> {
let mut result = Vec::new();
let mut visited = HashSet::new();
let mut temp_visited = HashSet::new();
for i in 0..operation_count {
if !visited.contains(&i) {
Self::visit_node(
i,
dependencies,
&mut visited,
&mut temp_visited,
&mut result,
)?;
}
}
Ok(result)
}
fn visit_node(
node: usize,
dependencies: &HashMap<usize, Vec<usize>>,
visited: &mut HashSet<usize>,
temp_visited: &mut HashSet<usize>,
result: &mut Vec<usize>,
) -> Result<()> {
if temp_visited.contains(&node) {
return Err(SaferRingError::Io(std::io::Error::new(
std::io::ErrorKind::InvalidInput,
"Circular dependency detected",
)));
}
if visited.contains(&node) {
return Ok(());
}
temp_visited.insert(node);
if let Some(deps) = dependencies.get(&node) {
for &dep in deps {
Self::visit_node(dep, dependencies, visited, temp_visited, result)?;
}
}
temp_visited.remove(&node);
visited.insert(node);
result.push(node);
Ok(())
}
}