1use std::{collections::HashMap, error::Error, fmt};
30
31use petgraph::{
32 dot::{Config, Dot},
33 graph::NodeIndex,
34 stable_graph::StableGraph,
35 visit::{EdgeRef, IntoEdgeReferences},
36 Undirected,
37};
38
39use crate::ForceGraph;
40
41#[derive(Clone, Debug)]
43pub enum DotParseError {
44 IndexNotFound(String),
46}
47
48impl fmt::Display for DotParseError {
49 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50 match self {
51 Self::IndexNotFound(n) => write!(f, "Index for {n} was not found in the graph"),
52 }
53 }
54}
55
56impl Error for DotParseError {}
57
58pub fn graph_to_dot<N, E>(graph: &ForceGraph<N, E>) -> Result<String, DotParseError> {
60 let mut new_graph: StableGraph<String, (), Undirected> = StableGraph::default();
61 let mut indices: HashMap<String, NodeIndex> = HashMap::new();
62
63 for idx in graph.node_indices() {
64 let node = &graph[idx];
65
66 indices.insert(node.name.clone(), new_graph.add_node(node.name.clone()));
67 }
68
69 for edge in graph.edge_references() {
70 let source = &graph[edge.source()].name;
71 let target = &graph[edge.target()].name;
72
73 let source_idx = match indices.get(source) {
74 Some(idx) => *idx,
75 None => return Err(DotParseError::IndexNotFound(source.clone())),
76 };
77
78 let target_idx = match indices.get(target) {
79 Some(idx) => *idx,
80 None => return Err(DotParseError::IndexNotFound(target.clone())),
81 };
82
83 new_graph.add_edge(source_idx, target_idx, ());
84 }
85
86 Ok(format!("{:?}", Dot::with_config(&new_graph, &[Config::EdgeNoLabel])).replace("\\\"", ""))
87}