marser_trace_schema/
io.rs1use std::fs::File;
4use std::io::{self, BufRead, BufReader, Read};
5use std::path::Path;
6
7use serde::Deserialize;
8
9use crate::event::NodeTrace;
10use crate::session::TraceSession;
11use crate::version::check_trace_version;
12
13#[derive(Clone, Copy, Debug, PartialEq, Eq)]
14pub enum TraceFormat {
15 Json,
16 Jsonl,
17}
18
19#[derive(Deserialize)]
20struct TraceJsonEnvelope {
21 trace_version: Option<u32>,
22 nodes: Vec<NodeTrace>,
23 source_text: Option<String>,
24}
25
26pub fn load_trace_file(
27 path: impl AsRef<Path>,
28 format: Option<TraceFormat>,
29) -> io::Result<TraceSession> {
30 let path = path.as_ref();
31 let file = File::open(path)?;
32 let format = match format {
33 Some(format) => format,
34 None => detect_trace_format(path)?,
35 };
36 match format {
37 TraceFormat::Json => load_json(file),
38 TraceFormat::Jsonl => load_jsonl(file),
39 }
40}
41
42pub fn detect_trace_format(path: impl AsRef<Path>) -> io::Result<TraceFormat> {
43 let mut file = File::open(path)?;
44 let mut buf = [0_u8; 1];
45 loop {
46 let read = file.read(&mut buf)?;
47 if read == 0 {
48 return Ok(TraceFormat::Jsonl);
49 }
50 match buf[0] {
51 b' ' | b'\n' | b'\r' | b'\t' => continue,
52 b'[' | b'{' => return Ok(TraceFormat::Json),
53 _ => return Ok(TraceFormat::Jsonl),
54 }
55 }
56}
57
58pub fn load_json(reader: impl Read) -> io::Result<TraceSession> {
59 let value: serde_json::Value = serde_json::from_reader(reader).map_err(io::Error::other)?;
60 if value.is_array() {
61 let nodes: Vec<NodeTrace> = serde_json::from_value(value).map_err(io::Error::other)?;
62 return Ok(TraceSession::from_events(nodes));
63 }
64 let payload: TraceJsonEnvelope = serde_json::from_value(value).map_err(io::Error::other)?;
65 check_trace_version(payload.trace_version).map_err(|e| io::Error::other(e.to_string()))?;
66 let mut session = TraceSession::from_events(payload.nodes);
67 if let Some(source_text) = payload.source_text {
68 session.set_source_text(source_text);
69 }
70 Ok(session)
71}
72
73pub fn load_jsonl(reader: impl Read) -> io::Result<TraceSession> {
74 let mut events = Vec::new();
75 for line in BufReader::new(reader).lines() {
76 let line = line?;
77 if line.trim().is_empty() {
78 continue;
79 }
80 let event: NodeTrace = serde_json::from_str(&line).map_err(io::Error::other)?;
81 events.push(event);
82 }
83 Ok(TraceSession::from_events(events))
84}