gsgdt/diff/
diff.rs

1use crate::diff::{match_graphs, DiffGraph, Match};
2use crate::{MultiGraph, Edge, Graph, NodeStyle};
3use std::collections::HashSet;
4
5/// Returns a MultiGraph containing the diff of the two graphs.
6/// To be visualized with dot.
7pub fn visualize_diff(d1: &DiffGraph, d2: &DiffGraph) -> MultiGraph {
8    let matches = match_graphs(d1, d2);
9
10    let mut matched1 = HashSet::new();
11    let mut matched2 = HashSet::new();
12    let mut partial1 = HashSet::new();
13    let mut partial2 = HashSet::new();
14
15    for mch in matches {
16        match mch {
17            Match::Full(m) => {
18                matched1.insert(m.from);
19                matched2.insert(m.to);
20            }
21            Match::Partial(m) => {
22                partial1.insert(m.from);
23                partial2.insert(m.to);
24            }
25        }
26    }
27
28    let added_style = NodeStyle {
29        title_bg: Some("green".into()),
30        ..Default::default()
31    };
32    let removed_style = NodeStyle {
33        title_bg: Some("red".into()),
34        ..Default::default()
35    };
36    let changed_style = NodeStyle {
37        title_bg: Some("yellow".into()),
38        ..Default::default()
39    };
40    let default_style = NodeStyle {
41        ..Default::default()
42    };
43
44    let edges1: Vec<Edge> = d1
45        .graph
46        .edges
47        .iter()
48        .map(|e| {
49            Edge::new(
50                format!("{}_diff1", e.from),
51                format!("{}_diff1", e.to),
52                e.label.clone(),
53            )
54        })
55        .collect();
56    let edges2: Vec<Edge> = d2
57        .graph
58        .edges
59        .iter()
60        .map(|e| {
61            Edge::new(
62                format!("{}_diff2", e.from),
63                format!("{}_diff2", e.to),
64                e.label.clone(),
65            )
66        })
67        .collect();
68
69    let mut nodes1 = Vec::new();
70    for node in &d1.graph.nodes {
71        let label = node.label.as_str();
72        let mut node_cloned = node.clone();
73        node_cloned.label = format!("{}_diff1", node.label);
74        if matched1.contains(label) {
75            node_cloned.style = default_style.clone();
76            nodes1.push(node_cloned);
77        } else if partial1.contains(label) {
78            node_cloned.style = changed_style.clone();
79            nodes1.push(node_cloned);
80        } else {
81            node_cloned.style = removed_style.clone();
82            nodes1.push(node_cloned);
83        }
84    }
85
86    let mut nodes2 = Vec::new();
87    for node in &d2.graph.nodes {
88        let label = node.label.as_str();
89        let mut node_cloned = node.clone();
90        node_cloned.label = format!("{}_diff2", node.label);
91        if matched2.contains(label) {
92            node_cloned.style = default_style.clone();
93            nodes2.push(node_cloned);
94        } else if partial2.contains(label) {
95            node_cloned.style = changed_style.clone();
96            nodes2.push(node_cloned);
97        } else {
98            node_cloned.style = added_style.clone();
99            nodes2.push(node_cloned);
100        }
101    }
102    let newg1 = Graph::new("diff1".to_owned(), nodes1, edges1);
103    let newg2 = Graph::new("diff2".to_owned(), nodes2, edges2);
104
105    MultiGraph::new("diff".to_owned(), vec![newg1, newg2])
106}