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}
107