1 use super::LabelText
::{self, EscStr, HtmlStr, LabelStr}
;
2 use super::{render, Edges, GraphWalk, Id, Labeller, Nodes, Style}
;
4 use std
::io
::prelude
::*;
7 /// each node is an index in a vector in the graph.
16 fn edge(from
: usize, to
: usize, label
: &'
static str, style
: Style
) -> Edge
{
17 Edge { from, to, label, style }
20 struct LabelledGraph
{
21 /// The name for this graph. Used for labeling generated `digraph`.
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
29 /// If a node maps to None here, then just use its name as its
31 node_labels
: Vec
<Option
<&'
static str>>,
33 node_styles
: Vec
<Style
>,
35 /// Each edge relates a from-index to a to-index along with a
36 /// label; `edges` collects them.
40 // A simple wrapper around LabelledGraph that forces the labels to
41 // be emitted as EscStr.
42 struct LabelledGraphWithEscStrs
{
47 AllNodesLabelled(Vec
<L
>),
48 UnlabelledNodes(usize),
49 SomeNodesLabelled(Vec
<Option
<L
>>),
52 type Trivial
= NodeLabels
<&'
static str>;
54 impl NodeLabels
<&'
static str> {
55 fn to_opt_strs(self) -> Vec
<Option
<&'
static str>> {
57 UnlabelledNodes(len
) => vec
![None
; len
],
58 AllNodesLabelled(lbls
) => lbls
.into_iter().map(|l
| Some(l
)).collect(),
59 SomeNodesLabelled(lbls
) => lbls
.into_iter().collect(),
63 fn len(&self) -> usize {
65 &UnlabelledNodes(len
) => len
,
66 &AllNodesLabelled(ref lbls
) => lbls
.len(),
67 &SomeNodesLabelled(ref lbls
) => lbls
.len(),
77 node_styles
: Option
<Vec
<Style
>>,
79 let count
= node_labels
.len();
82 node_labels
: node_labels
.to_opt_strs(),
84 node_styles
: match node_styles
{
86 None
=> vec
![Style
::None
; count
],
92 impl LabelledGraphWithEscStrs
{
93 fn new(name
: &'
static str, node_labels
: Trivial
, edges
: Vec
<Edge
>) -> LabelledGraphWithEscStrs
{
94 LabelledGraphWithEscStrs { graph: LabelledGraph::new(name, node_labels, edges, None) }
98 fn id_name
<'a
>(n
: &Node
) -> Id
<'a
> {
99 Id
::new(format
!("N{}", *n
)).unwrap()
102 impl<'a
> Labeller
<'a
> for LabelledGraph
{
104 type Edge
= &'a Edge
;
105 fn graph_id(&'a
self) -> Id
<'a
> {
106 Id
::new(self.name
).unwrap()
108 fn node_id(&'a
self, n
: &Node
) -> Id
<'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()),
117 fn edge_label(&'a
self, e
: &&'a Edge
) -> LabelText
<'a
> {
118 LabelStr(e
.label
.into())
120 fn node_style(&'a
self, n
: &Node
) -> Style
{
123 fn edge_style(&'a
self, e
: &&'a Edge
) -> Style
{
128 impl<'a
> Labeller
<'a
> for LabelledGraphWithEscStrs
{
130 type Edge
= &'a Edge
;
131 fn graph_id(&'a
self) -> Id
<'a
> {
132 self.graph
.graph_id()
134 fn node_id(&'a
self, n
: &Node
) -> Id
<'a
> {
135 self.graph
.node_id(n
)
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
),
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
),
149 impl<'a
> GraphWalk
<'a
> for LabelledGraph
{
151 type Edge
= &'a Edge
;
152 fn nodes(&'a
self) -> Nodes
<'a
, Node
> {
153 (0..self.node_labels
.len()).collect()
155 fn edges(&'a
self) -> Edges
<'a
, &'a Edge
> {
156 self.edges
.iter().collect()
158 fn source(&'a
self, edge
: &&'a Edge
) -> Node
{
161 fn target(&'a
self, edge
: &&'a Edge
) -> Node
{
166 impl<'a
> GraphWalk
<'a
> for LabelledGraphWithEscStrs
{
168 type Edge
= &'a Edge
;
169 fn nodes(&'a
self) -> Nodes
<'a
, Node
> {
172 fn edges(&'a
self) -> Edges
<'a
, &'a Edge
> {
175 fn source(&'a
self, edge
: &&'a Edge
) -> Node
{
178 fn target(&'a
self, edge
: &&'a Edge
) -> Node
{
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
)?
;
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.
197 let labels
: Trivial
= UnlabelledNodes(0);
198 let r
= test_input(LabelledGraph
::new("empty_graph", labels
, vec
![], None
));
201 r
#"digraph empty_graph {
209 let labels
: Trivial
= UnlabelledNodes(1);
210 let r
= test_input(LabelledGraph
::new("single_node", labels
, vec
![], None
));
213 r
#"digraph single_node {
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
));
227 r
#"digraph single_node {
228 N0[label="N0"][style="dashed"];
236 let labels
: Trivial
= UnlabelledNodes(2);
237 let result
= test_input(LabelledGraph
::new(
240 vec
![edge(0, 1, "E", Style
::None
)],
245 r
#"digraph single_edge {
255 fn single_edge_with_style() {
256 let labels
: Trivial
= UnlabelledNodes(2);
257 let result
= test_input(LabelledGraph
::new(
260 vec
![edge(0, 1, "E", Style
::Bold
)],
265 r
#"digraph single_edge {
268 N0 -> N1[label="E"][style="bold"];
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",
281 vec
![edge(0, 1, "A-1", Style
::None
)],
286 r
#"digraph test_some_labelled {
288 N1[label="N1"][style="dotted"];
289 N0 -> N1[label="A-1"];
296 fn single_cyclic_node() {
297 let labels
: Trivial
= UnlabelledNodes(1);
298 let r
= test_input(LabelledGraph
::new(
299 "single_cyclic_node",
301 vec
![edge(0, 0, "E", Style
::None
)],
306 r
#"digraph single_cyclic_node {
316 let labels
= AllNodesLabelled(vec
!["{x,y}", "{x}", "{y}", "{}"]);
317 let r
= test_input(LabelledGraph
::new(
321 edge(0, 1, "", Style
::None
),
322 edge(0, 2, "", Style
::None
),
323 edge(1, 3, "", Style
::None
),
324 edge(2, 3, "", Style
::None
),
330 r
#"digraph hasse_diagram {
345 fn left_aligned_text() {
346 let labels
= AllNodesLabelled(vec
![
359 let mut writer
= Vec
::new();
361 let g
= LabelledGraphWithEscStrs
::new(
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
),
372 render(&g
, &mut writer
).unwrap();
373 let mut r
= String
::new();
374 Read
::read_to_string(&mut &*writer
, &mut r
).unwrap();
378 r
#"digraph syntax_tree {
379 N0[label="if test {\l branch1\l} else {\l branch2\l}\lafterward\l"];
382 N3[label="afterward"];
383 N0 -> N1[label="then"];
384 N0 -> N2[label="else"];
393 fn simple_id_construction() {
394 let id1
= Id
::new("hello");
397 Err(..) => panic
!("'hello' is not a valid value for id anymore"),
402 fn badly_formatted_id() {
403 let id2
= Id
::new("Weird { struct : ure } !!!");
405 Ok(_
) => panic
!("graphviz id suddenly allows spaces, brackets and stuff"),