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 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}