//! JSON Lines sink — one structured row per line, constant memory. //! //! Suited for piping into `jq`, importing into pandas / DuckDB's //! `read_json_auto`, or feeding downstream tooling that expects a //! line-delimited stream rather than a single megaobject. use std::io::{self, Write}; use serde::Serialize; use crate::disasm::RichDisasmItem; #[derive(Serialize)] struct JsonRow<'a> { addr: u32, raw: u32, mnemonic: &'a str, operands: &'a str, disasm: &'a str, #[serde(skip_serializing_if = "Option::is_none")] ext_mnemonic: Option<&'a str>, #[serde(skip_serializing_if = "Option::is_none")] ext_operands: Option<&'a str>, #[serde(skip_serializing_if = "Option::is_none")] ext_disasm: Option<&'a str>, #[serde(skip_serializing_if = "Option::is_none")] branch_target: Option, section: &'a str, #[serde(skip_serializing_if = "Option::is_none")] function: Option, #[serde(skip_serializing_if = "Option::is_none")] label: Option<&'a str>, } /// Write each item as a single JSON object on its own line. Returns the /// number of rows written. pub fn write_jsonl<'a, W: Write>( out: &mut W, items: impl IntoIterator>, ) -> io::Result { let mut count: u64 = 0; for ri in items { let t = &ri.item.text; let row = JsonRow { addr: ri.item.addr, raw: ri.item.raw, mnemonic: &t.mnemonic, operands: &t.operands, disasm: &t.disasm, ext_mnemonic: t.ext_mnemonic.as_deref(), ext_operands: t.ext_operands.as_deref(), ext_disasm: t.ext_disasm.as_deref(), branch_target: t.branch_target, section: ri.section, function: ri.function, label: ri.label, }; serde_json::to_writer(&mut *out, &row)?; out.write_all(b"\n")?; count += 1; } Ok(count) }