//! Which gate stops the resources that never decode? //! Usage: gate_histogram [max_resources] use sylpheed_formats::mesh::{debug_best_rejection, xbg7_resource_names, Xbg7Model}; use std::collections::{BTreeMap, HashSet}; fn main() { let dir = std::env::args().nth(1).expect("resource3d dir"); let cap: usize = std::env::args().nth(2).and_then(|s| s.parse().ok()).unwrap_or(usize::MAX); let mut files: Vec<_> = std::fs::read_dir(&dir) .unwrap() .flatten() .map(|e| e.path()) .filter(|p| p.extension().and_then(|s| s.to_str()) == Some("xpr")) .collect(); files.sort(); let mut hist: BTreeMap = BTreeMap::new(); let mut done = 0usize; for f in &files { if done >= cap { break; } let Ok(bytes) = std::fs::read(f) else { continue }; let names = xbg7_resource_names(&bytes); if names.is_empty() { continue; } let got: HashSet = Xbg7Model::anchor_models_cancellable(&bytes, 0.0, &|| false) .into_iter() .map(|m| m.name) .collect(); for n in names.iter().filter(|n| !got.contains(*n)) { if done >= cap { break; } done += 1; if let Some((rank, why)) = debug_best_rejection(&bytes, n) { let e = hist.entry(rank).or_insert((0, String::new())); e.0 += 1; if e.1.is_empty() { e.1 = format!("{n}: {why}"); } } } } println!("furthest gate reached, over {done} resources that never decode:"); let label = |r: usize| match r { 0 => "no gate reached", 1 => "index out of range", 2 => "buffer not covered by indices", 3 => "degenerate / implausible positions", 4 => "connectivity (mean edge / diagonal)", 5 => "winding consistency", 9 => "grouped pool (different path)", _ => "?", }; for (r, (n, ex)) in &hist { println!(" {:<38} {n:>5} e.g. {ex}", label(*r)); } }