1use crate::graph::csr::{CsrLayout, DirectedCsrGraph, NodeValues, UndirectedCsrGraph};
2use crate::index::Idx;
3use crate::input::EdgeList;
4
5use gdl::CypherValue;
6
7#[cfg(feature = "dotgraph")]
8use crate::input::DotGraph;
9#[cfg(feature = "dotgraph")]
10use linereader::LineReader;
11#[cfg(feature = "dotgraph")]
12use std::fmt::Write;
13#[cfg(feature = "dotgraph")]
14use std::hash::Hash;
15
16pub struct MyCypherValue<'a>(&'a CypherValue);
18
19impl From<MyCypherValue<'_>> for () {
20 fn from(_: MyCypherValue) -> Self {}
21}
22
23macro_rules! impl_from_cypher_value {
24 ($enum:path, $ty:ty) => {
25 impl<'a> ::std::convert::From<$crate::input::gdl::MyCypherValue<'a>> for $ty {
26 fn from(cv: $crate::input::gdl::MyCypherValue) -> Self {
27 if let $enum(f) = cv.0 {
28 *f as $ty
29 } else {
30 panic!("expected {} value", stringify!($ty))
31 }
32 }
33 }
34 };
35}
36
37impl_from_cypher_value!(CypherValue::Float, f32);
38impl_from_cypher_value!(CypherValue::Float, f64);
39impl_from_cypher_value!(CypherValue::Integer, i32);
40impl_from_cypher_value!(CypherValue::Integer, i64);
41impl_from_cypher_value!(CypherValue::Integer, isize);
42impl_from_cypher_value!(CypherValue::Integer, u32);
43impl_from_cypher_value!(CypherValue::Integer, u64);
44impl_from_cypher_value!(CypherValue::Integer, usize);
45
46impl<'gdl, NI, EV> From<&'gdl gdl::Graph> for EdgeList<NI, EV>
47where
48 NI: Idx,
49 EV: From<MyCypherValue<'gdl>> + Default + Send + Sync,
50{
51 fn from(gdl_graph: &'gdl gdl::Graph) -> Self {
52 let edges = gdl_graph
53 .relationships()
54 .map(|r| {
55 let source = gdl_graph.get_node(r.source()).unwrap().id();
56 let target = gdl_graph.get_node(r.target()).unwrap().id();
57
58 let value = if let Some(k) = r.property_keys().next() {
59 EV::from(MyCypherValue(r.property_value(k).unwrap()))
60 } else {
61 EV::default()
62 };
63
64 (NI::new(source), NI::new(target), value)
65 })
66 .collect::<Vec<_>>();
67
68 EdgeList::new(edges)
69 }
70}
71
72impl<'gdl, NV> From<&'gdl gdl::Graph> for NodeValues<NV>
73where
74 NV: From<MyCypherValue<'gdl>> + Default + Send + Sync,
75{
76 fn from(gdl_graph: &'gdl gdl::Graph) -> Self {
77 let mut node_values = Vec::with_capacity(gdl_graph.node_count());
78 node_values.resize_with(gdl_graph.node_count(), || NV::default());
79
80 gdl_graph.nodes().for_each(|n| {
81 if let Some(k) = n.property_keys().next() {
82 node_values[n.id()] = NV::from(MyCypherValue(n.property_value(k).unwrap()));
83 }
84 });
85
86 NodeValues::new(node_values)
87 }
88}
89
90#[cfg(feature = "dotgraph")]
91impl<NI, Label> From<&gdl::Graph> for DotGraph<NI, Label>
92where
93 NI: Idx,
94 Label: Idx + Hash,
95{
96 fn from(gdl_graph: &gdl::Graph) -> Self {
102 fn degree(gdl_graph: &gdl::Graph, node: &gdl::graph::Node) -> usize {
103 let mut degree = 0;
104
105 for rel in gdl_graph.relationships() {
106 if rel.source() == node.variable() {
107 degree += 1;
108 }
109 if rel.target() == node.variable() {
110 degree += 1;
111 }
112 }
113 degree
114 }
115
116 let header = format!(
117 "t {} {}",
118 gdl_graph.node_count(),
119 gdl_graph.relationship_count()
120 );
121
122 let mut nodes_string = String::from("");
123
124 let mut sorted_nodes = gdl_graph.nodes().collect::<Vec<_>>();
125 sorted_nodes.sort_by_key(|node| node.id());
126
127 for node in sorted_nodes {
128 let id = node.id();
129 let label = node.labels().next().expect("Single label expected");
130 let degree = degree(gdl_graph, node);
131 let _ = writeln!(nodes_string, "v {id} {} {degree}", &label[1..]);
132 }
133
134 let mut rels_string = String::from("");
135
136 let mut sorted_rels = gdl_graph.relationships().collect::<Vec<_>>();
137 sorted_rels.sort_by_key(|rel| (rel.source(), rel.target()));
138
139 for rel in sorted_rels {
140 let source_id = gdl_graph
141 .get_node(rel.source())
142 .expect("Source expected")
143 .id();
144 let target_id = gdl_graph
145 .get_node(rel.target())
146 .expect("Target expected")
147 .id();
148 let _ = writeln!(rels_string, "e {source_id} {target_id}");
149 }
150
151 let input = format!("{header}\n{nodes_string}{rels_string}");
152 let reader = LineReader::new(input.as_bytes());
153
154 DotGraph::<NI, Label>::try_from(reader).expect("GDL to .graph conversion failed")
155 }
156}
157
158impl<'a, NI, NV, EV> From<(&'a gdl::Graph, CsrLayout)> for DirectedCsrGraph<NI, NV, EV>
159where
160 NI: Idx,
161 NV: From<MyCypherValue<'a>> + Default + Copy + Send + Sync,
162 EV: From<MyCypherValue<'a>> + Default + Copy + Send + Sync,
163{
164 fn from((gdl_graph, csr_layout): (&'a gdl::Graph, CsrLayout)) -> Self {
165 let node_values = NodeValues::from(gdl_graph);
166 let edge_list = EdgeList::from(gdl_graph);
167 DirectedCsrGraph::from((node_values, edge_list, csr_layout))
168 }
169}
170
171impl<NI, NV, EV> From<(gdl::Graph, CsrLayout)> for DirectedCsrGraph<NI, NV, EV>
172where
173 NI: Idx,
174 for<'a> NV: From<MyCypherValue<'a>> + Default + Copy + Send + Sync,
175 for<'a> EV: From<MyCypherValue<'a>> + Default + Copy + Send + Sync,
176{
177 fn from((gdl_graph, csr_layout): (gdl::Graph, CsrLayout)) -> Self {
178 let node_values = NodeValues::from(&gdl_graph);
179 let edge_list = EdgeList::from(&gdl_graph);
180 DirectedCsrGraph::from((node_values, edge_list, csr_layout))
181 }
182}
183
184impl<'a, NI, NV, EV> From<(&'a gdl::Graph, CsrLayout)> for UndirectedCsrGraph<NI, NV, EV>
185where
186 NI: Idx,
187 NV: From<MyCypherValue<'a>> + Default + Copy + Send + Sync,
188 EV: From<MyCypherValue<'a>> + Default + Copy + Send + Sync,
189{
190 fn from((gdl_graph, csr_layout): (&'a gdl::Graph, CsrLayout)) -> Self {
191 let node_values = NodeValues::from(gdl_graph);
192 let edge_list = EdgeList::from(gdl_graph);
193 UndirectedCsrGraph::from((node_values, edge_list, csr_layout))
194 }
195}
196
197impl<NI, NV, EV> From<(gdl::Graph, CsrLayout)> for UndirectedCsrGraph<NI, NV, EV>
198where
199 NI: Idx,
200 for<'a> NV: From<MyCypherValue<'a>> + Default + Copy + Send + Sync,
201 for<'a> EV: From<MyCypherValue<'a>> + Default + Copy + Send + Sync,
202{
203 fn from((gdl_graph, csr_layout): (gdl::Graph, CsrLayout)) -> Self {
204 let node_values = NodeValues::from(&gdl_graph);
205 let edge_list = EdgeList::from(&gdl_graph);
206 UndirectedCsrGraph::from((node_values, edge_list, csr_layout))
207 }
208}