Skip to main content

memvid_cli/commands/
debug.rs

1//! Debug command handler
2
3use std::path::PathBuf;
4
5use anyhow::{bail, Result};
6use clap::{ArgAction, Args};
7
8use crate::utils::open_read_only_mem;
9
10/// Arguments for the `debug-segment` subcommand
11#[derive(Args)]
12pub struct DebugSegmentArgs {
13    #[arg(value_name = "FILE", value_parser = clap::value_parser!(PathBuf))]
14    pub file: PathBuf,
15    #[arg(long = "segment-id", value_name = "ID")]
16    pub segment_id: u64,
17    #[arg(long = "hex-dump", action = ArgAction::SetTrue)]
18    pub hex_dump: bool,
19    #[arg(long = "max-bytes", value_name = "N", default_value = "256")]
20    pub max_bytes: usize,
21}
22
23/// Handler for `memvid debug-segment`
24pub fn handle_debug_segment(args: DebugSegmentArgs) -> Result<()> {
25    let mut mem = open_read_only_mem(&args.file)?;
26    let Some((descriptor, bytes)) = mem.read_vec_segment(args.segment_id)? else {
27        bail!(
28            "vector segment {} not found in {}",
29            args.segment_id,
30            args.file.display()
31        );
32    };
33
34    println!("Vector segment {}", descriptor.common.segment_id);
35    println!("  offset: {}", descriptor.common.bytes_offset);
36    println!("  length: {} bytes", descriptor.common.bytes_length);
37    println!("  checksum: {}", hex::encode(descriptor.common.checksum));
38    println!("  vectors: {}", descriptor.vector_count);
39    println!("  dimension: {}", descriptor.dimension);
40    println!("  compression: {:?}", descriptor.vector_compression);
41    println!("  bytes loaded: {}", bytes.len());
42
43    if args.hex_dump {
44        if args.max_bytes == 0 {
45            println!("Hex dump skipped: --max-bytes is 0");
46            return Ok(());
47        }
48        if bytes.is_empty() {
49            println!("Hex dump skipped: segment contains no bytes");
50            return Ok(());
51        }
52        let limit = bytes.len().min(args.max_bytes);
53        println!("Hex dump (showing {} of {} bytes):", limit, bytes.len());
54        for (row, chunk) in bytes[..limit].chunks(16).enumerate() {
55            let offset = row * 16;
56            print!("{offset:08x}: ");
57            for i in 0..16 {
58                if let Some(byte) = chunk.get(i) {
59                    print!("{byte:02x} ");
60                } else {
61                    print!("   ");
62                }
63            }
64            print!("|");
65            for byte in chunk {
66                let ch = if (0x20..=0x7e).contains(byte) {
67                    *byte as char
68                } else {
69                    '.'
70                };
71                print!("{ch}");
72            }
73            println!("|");
74        }
75    }
76
77    Ok(())
78}