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
use crate::obligation_forest::{ForestObligation, ObligationForest};
use rustc_graphviz as dot;
use std::env::var_os;
use std::fs::File;
use std::io::BufWriter;
use std::path::Path;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering;
impl<O: ForestObligation> ObligationForest<O> {
#[allow(dead_code)]
pub fn dump_graphviz<P: AsRef<Path>>(&self, dir: P, description: &str) {
static COUNTER: AtomicUsize = AtomicUsize::new(0);
if var_os("DUMP_OBLIGATION_FOREST_GRAPHVIZ").is_none() {
return;
}
let counter = COUNTER.fetch_add(1, Ordering::AcqRel);
let file_path = dir.as_ref().join(format!("{:010}_{}.gv", counter, description));
let mut gv_file = BufWriter::new(File::create(file_path).unwrap());
dot::render(&self, &mut gv_file).unwrap();
}
}
impl<'a, O: ForestObligation + 'a> dot::Labeller<'a> for &'a ObligationForest<O> {
type Node = usize;
type Edge = (usize, usize);
fn graph_id(&self) -> dot::Id<'_> {
dot::Id::new("trait_obligation_forest").unwrap()
}
fn node_id(&self, index: &Self::Node) -> dot::Id<'_> {
dot::Id::new(format!("obligation_{}", index)).unwrap()
}
fn node_label(&self, index: &Self::Node) -> dot::LabelText<'_> {
let node = &self.nodes[*index];
let label = format!("{:?} ({:?})", node.obligation.as_cache_key(), node.state.get());
dot::LabelText::LabelStr(label.into())
}
fn edge_label(&self, (_index_source, _index_target): &Self::Edge) -> dot::LabelText<'_> {
dot::LabelText::LabelStr("".into())
}
}
impl<'a, O: ForestObligation + 'a> dot::GraphWalk<'a> for &'a ObligationForest<O> {
type Node = usize;
type Edge = (usize, usize);
fn nodes(&self) -> dot::Nodes<'_, Self::Node> {
(0..self.nodes.len()).collect()
}
fn edges(&self) -> dot::Edges<'_, Self::Edge> {
(0..self.nodes.len())
.flat_map(|i| {
let node = &self.nodes[i];
node.dependents.iter().map(move |&d| (d, i))
})
.collect()
}
fn source(&self, (s, _): &Self::Edge) -> Self::Node {
*s
}
fn target(&self, (_, t): &Self::Edge) -> Self::Node {
*t
}
}