1use std::fs::File;
2use std::io::prelude::*;
3use std::io::BufWriter;
4use std::path::Path;
5
6use anyhow::Result;
7use log::*;
8use petgraph::visit::*;
9
10use crate::ids::codes::ns_of_book_code;
11
12use super::{IdGraph, IdNode};
13
14fn gml_begin<W: Write>(w: &mut W) -> Result<()> {
15 writeln!(w, "graph [")?;
16 Ok(())
17}
18
19fn gml_end<W: Write>(w: &mut W) -> Result<()> {
20 writeln!(w, "]")?;
21 Ok(())
22}
23
24fn gml_node<W: Write>(w: &mut W, graph: &IdGraph, v: IdNode) -> Result<()> {
25 let node = graph.node_weight(v).unwrap();
26 writeln!(w, " node [")?;
27 writeln!(w, " id {}", node.code)?;
28 let ns = ns_of_book_code(node.code).unwrap();
29 writeln!(w, " namespace \"{}\"", ns.name())?;
30 if let Some(ref l) = node.label {
31 writeln!(w, " label \"{}\"", l)?;
32 }
33 writeln!(w, " ]")?;
34 Ok(())
35}
36
37fn gml_edge<W: Write>(w: &mut W, graph: &IdGraph, sv: IdNode, dv: IdNode) -> Result<()> {
38 let src = graph.node_weight(sv).unwrap();
39 let dst = graph.node_weight(dv).unwrap();
40 writeln!(w, " edge [")?;
41 writeln!(w, " source {}", src.code)?;
42 writeln!(w, " target {}", dst.code)?;
43 writeln!(w, " ]")?;
44 Ok(())
45}
46
47pub fn save_gml<P: AsRef<Path>>(graph: &IdGraph, path: P) -> Result<()> {
49 info!("saving graph to {}", path.as_ref().to_string_lossy());
50 let out = File::create(path)?;
51 let mut out = BufWriter::new(out);
52 gml_begin(&mut out)?;
53 for n in graph.node_indices() {
54 gml_node(&mut out, graph, n)?;
55 }
56 for e in graph.edge_references() {
57 gml_edge(&mut out, graph, e.source(), e.target())?;
58 }
59 gml_end(&mut out)?;
60 Ok(())
61}