1pub mod dot;
2
3use crate::{DiGraph, EmptyPayload};
4use graphviz_rust::attributes::{EdgeAttributes, NodeAttributes};
5use graphviz_rust::cmd::{CommandArg, Format};
6use graphviz_rust::dot_generator::*;
7use graphviz_rust::dot_structures::*;
8use graphviz_rust::printer::{DotPrinter, PrinterContext};
9use graphviz_rust::{exec, exec_dot};
10use std::hash::Hash;
11
12use self::dot::{DotProcessor, ToStringProcessor};
13pub struct DotGraphVisualizer<'a, NId, NL, EL>
14where
15 NId: Eq + Hash,
16{
17 graph: &'a DiGraph<NId, NL, EL>,
18}
19
20impl<'a, NId, NL, EL> DotGraphVisualizer<'a, NId, NL, EL>
21where
22 NId: Eq + Hash + ToString,
23 NL: ToString,
24 EL: ToString,
25{
26 pub fn str_to_dot_file(&self, path: &str) -> std::io::Result<String> {
27 self.to_dot_file(path, ToStringProcessor {})
28 }
29}
30
31impl<'a, NId, NL, EL> DotGraphVisualizer<'a, NId, NL, EL>
32where
33 NId: Eq + Hash,
34{
35 pub fn new(graph: &'a DiGraph<NId, NL, EL>) -> Self {
36 Self { graph }
37 }
38 pub fn to_dot<P>(&self, processor: P) -> Graph
39 where
40 P: DotProcessor<'a, NId, NL, EL>,
41 {
42 let mut dot = graph!(strict di id!("di_graph"));
43 for (id, pl) in self.graph.nodes.iter() {
44 dot.add_stmt(processor.node(id, pl));
45 }
46 for (from, to_map) in self.graph.edges.iter() {
47 for (to, pl) in to_map.iter() {
48 dot.add_stmt(processor.edge(from, to, pl))
49 }
50 }
51 dot
52 }
53
54 pub fn to_dot_file<P>(&'a self, path: &str, processor: P) -> std::io::Result<String>
55 where
56 P: DotProcessor<'a, NId, NL, EL>,
57 {
58 vis_to_file(self.to_dot(processor), path.to_string())
59 }
60}
61
62pub fn vis(dot_graph: Graph) -> String {
63 dot_graph.print(&mut PrinterContext::default())
64}
65
66pub fn vis_to_file(dot_graph: Graph, path: String) -> std::io::Result<String> {
67 let ext = path
68 .split(".")
69 .last()
70 .map(|x| x.to_lowercase())
71 .unwrap_or("svg".to_string());
72 let format = match ext.as_str() {
73 "svg" => Format::Svg,
74 "dot" => Format::Dot,
75 _ => panic!("dot or svg"),
76 };
77 exec(
78 dot_graph,
79 &mut PrinterContext::default(),
80 vec![CommandArg::Output(path), CommandArg::Format(format)],
81 )
82}