use std::path::Path;
use obj::{Db, DumpRecord};
use crate::DumpFormat;
pub(crate) fn run(path: &Path, collection: &str, limit: usize, format: DumpFormat) -> i32 {
let db = match Db::open(path) {
Ok(db) => db,
Err(err) => {
eprintln!("error: failed to open {}: {err}", path.display());
return 2;
}
};
let iter = match db.dump_raw(collection, limit) {
Ok(it) => it,
Err(err) => {
eprintln!("error: dump failed: {err}");
return 2;
}
};
println!("## {collection}");
println!("limit: {}", if limit == 0 { "none" } else { "set" });
println!();
let mut printed: u64 = 0;
for step in iter {
match step {
Ok(record) => {
print_record(&record, format);
printed = printed.saturating_add(1);
}
Err(err) => {
eprintln!("error: per-doc decode failure: {err}");
return 2;
}
}
}
println!("# emitted: {printed}");
0
}
fn print_record(record: &DumpRecord, format: DumpFormat) {
println!("- id: {}", record.id.get());
println!(" collection_id: {}", record.header.collection_id);
println!(" type_version: {}", record.header.type_version);
println!(" payload_len: {}", record.header.payload_len);
println!(" payload_crc32c: {:#010x}", record.header.payload_crc32c);
if matches!(format, DumpFormat::Hex) {
println!(" payload_hex: {}", encode_hex(&record.payload));
}
}
fn encode_hex(bytes: &[u8]) -> String {
const HEX_DIGITS: &[u8; 16] = b"0123456789abcdef";
let mut out: Vec<u8> = Vec::with_capacity(bytes.len().saturating_mul(2));
for b in bytes {
out.push(HEX_DIGITS[usize::from(b >> 4)]);
out.push(HEX_DIGITS[usize::from(b & 0x0F)]);
}
String::from_utf8(out).unwrap_or_default()
}