use std::error::Error; use std::fs::{self, File}; use std::io::{BufRead, BufReader, BufWriter, Write}; use std::path::Path; use serde::{Deserialize, Serialize}; use crate::{Delta, Edge, Graph, Node}; pub fn write_graph_artifact( directory: impl AsRef, graph: &Graph, delta: &[Delta], ) -> std::io::Result<()> { let directory = directory.as_ref(); fs::create_dir_all(directory)?; write_json_file(directory.join("metadata.json"), &graph.metadata)?; write_jsonl_file(directory.join("nodes.jsonl"), graph.nodes.values())?; write_jsonl_file(directory.join("edges.jsonl"), graph.edges.iter())?; write_jsonl_file(directory.join("delta.jsonl"), delta.iter())?; Ok(()) } pub fn read_graph_artifact(directory: impl AsRef) -> std::io::Result { let directory = directory.as_ref(); let metadata = read_json_file(directory.join("metadata.json"))?; let nodes: Vec = read_jsonl_file(directory.join("nodes.jsonl"))?; let edges: Vec = read_jsonl_file(directory.join("edges.jsonl"))?; let mut graph = Graph::new(metadata); for node in nodes { graph.add_node(node).map_err(invalid_data)?; } for edge in edges { graph.add_edge(edge).map_err(invalid_data)?; } Ok(graph) } pub fn read_graph_delta(directory: impl AsRef) -> std::io::Result> { read_jsonl_file(directory.as_ref().join("delta.jsonl")) } fn write_json_file(path: impl AsRef, value: &impl Serialize) -> std::io::Result<()> { let file = File::create(path)?; let writer = BufWriter::new(file); serde_json::to_writer_pretty(writer, value).map_err(invalid_data) } fn read_json_file Deserialize<'de>>(path: impl AsRef) -> std::io::Result { let file = File::open(path)?; let reader = BufReader::new(file); serde_json::from_reader(reader).map_err(invalid_data) } fn write_jsonl_file<'a, T: 'a + Serialize>( path: impl AsRef, values: impl IntoIterator, ) -> std::io::Result<()> { let file = File::create(path)?; let mut writer = BufWriter::new(file); for value in values { serde_json::to_writer(&mut writer, value).map_err(invalid_data)?; writer.write_all(b"\n")?; } Ok(()) } fn read_jsonl_file Deserialize<'de>>( path: impl AsRef, ) -> std::io::Result> { let file = File::open(path)?; let reader = BufReader::new(file); let mut values = Vec::new(); for line in reader.lines() { let line = line?; if line.trim().is_empty() { continue; } values.push(serde_json::from_str(&line).map_err(invalid_data)?); } Ok(values) } fn invalid_data(error: impl Error + Send + Sync + 'static) -> std::io::Error { std::io::Error::new(std::io::ErrorKind::InvalidData, error) }