graphviz_dot_parser/
types.rs

1use petgraph::EdgeType;
2use petgraph::Graph;
3use std::collections::HashMap;
4
5pub struct GraphAST {
6    pub is_strict: bool,
7    pub is_directed: bool,
8    pub id: Option<String>,
9    pub stmt: Vec<Stmt>,
10}
11
12impl GraphAST {
13    fn to_graph_internal<Ty: EdgeType, N, E>(
14        &self,
15        node_parser: &dyn Fn(&String, &Attributes) -> N,
16        edge_parser: &dyn Fn(&Attributes) -> E,
17        g: &mut Graph<N, E, Ty>,
18    ) {
19        let mut nodes = HashMap::new();
20        for stmt in &self.stmt {
21            match stmt {
22                Stmt::Node(n, attr) => {
23                    let idx = g.add_node(node_parser(n, attr));
24                    nodes.insert(n, idx);
25                }
26                Stmt::Edge(n1, n2, attrs) => {
27                    let e = edge_parser(attrs);
28                    g.add_edge(*nodes.get(&n1).unwrap(), *nodes.get(&n2).unwrap(), e);
29                }
30                _ => {}
31            }
32        }
33    }
34
35    pub fn to_directed_graph_using<N, E>(
36        &self,
37        new_node: &dyn Fn(&String, &Attributes) -> N,
38        new_edge: &dyn Fn(&Attributes) -> E,
39    ) -> Option<Graph<N, E>> {
40        if self.is_directed {
41            let mut g = Graph::new();
42            self.to_graph_internal(new_node, new_edge, &mut g);
43            Some(g)
44        } else {
45            None
46        }
47    }
48
49    pub fn to_undirected_graph_using<N, E>(
50        &self,
51        new_node: &dyn Fn(&String, &Attributes) -> N,
52        new_edge: &dyn Fn(&Attributes) -> E,
53    ) -> Option<Graph<N, E, petgraph::Undirected>> {
54        if !self.is_directed {
55            let mut g = Graph::new_undirected();
56            self.to_graph_internal(new_node, new_edge, &mut g);
57            Some(g)
58        } else {
59            None
60        }
61    }
62
63    pub fn to_directed_graph(&self) -> Option<Graph<String, ()>> {
64        self.to_directed_graph_using(&|n, _| n.clone(), &|_| ())
65    }
66
67    pub fn to_undirected_graph(&self) -> Option<Graph<String, (), petgraph::Undirected>> {
68        self.to_undirected_graph_using(&|n, _| n.clone(), &|_| ())
69    }
70}
71
72#[derive(Eq, PartialEq, Debug)]
73pub enum AttributeType {
74    Graph,
75    Node,
76    Edge,
77}
78
79pub type Attributes = Vec<(String, String)>;
80
81#[derive(Eq, PartialEq, Debug)]
82pub enum Stmt {
83    // Many features are currently not supported
84    Node(String, Attributes),
85    Edge(String, String, Attributes),
86    Attr(AttributeType, Attributes),
87    Assign(String, String),
88    SubGraph(Option<String>, Vec<Stmt>),
89}
90
91#[cfg(test)]
92mod tests {
93    use crate::types::*;
94    #[test]
95    fn test_petgraph_conversion_directed() {
96        let g = GraphAST {
97            is_strict: false,
98            is_directed: true,
99            id: None,
100            stmt: vec![
101                Stmt::Node(String::from("1"), vec![]),
102                Stmt::Node(String::from("2"), vec![]),
103                Stmt::Edge(String::from("1"), String::from("2"), vec![]),
104            ],
105        };
106        let graph = g.to_undirected_graph();
107        assert_eq!(graph.is_none(), true);
108        let graph = g.to_directed_graph();
109        assert_eq!(graph.is_some(), true);
110        let graph = graph.unwrap();
111        assert_eq!(graph.is_directed(), true);
112        assert_eq!(graph.node_count(), 2);
113        assert_eq!(graph.edge_count(), 1);
114    }
115
116    #[test]
117    fn test_petgraph_conversion_undirected() {
118        let g = GraphAST {
119            is_strict: false,
120            is_directed: false,
121            id: None,
122            stmt: vec![
123                Stmt::Node(String::from("1"), vec![]),
124                Stmt::Node(String::from("2"), vec![]),
125                Stmt::Edge(String::from("1"), String::from("2"), vec![]),
126            ],
127        };
128        let graph = g.to_directed_graph();
129        assert_eq!(graph.is_none(), true);
130        let graph = g.to_undirected_graph();
131        assert_eq!(graph.is_some(), true);
132        let graph = graph.unwrap();
133        assert_eq!(graph.is_directed(), false);
134        assert_eq!(graph.node_count(), 2);
135        assert_eq!(graph.edge_count(), 1);
136    }
137}