Skip to main content

marser_trace_schema/
io.rs

1//! AI assistance: this file was written with AI assistance. The maintainer reviewed it and did not find errors.
2
3use 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}