Skip to main content

mpeg_syntax_dump/render/
mod.rs

1pub mod text;
2pub mod ansi;
3pub mod compact;
4
5use std::io;
6
7use crate::types::Value;
8
9/// Default number of spaces per indentation level.
10pub const INDENT_WIDTH: usize = 4;
11
12/// Maximum number of bytes shown in a raw hex dump before truncation.
13pub const MAX_HEX_BYTES: usize = 128;
14
15/// Number of bytes per hex dump line.
16pub const HEX_BYTES_PER_LINE: usize = 16;
17
18const INDENT_BUF: &[u8; 32] = b"                                ";
19
20/// Write indentation spaces to the output.
21pub fn write_indent(w: &mut impl io::Write, depth: usize) -> io::Result<()> {
22    let total = depth * INDENT_WIDTH;
23    if total == 0 {
24        return Ok(());
25    }
26    if total <= INDENT_BUF.len() {
27        w.write_all(&INDENT_BUF[..total])
28    } else {
29        let buf = vec![b' '; total];
30        w.write_all(&buf)
31    }
32}
33
34/// Format a value for display, returning the formatted string.
35pub fn format_value(value: &Value) -> String {
36    value.to_string()
37}
38
39/// Format term annotations as a trailing comment: `  /* name: value */`
40/// If multiple terms, they are comma-separated within a single comment.
41pub fn format_term_annotations(terms: &[crate::types::TermAnnotation<'_>]) -> String {
42    if terms.is_empty() {
43        return String::new();
44    }
45    let inner: Vec<String> = terms
46        .iter()
47        .map(|t| format!("{}: {}", t.name, t.value))
48        .collect();
49    format!("  /* {} */", inner.join(", "))
50}
51
52/// Format raw bytes as hex dump lines. Returns a Vec of formatted lines.
53/// Each line contains up to 16 bytes, with a space separator after the 8th byte.
54/// If the data exceeds `MAX_HEX_BYTES`, the dump is truncated and ends with `...`.
55pub fn format_hex_dump(data: &[u8]) -> Vec<String> {
56    let truncated = data.len() > MAX_HEX_BYTES;
57    let show_bytes = if truncated { MAX_HEX_BYTES } else { data.len() };
58    let mut lines = Vec::new();
59
60    for chunk_start in (0..show_bytes).step_by(HEX_BYTES_PER_LINE) {
61        let chunk_end = (chunk_start + HEX_BYTES_PER_LINE).min(show_bytes);
62        let chunk = &data[chunk_start..chunk_end];
63        let mut line = String::new();
64        for (i, byte) in chunk.iter().enumerate() {
65            if i > 0 {
66                line.push(' ');
67            }
68            if i == 8 {
69                line.push(' ');
70            }
71            line.push_str(&format!("{byte:02x}"));
72        }
73        lines.push(line);
74    }
75
76    if truncated {
77        lines.push("...".to_string());
78    }
79
80    lines
81}