dot_graph/
graph.rs

1use crate::{
2    node::{Node},
3    edge::{Edge}, subgraph::Subgraph,
4};
5use std::io::prelude::*;
6use std::io;
7
8/// Entry point of this library, use `to_dot_string` to get the string output.
9pub struct Graph {
10    name: String,
11    kind: Kind,
12    nodes: Vec<Node>,
13    edges: Vec<Edge>,
14    subgraph: Vec<Subgraph>
15}
16
17impl Graph {
18    pub fn new(name: &str, kind: Kind) -> Graph {
19        Graph { name: String::from(name), kind: kind, nodes: vec![], edges: vec![], subgraph: vec![] }
20    }
21
22    pub fn add_node(&mut self, node: Node) -> () {
23        self.nodes.push(node);
24    }
25
26    pub fn add_edge(&mut self, edge: Edge) -> () {
27        self.edges.push(edge);
28    }
29
30    pub fn add_subgraph(&mut self, subgraph: Subgraph) -> () {
31        self.subgraph.push(subgraph.edgeop(self.kind.edgeop()))
32    }
33
34    pub fn to_dot_string(&self) -> io::Result<String> {
35        let mut writer = Vec::new();
36        self.render_opts(&mut writer).unwrap();
37        let mut s = String::new();
38        Read::read_to_string(&mut &*writer, &mut s)?;
39        Ok(s)
40    }
41
42    /// Renders graph `g` into the writer `w` in DOT syntax.
43    /// (Main entry point for the library.)
44    fn render_opts<'a,
45                    W: Write>
46        (&self,
47        w: &mut W)
48        -> io::Result<()> {
49        fn writeln<W: Write>(w: &mut W, arg: &[&str]) -> io::Result<()> {
50            for &s in arg {
51                w.write_all(s.as_bytes())?;
52            }
53            write!(w, "\n")
54        }
55
56        fn indent<W: Write>(w: &mut W) -> io::Result<()> {
57            w.write_all(b"    ")
58        }
59
60        writeln(w, &[self.kind.keyword(), " ", self.name.as_str(), " {"])?;
61        for n in self.subgraph.iter() {
62            indent(w)?;
63            let mut text: Vec<&str> = vec![];
64            let subgraph_dot_string: String = n.to_dot_string();
65            text.push(&subgraph_dot_string.as_str());
66            writeln(w, &text)?;
67        }
68
69        for n in self.nodes.iter() {
70            indent(w)?;
71            let mut text: Vec<&str> = vec![];
72            let node_dot_string: String = n.to_dot_string();
73            text.push(&node_dot_string.as_str());
74            writeln(w, &text)?;
75        }
76
77        let edge_symbol = self.kind.edgeop();
78        for e in self.edges.iter() {
79            indent(w)?;
80            let mut text: Vec<&str> = vec![];
81            let edge_dot_string: String = e.to_dot_string(edge_symbol);
82            text.push(&edge_dot_string.as_str());
83            writeln(w, &text)?;
84        }
85
86        writeln(w, &["}"])
87    }
88}
89
90/// Graph kind determines if `digraph` or `graph` is used as keyword
91/// for the graph.
92#[derive(Copy, Clone, PartialEq, Eq, Debug)]
93pub enum Kind {
94    Digraph,
95    Graph,
96}
97
98impl Kind {
99    /// The keyword to use to introduce the graph.
100    /// Determines which edge syntax must be used, and default style.
101    pub fn keyword(&self) -> &'static str {
102        match *self {
103            Kind::Digraph => "digraph",
104            Kind::Graph => "graph"
105        }
106    }
107
108    /// The edgeop syntax to use for this graph kind.
109    pub fn edgeop(&self) -> &'static str {
110        match *self {
111            Kind::Digraph => "->",
112            Kind::Graph => "--",
113        }
114    }
115}