1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
use crate::diff::{match_graphs, DiffGraph, Match};
use crate::{MultiGraph, Edge, Graph, NodeStyle};
use std::collections::HashSet;

/// Returns a MultiGraph containing the diff of the two graphs.
/// To be visualized with dot.
pub fn visualize_diff(d1: &DiffGraph, d2: &DiffGraph) -> MultiGraph {
    let matches = match_graphs(d1, d2);

    let mut matched1 = HashSet::new();
    let mut matched2 = HashSet::new();
    let mut partial1 = HashSet::new();
    let mut partial2 = HashSet::new();

    for mch in matches {
        match mch {
            Match::Full(m) => {
                matched1.insert(m.from);
                matched2.insert(m.to);
            }
            Match::Partial(m) => {
                partial1.insert(m.from);
                partial2.insert(m.to);
            }
        }
    }

    let added_style = NodeStyle {
        title_bg: Some("green".into()),
        ..Default::default()
    };
    let removed_style = NodeStyle {
        title_bg: Some("red".into()),
        ..Default::default()
    };
    let changed_style = NodeStyle {
        title_bg: Some("yellow".into()),
        ..Default::default()
    };
    let default_style = NodeStyle {
        ..Default::default()
    };

    let edges1: Vec<Edge> = d1
        .graph
        .edges
        .iter()
        .map(|e| {
            Edge::new(
                format!("{}_diff1", e.from),
                format!("{}_diff1", e.to),
                e.label.clone(),
            )
        })
        .collect();
    let edges2: Vec<Edge> = d2
        .graph
        .edges
        .iter()
        .map(|e| {
            Edge::new(
                format!("{}_diff2", e.from),
                format!("{}_diff2", e.to),
                e.label.clone(),
            )
        })
        .collect();

    let mut nodes1 = Vec::new();
    for node in &d1.graph.nodes {
        let label = node.label.as_str();
        let mut node_cloned = node.clone();
        node_cloned.label = format!("{}_diff1", node.label);
        if matched1.contains(label) {
            node_cloned.style = default_style.clone();
            nodes1.push(node_cloned);
        } else if partial1.contains(label) {
            node_cloned.style = changed_style.clone();
            nodes1.push(node_cloned);
        } else {
            node_cloned.style = removed_style.clone();
            nodes1.push(node_cloned);
        }
    }

    let mut nodes2 = Vec::new();
    for node in &d2.graph.nodes {
        let label = node.label.as_str();
        let mut node_cloned = node.clone();
        node_cloned.label = format!("{}_diff2", node.label);
        if matched2.contains(label) {
            node_cloned.style = default_style.clone();
            nodes2.push(node_cloned);
        } else if partial2.contains(label) {
            node_cloned.style = changed_style.clone();
            nodes2.push(node_cloned);
        } else {
            node_cloned.style = added_style.clone();
            nodes2.push(node_cloned);
        }
    }
    let newg1 = Graph::new("diff1".to_owned(), nodes1, edges1);
    let newg2 = Graph::new("diff2".to_owned(), nodes2, edges2);

    MultiGraph::new("diff".to_owned(), vec![newg1, newg2])
}