1use crate::util::escape_html;
2use std::io::{self, Write};
3use serde::{Deserialize, Serialize};
4
5/// NodeStyle defines some style of [Node](struct.Node.html)
6#[derive(Clone, Serialize, Deserialize)]
7pub struct NodeStyle {
8 /// Override the title color of the title
9 /// To color the title of the node differently in graphviz
10 pub title_bg: Option<String>,
11
12 /// Print a seperator b/w the rest of the statements and the last one
13 pub last_stmt_sep: bool,
14}
15
16impl Default for NodeStyle {
17 fn default() -> NodeStyle {
18 NodeStyle {
19 title_bg: None,
20 last_stmt_sep: false,
21 }
22 }
23}
24
25/// A graph node
26#[derive(Clone, Serialize, Deserialize)]
27pub struct Node {
28 /// A list of statements.
29 pub stmts: Vec<String>,
30
31 /// A unique identifier for the given node.
32 pub label: String,
33
34 /// The title is printed on the top of BB, the index of the basic block
35 pub(crate) title: String,
36
37 /// Can be used to override the default styles
38 pub(crate) style: NodeStyle,
39}
40
41impl Node {
42 pub fn new(stmts: Vec<String>, label: String, title: String, style: NodeStyle) -> Node {
43 Node {
44 stmts,
45 label,
46 title,
47 style,
48 }
49 }
50
51 pub fn to_dot<W: Write>(&self, w: &mut W) -> io::Result<()> {
52 write!(w, r#"<table border="0" cellborder="1" cellspacing="0">"#)?;
53
54 let bg_attr = match &self.style.title_bg {
55 Some(color) => format!(r#"bgcolor="{}""#, color),
56 None => "".into(),
57 };
58 write!(
59 w,
60 r#"<tr><td {bg_attr} {attrs} colspan="{colspan}">{blk}</td></tr>"#,
61 attrs = r#"align="center""#,
62 // TODO: Not sure what this is for
63 colspan = 1,
64 blk = self.title,
65 bg_attr = bg_attr
66 )?;
67
68 let stmts_len = self.stmts.len();
69 if !self.stmts.is_empty() {
70 if self.stmts.len() > 1 {
71 write!(w, r#"<tr><td align="left" balign="left">"#)?;
72 for statement in &self.stmts[..stmts_len - 1] {
73 write!(w, "{}<br/>", escape_html(statement))?;
74 }
75 write!(w, "</td></tr>")?;
76 }
77
78 if !self.style.last_stmt_sep {
79 write!(w, r#"<tr><td align="left">"#)?;
80 write!(w, "{}", escape_html(&self.stmts[stmts_len - 1]))?;
81 } else {
82 write!(w, r#"<tr><td align="left" balign="left">"#)?;
83 write!(w, "{}", escape_html(&self.stmts[stmts_len - 1]))?;
84 }
85 write!(w, "</td></tr>")?;
86 }
87
88 write!(w, "</table>")
89 }
90}
91
92/// A directed graph edge
93#[derive(Clone, Serialize, Deserialize, Debug)]
94pub struct Edge {
95 /// The label of the source node of the edge.
96 pub from: String,
97
98 /// The label of the target node of the edge.
99 pub to: String,
100
101 /// The label (title) of the edge. This doesn't have to unique.
102 // TODO: Rename this to title?
103 pub label: String,
104}
105
106impl Edge {
107 pub fn new(from: String, to: String, label: String) -> Edge {
108 Edge { from, to, label }
109 }
110
111 pub fn to_dot<W: Write>(&self, w: &mut W) -> io::Result<()> {
112 writeln!(
113 w,
114 r#" {} -> {} [label="{}"];"#,
115 self.from, self.to, self.label
116 )
117 }
118}
119