//! Hex + ASCII rendering, shared by `read` and by `find`'s context blocks.

use std::fmt::Write as _;
use std::io::{self, Write};

fn ascii_gutter(row: &[u8]) -> String {
    row.iter()
        .map(|&b| {
            if (0x20..=0x7e).contains(&b) {
                b as char
            } else {
                '.'
            }
        })
        .collect()
}

/// Classic 16-bytes-per-line dump with absolute addresses in the left column.
pub fn hexdump(out: &mut impl Write, base: u64, data: &[u8], indent: &str) -> io::Result<()> {
    for (i, row) in data.chunks(16).enumerate() {
        let addr = base + (i * 16) as u64;
        let mut hex = String::with_capacity(50);
        for (j, b) in row.iter().enumerate() {
            if j == 8 {
                hex.push(' ');
            }
            // Writing into a String is infallible.
            let _ = write!(hex, "{b:02x} ");
        }
        writeln!(out, "{indent}{addr:012x}  {hex:<50}|{}|", ascii_gutter(row))?;
    }
    Ok(())
}
