1 use super::LabelText::{self, EscStr, HtmlStr, LabelStr};
2 use super::{render, Edges, GraphWalk, Id, Labeller, Nodes, Style};
3 use std::io;
4 use std::io::prelude::*;
5 use NodeLabels::*;
6 
7 /// each node is an index in a vector in the graph.
8 type Node = usize;
9 struct Edge {
10     from: usize,
11     to: usize,
12     label: &'static str,
13     style: Style,
14 }
15 
edge(from: usize, to: usize, label: &'static str, style: Style) -> Edge16 fn edge(from: usize, to: usize, label: &'static str, style: Style) -> Edge {
17     Edge { from, to, label, style }
18 }
19 
20 struct LabelledGraph {
21     /// The name for this graph. Used for labeling generated `digraph`.
22     name: &'static str,
23 
24     /// Each node is an index into `node_labels`; these labels are
25     /// used as the label text for each node. (The node *names*,
26     /// which are unique identifiers, are derived from their index
27     /// in this array.)
28     ///
29     /// If a node maps to None here, then just use its name as its
30     /// text.
31     node_labels: Vec<Option<&'static str>>,
32 
33     node_styles: Vec<Style>,
34 
35     /// Each edge relates a from-index to a to-index along with a
36     /// label; `edges` collects them.
37     edges: Vec<Edge>,
38 }
39 
40 // A simple wrapper around LabelledGraph that forces the labels to
41 // be emitted as EscStr.
42 struct LabelledGraphWithEscStrs {
43     graph: LabelledGraph,
44 }
45 
46 enum NodeLabels<L> {
47     AllNodesLabelled(Vec<L>),
48     UnlabelledNodes(usize),
49     SomeNodesLabelled(Vec<Option<L>>),
50 }
51 
52 type Trivial = NodeLabels<&'static str>;
53 
54 impl NodeLabels<&'static str> {
to_opt_strs(self) -> Vec<Option<&'static str>>55     fn to_opt_strs(self) -> Vec<Option<&'static str>> {
56         match self {
57             UnlabelledNodes(len) => vec![None; len],
58             AllNodesLabelled(lbls) => lbls.into_iter().map(Some).collect(),
59             SomeNodesLabelled(lbls) => lbls.into_iter().collect(),
60         }
61     }
62 
len(&self) -> usize63     fn len(&self) -> usize {
64         match self {
65             &UnlabelledNodes(len) => len,
66             &AllNodesLabelled(ref lbls) => lbls.len(),
67             &SomeNodesLabelled(ref lbls) => lbls.len(),
68         }
69     }
70 }
71 
72 impl LabelledGraph {
new( name: &'static str, node_labels: Trivial, edges: Vec<Edge>, node_styles: Option<Vec<Style>>, ) -> LabelledGraph73     fn new(
74         name: &'static str,
75         node_labels: Trivial,
76         edges: Vec<Edge>,
77         node_styles: Option<Vec<Style>>,
78     ) -> LabelledGraph {
79         let count = node_labels.len();
80         LabelledGraph {
81             name,
82             node_labels: node_labels.to_opt_strs(),
83             edges,
84             node_styles: match node_styles {
85                 Some(nodes) => nodes,
86                 None => vec![Style::None; count],
87             },
88         }
89     }
90 }
91 
92 impl LabelledGraphWithEscStrs {
new(name: &'static str, node_labels: Trivial, edges: Vec<Edge>) -> LabelledGraphWithEscStrs93     fn new(name: &'static str, node_labels: Trivial, edges: Vec<Edge>) -> LabelledGraphWithEscStrs {
94         LabelledGraphWithEscStrs { graph: LabelledGraph::new(name, node_labels, edges, None) }
95     }
96 }
97 
id_name<'a>(n: &Node) -> Id<'a>98 fn id_name<'a>(n: &Node) -> Id<'a> {
99     Id::new(format!("N{}", *n)).unwrap()
100 }
101 
102 impl<'a> Labeller<'a> for LabelledGraph {
103     type Node = Node;
104     type Edge = &'a Edge;
graph_id(&'a self) -> Id<'a>105     fn graph_id(&'a self) -> Id<'a> {
106         Id::new(self.name).unwrap()
107     }
node_id(&'a self, n: &Node) -> Id<'a>108     fn node_id(&'a self, n: &Node) -> Id<'a> {
109         id_name(n)
110     }
node_label(&'a self, n: &Node) -> LabelText<'a>111     fn node_label(&'a self, n: &Node) -> LabelText<'a> {
112         match self.node_labels[*n] {
113             Some(l) => LabelStr(l.into()),
114             None => LabelStr(id_name(n).name),
115         }
116     }
edge_label(&'a self, e: &&'a Edge) -> LabelText<'a>117     fn edge_label(&'a self, e: &&'a Edge) -> LabelText<'a> {
118         LabelStr(e.label.into())
119     }
node_style(&'a self, n: &Node) -> Style120     fn node_style(&'a self, n: &Node) -> Style {
121         self.node_styles[*n]
122     }
edge_style(&'a self, e: &&'a Edge) -> Style123     fn edge_style(&'a self, e: &&'a Edge) -> Style {
124         e.style
125     }
126 }
127 
128 impl<'a> Labeller<'a> for LabelledGraphWithEscStrs {
129     type Node = Node;
130     type Edge = &'a Edge;
graph_id(&'a self) -> Id<'a>131     fn graph_id(&'a self) -> Id<'a> {
132         self.graph.graph_id()
133     }
node_id(&'a self, n: &Node) -> Id<'a>134     fn node_id(&'a self, n: &Node) -> Id<'a> {
135         self.graph.node_id(n)
136     }
node_label(&'a self, n: &Node) -> LabelText<'a>137     fn node_label(&'a self, n: &Node) -> LabelText<'a> {
138         match self.graph.node_label(n) {
139             LabelStr(s) | EscStr(s) | HtmlStr(s) => EscStr(s),
140         }
141     }
edge_label(&'a self, e: &&'a Edge) -> LabelText<'a>142     fn edge_label(&'a self, e: &&'a Edge) -> LabelText<'a> {
143         match self.graph.edge_label(e) {
144             LabelStr(s) | EscStr(s) | HtmlStr(s) => EscStr(s),
145         }
146     }
147 }
148 
149 impl<'a> GraphWalk<'a> for LabelledGraph {
150     type Node = Node;
151     type Edge = &'a Edge;
nodes(&'a self) -> Nodes<'a, Node>152     fn nodes(&'a self) -> Nodes<'a, Node> {
153         (0..self.node_labels.len()).collect()
154     }
edges(&'a self) -> Edges<'a, &'a Edge>155     fn edges(&'a self) -> Edges<'a, &'a Edge> {
156         self.edges.iter().collect()
157     }
source(&'a self, edge: &&'a Edge) -> Node158     fn source(&'a self, edge: &&'a Edge) -> Node {
159         edge.from
160     }
target(&'a self, edge: &&'a Edge) -> Node161     fn target(&'a self, edge: &&'a Edge) -> Node {
162         edge.to
163     }
164 }
165 
166 impl<'a> GraphWalk<'a> for LabelledGraphWithEscStrs {
167     type Node = Node;
168     type Edge = &'a Edge;
nodes(&'a self) -> Nodes<'a, Node>169     fn nodes(&'a self) -> Nodes<'a, Node> {
170         self.graph.nodes()
171     }
edges(&'a self) -> Edges<'a, &'a Edge>172     fn edges(&'a self) -> Edges<'a, &'a Edge> {
173         self.graph.edges()
174     }
source(&'a self, edge: &&'a Edge) -> Node175     fn source(&'a self, edge: &&'a Edge) -> Node {
176         edge.from
177     }
target(&'a self, edge: &&'a Edge) -> Node178     fn target(&'a self, edge: &&'a Edge) -> Node {
179         edge.to
180     }
181 }
182 
test_input(g: LabelledGraph) -> io::Result<String>183 fn test_input(g: LabelledGraph) -> io::Result<String> {
184     let mut writer = Vec::new();
185     render(&g, &mut writer).unwrap();
186     let mut s = String::new();
187     Read::read_to_string(&mut &*writer, &mut s)?;
188     Ok(s)
189 }
190 
191 // All of the tests use raw-strings as the format for the expected outputs,
192 // so that you can cut-and-paste the content into a .dot file yourself to
193 // see what the graphviz visualizer would produce.
194 
195 #[test]
empty_graph()196 fn empty_graph() {
197     let labels: Trivial = UnlabelledNodes(0);
198     let r = test_input(LabelledGraph::new("empty_graph", labels, vec![], None));
199     assert_eq!(
200         r.unwrap(),
201         r#"digraph empty_graph {
202 }
203 "#
204     );
205 }
206 
207 #[test]
single_node()208 fn single_node() {
209     let labels: Trivial = UnlabelledNodes(1);
210     let r = test_input(LabelledGraph::new("single_node", labels, vec![], None));
211     assert_eq!(
212         r.unwrap(),
213         r#"digraph single_node {
214     N0[label="N0"];
215 }
216 "#
217     );
218 }
219 
220 #[test]
single_node_with_style()221 fn single_node_with_style() {
222     let labels: Trivial = UnlabelledNodes(1);
223     let styles = Some(vec![Style::Dashed]);
224     let r = test_input(LabelledGraph::new("single_node", labels, vec![], styles));
225     assert_eq!(
226         r.unwrap(),
227         r#"digraph single_node {
228     N0[label="N0"][style="dashed"];
229 }
230 "#
231     );
232 }
233 
234 #[test]
single_edge()235 fn single_edge() {
236     let labels: Trivial = UnlabelledNodes(2);
237     let result = test_input(LabelledGraph::new(
238         "single_edge",
239         labels,
240         vec![edge(0, 1, "E", Style::None)],
241         None,
242     ));
243     assert_eq!(
244         result.unwrap(),
245         r#"digraph single_edge {
246     N0[label="N0"];
247     N1[label="N1"];
248     N0 -> N1[label="E"];
249 }
250 "#
251     );
252 }
253 
254 #[test]
single_edge_with_style()255 fn single_edge_with_style() {
256     let labels: Trivial = UnlabelledNodes(2);
257     let result = test_input(LabelledGraph::new(
258         "single_edge",
259         labels,
260         vec![edge(0, 1, "E", Style::Bold)],
261         None,
262     ));
263     assert_eq!(
264         result.unwrap(),
265         r#"digraph single_edge {
266     N0[label="N0"];
267     N1[label="N1"];
268     N0 -> N1[label="E"][style="bold"];
269 }
270 "#
271     );
272 }
273 
274 #[test]
test_some_labelled()275 fn test_some_labelled() {
276     let labels: Trivial = SomeNodesLabelled(vec![Some("A"), None]);
277     let styles = Some(vec![Style::None, Style::Dotted]);
278     let result = test_input(LabelledGraph::new(
279         "test_some_labelled",
280         labels,
281         vec![edge(0, 1, "A-1", Style::None)],
282         styles,
283     ));
284     assert_eq!(
285         result.unwrap(),
286         r#"digraph test_some_labelled {
287     N0[label="A"];
288     N1[label="N1"][style="dotted"];
289     N0 -> N1[label="A-1"];
290 }
291 "#
292     );
293 }
294 
295 #[test]
single_cyclic_node()296 fn single_cyclic_node() {
297     let labels: Trivial = UnlabelledNodes(1);
298     let r = test_input(LabelledGraph::new(
299         "single_cyclic_node",
300         labels,
301         vec![edge(0, 0, "E", Style::None)],
302         None,
303     ));
304     assert_eq!(
305         r.unwrap(),
306         r#"digraph single_cyclic_node {
307     N0[label="N0"];
308     N0 -> N0[label="E"];
309 }
310 "#
311     );
312 }
313 
314 #[test]
hasse_diagram()315 fn hasse_diagram() {
316     let labels = AllNodesLabelled(vec!["{x,y}", "{x}", "{y}", "{}"]);
317     let r = test_input(LabelledGraph::new(
318         "hasse_diagram",
319         labels,
320         vec![
321             edge(0, 1, "", Style::None),
322             edge(0, 2, "", Style::None),
323             edge(1, 3, "", Style::None),
324             edge(2, 3, "", Style::None),
325         ],
326         None,
327     ));
328     assert_eq!(
329         r.unwrap(),
330         r#"digraph hasse_diagram {
331     N0[label="{x,y}"];
332     N1[label="{x}"];
333     N2[label="{y}"];
334     N3[label="{}"];
335     N0 -> N1[label=""];
336     N0 -> N2[label=""];
337     N1 -> N3[label=""];
338     N2 -> N3[label=""];
339 }
340 "#
341     );
342 }
343 
344 #[test]
left_aligned_text()345 fn left_aligned_text() {
346     let labels = AllNodesLabelled(vec![
347         "if test {\
348        \\l    branch1\
349        \\l} else {\
350        \\l    branch2\
351        \\l}\
352        \\lafterward\
353        \\l",
354         "branch1",
355         "branch2",
356         "afterward",
357     ]);
358 
359     let mut writer = Vec::new();
360 
361     let g = LabelledGraphWithEscStrs::new(
362         "syntax_tree",
363         labels,
364         vec![
365             edge(0, 1, "then", Style::None),
366             edge(0, 2, "else", Style::None),
367             edge(1, 3, ";", Style::None),
368             edge(2, 3, ";", Style::None),
369         ],
370     );
371 
372     render(&g, &mut writer).unwrap();
373     let mut r = String::new();
374     Read::read_to_string(&mut &*writer, &mut r).unwrap();
375 
376     assert_eq!(
377         r,
378         r#"digraph syntax_tree {
379     N0[label="if test {\l    branch1\l} else {\l    branch2\l}\lafterward\l"];
380     N1[label="branch1"];
381     N2[label="branch2"];
382     N3[label="afterward"];
383     N0 -> N1[label="then"];
384     N0 -> N2[label="else"];
385     N1 -> N3[label=";"];
386     N2 -> N3[label=";"];
387 }
388 "#
389     );
390 }
391 
392 #[test]
simple_id_construction()393 fn simple_id_construction() {
394     let id1 = Id::new("hello");
395     match id1 {
396         Ok(_) => {}
397         Err(..) => panic!("'hello' is not a valid value for id anymore"),
398     }
399 }
400 
401 #[test]
badly_formatted_id()402 fn badly_formatted_id() {
403     let id2 = Id::new("Weird { struct : ure } !!!");
404     match id2 {
405         Ok(_) => panic!("graphviz id suddenly allows spaces, brackets and stuff"),
406         Err(..) => {}
407     }
408 }
409