66 lines
2.0 KiB
Rust
66 lines
2.0 KiB
Rust
//! 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<u32>,
|
|
section: &'a str,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
function: Option<u32>,
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
label: Option<&'a str>,
|
|
is_data: bool,
|
|
}
|
|
|
|
/// 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<Item = RichDisasmItem<'a>>,
|
|
) -> io::Result<u64> {
|
|
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,
|
|
is_data: ri.is_data,
|
|
};
|
|
serde_json::to_writer(&mut *out, &row)?;
|
|
out.write_all(b"\n")?;
|
|
count += 1;
|
|
}
|
|
Ok(count)
|
|
}
|