#![allow(dead_code)]
use std::collections::{hash_map::Entry, HashMap, HashSet};
use std::error::Error;
use std::fmt::Display;
use std::hash::Hash;
#[derive(Debug, Clone)]
struct Dependencies<T>(HashSet<T>);
type Nodes<T> = HashMap<T, Dependencies<T>>;
#[derive(Debug)]
pub struct DepGraph<T: Hash + Eq + Clone + Display> {
nodes: Nodes<T>,
}
#[derive(Debug, Clone)]
pub struct CyclicError(String);
pub type Result<T> = std::result::Result<T, CyclicError>;
impl Error for CyclicError {}
impl Display for CyclicError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "cyclic dependency: {}", self.0)
}
}
impl CyclicError {
fn from<T: Display>(nodes: &Nodes<T>) -> CyclicError {
let mut s = vec![];
nodes
.iter()
.for_each(|(k, v)| v.0.iter().for_each(|d| s.push(format!("{} -> {}", k, d))));
let e = format!("[{}]", s.join(", "));
CyclicError(e)
}
}
impl<T> std::ops::Deref for Dependencies<T> {
type Target = HashSet<T>;
#[inline]
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T> std::ops::DerefMut for Dependencies<T> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<T> Dependencies<T> {
#[inline]
fn new() -> Dependencies<T> {
Dependencies(HashSet::new())
}
}
impl<T> DepGraph<T>
where
T: Hash + Eq + Clone + Display,
{
#[inline]
pub fn new() -> DepGraph<T> {
DepGraph {
nodes: HashMap::new(),
}
}
#[inline]
pub fn size(&self) -> usize {
self.nodes.len()
}
#[inline]
pub fn reset(&mut self) {
self.nodes = HashMap::new();
}
#[inline]
pub fn register_node<N: Into<T>>(&mut self, node: N) {
Self::__register(&mut self.nodes, node.into(), None);
}
#[inline]
pub fn register_dep<N: Into<T>>(&mut self, node: N, dep_node: N) {
Self::__register(&mut self.nodes, node.into(), Some(dep_node.into()))
}
#[inline]
pub fn register_deps<N: Into<T>>(&mut self, node: N, dep_nodes: Vec<N>) {
let node = node.into();
dep_nodes.into_iter().for_each(|dep_node| {
Self::__register(&mut self.nodes, node.clone(), Some(dep_node.into()));
})
}
#[inline]
pub fn unregister_node<N: Into<T>>(&mut self, node: N) -> bool {
let node = node.into();
let ret = self.nodes.contains_key(&node);
if ret {
Self::__unregister(&mut self.nodes, &node);
}
ret
}
pub fn pop(&mut self) -> Option<T> {
let node = self
.nodes
.iter()
.filter(|(_, deps)| deps.len() == 0)
.map(|(node, _)| node)
.next()
.cloned();
if let Some(node) = &node {
Self::__unregister(&mut self.nodes, node);
}
node
}
#[inline]
pub fn step(&mut self) -> Vec<T> {
Self::__step(&mut self.nodes)
}
pub fn check(&self) -> Result<()> {
let mut nodes = self.nodes.clone();
while !nodes.is_empty() {
let step = Self::__step(&mut nodes);
if step.is_empty() {
return Err(CyclicError::from(&nodes));
}
}
Ok(())
}
pub fn walk(&mut self) -> Result<Vec<Vec<T>>> {
let mut res = vec![];
while !self.nodes.is_empty() {
let step = self.step();
if step.is_empty() {
return Err(CyclicError::from(&self.nodes));
}
res.push(step);
}
Ok(res)
}
#[inline]
pub fn walk_flatten(&mut self) -> Result<Vec<T>> {
self.walk()
.map(|v| v.into_iter().flatten().collect::<Vec<_>>())
}
fn __step(nodes: &mut Nodes<T>) -> Vec<T> {
let step = nodes
.iter()
.filter(|(_, deps)| deps.len() == 0)
.map(|(node, _)| node.clone())
.collect::<Vec<_>>();
step.iter().for_each(|node| {
Self::__unregister(nodes, node);
});
step
}
#[inline]
fn __register(nodes: &mut Nodes<T>, node: T, dep_node: Option<T>) {
match nodes.entry(node) {
Entry::Vacant(e) => {
let mut dep = Dependencies::new();
if let Some(dep_node) = &dep_node {
dep.insert(dep_node.clone());
}
e.insert(dep);
}
Entry::Occupied(e) => {
if let Some(dep_node) = &dep_node {
e.into_mut().insert(dep_node.clone());
}
}
}
if let Some(dep_node) = dep_node {
match nodes.entry(dep_node) {
Entry::Vacant(e) => {
e.insert(Dependencies::new());
}
Entry::Occupied(_) => {
}
}
}
}
#[inline]
fn __unregister(nodes: &mut Nodes<T>, node: &T) {
nodes.remove(node);
nodes.iter_mut().for_each(|(_, deps)| {
deps.remove(node);
});
}
}
#[cfg(test)]
mod test {
use super::DepGraph;
#[test]
fn test_register_node() {
let mut graph = DepGraph::<String>::new();
graph.register_node("loneliness");
assert!(graph.walk().is_ok());
}
#[test]
fn test_register_dep() {
let mut graph = DepGraph::<String>::new();
graph.register_dep("npm", "node");
graph.register_dep("yarn", "node");
graph.register_dep("i", "you");
graph.register_dep("earth", "sun");
assert!(graph.walk().is_ok());
}
#[test]
fn test_register_deps() {
let mut graph = DepGraph::<String>::new();
graph.register_deps(
"vc_bundle",
vec!["vs2005", "vs2008", "vs2010", "vs2013", "vs2019"],
);
graph.register_deps(
"games",
vec!["minecraft", "war3", "csgo", "genshin", "pokemon"],
);
assert!(graph.walk().is_ok());
}
#[test]
fn test_check() {
let mut graph = DepGraph::<String>::new();
graph.register_node("one");
assert!(graph.check().is_ok());
graph.register_dep("me", "you");
graph.register_dep("you", "me");
assert!(graph.check().is_err());
}
#[test]
fn test_pop() {
let mut graph = DepGraph::<String>::new();
graph.register_node("are you ok?");
let ret = graph.pop();
assert_eq!(ret, Some("are you ok?".to_string()));
assert_eq!(graph.size(), 0);
}
#[test]
fn test_step() {
let mut graph = DepGraph::<String>::new();
graph.register_node("are you ok?");
graph.register_node("what's your problem?");
graph.register_dep("what's your problem?", "oh no!");
let ret = graph.step();
assert_eq!(ret.len(), 2);
assert_eq!(graph.size(), 1);
}
#[test]
fn test_unregister_node() {
let mut graph = DepGraph::<String>::new();
graph.register_dep("npm", "node");
graph.register_dep("yarn", "node");
graph.unregister_node("node");
graph.unregister_node("npm");
graph.unregister_node("yarn");
assert!(graph.size() == 0);
}
#[test]
fn test_walk_flatten() {
let mut graph = DepGraph::<String>::new();
graph.register_node("firefox");
graph.register_node("chromium");
graph.register_dep("msedge", "chromium");
let ret = graph.walk_flatten();
assert!(ret.is_ok());
assert_eq!(ret.unwrap().len(), 3);
}
#[test]
fn test_cyclic() {
let mut graph = DepGraph::<String>::new();
graph.register_dep("Death's End", "The Dark Forest");
graph.register_dep("The Dark Forest", "The Three-Body Problem");
graph.register_dep("The Three-Body Problem", "Death's End");
assert!(graph.walk().is_err());
}
#[test]
fn test_self_cyclic() {
let mut graph = DepGraph::<String>::new();
graph.register_dep("self", "self");
assert!(graph.walk().is_err());
}
}