fix(lint): clear the clippy gate across examples and tests

80 findings, not the 14 the first run showed -- clippy stops at the first
failing compilation unit, so `--keep-going` is what makes the list complete.

60 were machine-applicable (`cargo clippy --fix`). The rest by hand:

* five descending `sort_by` -> `sort_by_key(Reverse(..))`
* `chunks_exact(4)` on both sides of four zips, so the compared items stay
  `[u8; 4]` rather than one array against one slice
* three `type` aliases for the census maps and the captured-quad tuple
* `&PathBuf` -> `&Path` in two disc tests
* two range loops; one of them keeps `#[allow(needless_range_loop)]` with the
  reason -- the index is into a map's value, which changes each iteration
* the module doc list in `invert_capture` re-indented to markdown's rules
* `blit`'s eight arguments get `#[allow(too_many_arguments)]`, not a struct

One dead `let off = b.len();` in a `ratc` test is dropped rather than renamed.
The sibling test at :162 is the one that asserts an offset; if this one was
meant to as well, that is a test change and not a lint fix.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-09-12 16:42:41 +02:00
parent c6f7a18e30
commit ccd49ac31f
52 changed files with 121 additions and 93 deletions

View File

@@ -81,7 +81,7 @@ fn main() {
} }
let mut degen = 0usize; let mut degen = 0usize;
let (mut agree, mut counted) = (0usize, 0usize); let (mut agree, mut counted) = (0usize, 0usize);
for t in idx.chunks_exact(3) { for t in idx.as_chunks::<3>().0 {
let (x, y, z) = (t[0] as usize, t[1] as usize, t[2] as usize); let (x, y, z) = (t[0] as usize, t[1] as usize, t[2] as usize);
if x == y || y == z || x == z { if x == y || y == z || x == z {
degen += 1; degen += 1;

View File

@@ -43,8 +43,8 @@ fn main() {
let ar = PakArchive::open(root.join("dat/GP_TITLE.pak")).expect("GP_TITLE"); let ar = PakArchive::open(root.join("dat/GP_TITLE.pak")).expect("GP_TITLE");
let (mut ok, mut bad, mut missing) = (0, 0, 0); let (mut ok, mut bad, mut missing) = (0, 0, 0);
println!( println!(
"{:<7} {:<22} {:<10} {:<10} {}", "{:<7} {:<22} {:<10} {:<10} ",
"entry", "sprite", "expected", "accessor", "" "entry", "sprite", "expected", "accessor"
); );
for e in [2usize, 4, 5, 6] { for e in [2usize, 4, 5, 6] {
let by = ar.read(&ar.entries()[e]).expect("entry"); let by = ar.read(&ar.entries()[e]).expect("entry");

View File

@@ -81,8 +81,8 @@ fn main() {
} }
} }
println!( println!(
"{:<10} {:<22} {:<10} {:>10} {}", "{:<10} {:<22} {:<10} {:>10} measured blend",
"entry", "sprite", "+0x04", "bit 0x02", "measured blend" "entry", "sprite", "+0x04", "bit 0x02"
); );
let (mut tp, mut tn, mut fp, mut fnn, mut missing) = (0, 0, 0, 0, 0); let (mut tp, mut tn, mut fp, mut fnn, mut missing) = (0, 0, 0, 0, 0);
for &(e, n, additive) in MEASURED { for &(e, n, additive) in MEASURED {
@@ -269,6 +269,7 @@ fn decl_rivals() {
.filter(|(e, n, _)| decl.contains_key(&(*e, n.to_string()))) .filter(|(e, n, _)| decl.contains_key(&(*e, n.to_string())))
.collect(); .collect();
let mut rivals = 0; let mut rivals = 0;
#[allow(clippy::needless_range_loop)]
for w in 0..15 { for w in 0..15 {
for bit in 0..32 { for bit in 0..32 {
let (mut ok, mut s, mut c) = (true, false, false); let (mut ok, mut s, mut c) = (true, false, false);

View File

@@ -173,7 +173,7 @@ fn main() {
let (mut cover_exact, mut cover_short, mut idx_equal, mut idx_partial) = let (mut cover_exact, mut cover_short, mut idx_equal, mut idx_partial) =
(0usize, 0usize, 0usize, 0usize); (0usize, 0usize, 0usize, 0usize);
let mut rows: Vec<(usize, String)> = Vec::new(); let mut rows: Vec<(usize, String)> = Vec::new();
for (_, (voff, ibs, vcount)) in per_buf.iter() { for (voff, ibs, vcount) in per_buf.values() {
let batches = ibs.len(); let batches = ibs.len();
let total: u32 = ibs.iter().map(|i| i.icount).sum(); let total: u32 = ibs.iter().map(|i| i.icount).sum();
let lo = ibs.iter().map(|i| i.ibase).min().unwrap() as i64 - base_delta; let lo = ibs.iter().map(|i| i.ibase).min().unwrap() as i64 - base_delta;

View File

@@ -34,7 +34,7 @@ fn main() {
let text = std::fs::read_to_string(log).expect("log"); let text = std::fs::read_to_string(log).expect("log");
for d in parse_capture(&text) { for d in parse_capture(&text) {
let k = d.ib.map(|i| (i.ibase, i.icount)).unwrap_or((0, 0)); let k = d.ib.map(|i| (i.ibase, i.icount)).unwrap_or((0, 0));
if d.ib.map_or(false, |i| i.head_len > 0) if d.ib.is_some_and(|i| i.head_len > 0)
&& d.pos.len() >= 4 && d.pos.len() >= 4
&& seen.insert((log.clone(), d.vbase, k)) && seen.insert((log.clone(), d.vbase, k))
{ {

View File

@@ -183,7 +183,7 @@ fn main() {
None => clusters.push((*s, 1)), None => clusters.push((*s, 1)),
} }
} }
clusters.sort_by(|x, y| y.1.cmp(&x.1)); clusters.sort_by_key(|x| std::cmp::Reverse(x.1));
let tops: Vec<String> = clusters let tops: Vec<String> = clusters
.iter() .iter()
.filter(|(_, n)| *n >= 3) .filter(|(_, n)| *n >= 3)

View File

@@ -11,6 +11,9 @@
use std::collections::{BTreeMap, HashMap}; use std::collections::{BTreeMap, HashMap};
use sylpheed_formats::mesh::Xbg7Model; use sylpheed_formats::mesh::Xbg7Model;
/// Every place one model name was seen: (container, verts, tris, span).
type Sightings = BTreeMap<String, Vec<(String, usize, usize, [i64; 3])>>;
fn main() { fn main() {
let dir = std::env::args().nth(1).expect("resource3d dir"); let dir = std::env::args().nth(1).expect("resource3d dir");
let list = std::env::args().any(|a| a == "--list"); let list = std::env::args().any(|a| a == "--list");
@@ -23,7 +26,7 @@ fn main() {
files.sort(); files.sort();
// name -> [(container, verts, tris, span)] // name -> [(container, verts, tris, span)]
let mut seen: BTreeMap<String, Vec<(String, usize, usize, [i64; 3])>> = BTreeMap::new(); let mut seen: Sightings = BTreeMap::new();
for f in &files { for f in &files {
let Ok(bytes) = std::fs::read(f) else { let Ok(bytes) = std::fs::read(f) else {
continue; continue;

View File

@@ -119,8 +119,8 @@ fn main() {
} }
println!("\n--- schema 0x{schema:08x} {name} ({n_obj} objects) ---"); println!("\n--- schema 0x{schema:08x} {name} ({n_obj} objects) ---");
println!( println!(
"{:<30} {:>5} {:>5} {}", "{:<30} {:>5} {:>5} values seen (≤12) | owners defaulting",
"KEY", "set", "dflt", "values seen (≤12) | owners defaulting" "KEY", "set", "dflt"
); );
for (k, (n_set, n_def, vals, owners)) in defaulted { for (k, (n_set, n_def, vals, owners)) in defaulted {
let vv: Vec<&str> = vals.iter().map(|s| s.as_str()).collect(); let vv: Vec<&str> = vals.iter().map(|s| s.as_str()).collect();

View File

@@ -5,7 +5,7 @@ fn short(s: &str) -> String {
.trim_start_matches("UnitName_UN_") .trim_start_matches("UnitName_UN_")
.into() .into()
} }
fn g<'a>(o: &'a IdxdObject, k: &str) -> String { fn g(o: &IdxdObject, k: &str) -> String {
o.get_f32(k) o.get_f32(k)
.map(|v| { .map(|v| {
if v == v.trunc() { if v == v.trunc() {

View File

@@ -1,4 +1,4 @@
use sylpheed_formats::{game_data, localization::TextIndex, PakArchive}; use sylpheed_formats::{localization::TextIndex, PakArchive};
fn main() { fn main() {
let disc = std::env::var("SYLPHEED_DISC").unwrap(); let disc = std::env::var("SYLPHEED_DISC").unwrap();
let pak = PakArchive::open(format!("{disc}/dat/GP_MAIN_GAME_E.pak")).unwrap(); let pak = PakArchive::open(format!("{disc}/dat/GP_MAIN_GAME_E.pak")).unwrap();

View File

@@ -66,7 +66,7 @@ fn main() {
} }
} }
let (mut shared, mut inconsistent) = (0usize, 0usize); let (mut shared, mut inconsistent) = (0usize, 0usize);
for (_, list) in &seen { for list in seen.values() {
if list.len() < 2 || !list.iter().all(|e| e.1 == list[0].1 && e.2 == list[0].2) { if list.len() < 2 || !list.iter().all(|e| e.1 == list[0].1 && e.2 == list[0].2) {
continue; continue;
} }

View File

@@ -27,7 +27,7 @@ fn all_descriptors(buf: &[u8]) -> Vec<(usize, u32)> {
let mut o = 0; let mut o = 0;
while o <= end { while o <= end {
let id = be(o); let id = be(o);
if id >= 1 && id < ID_MAX && be(o + 4) == DESC_MARK && be(o + DESC_REPEAT) == id { if (1..ID_MAX).contains(&id) && be(o + 4) == DESC_MARK && be(o + DESC_REPEAT) == id {
out.push((o, id)); out.push((o, id));
} }
o += 4; o += 4;

View File

@@ -33,10 +33,12 @@ fn order_without_rule(build: &ui_layout::UiBuild, bundle: &[u8]) -> Vec<usize> {
fn counts(rgba: &[u8], t: u8) -> (usize, usize) { fn counts(rgba: &[u8], t: u8) -> (usize, usize) {
let rgb = rgba let rgb = rgba
.chunks_exact(4) .as_chunks::<4>()
.0
.iter()
.filter(|p| p[0] > t || p[1] > t || p[2] > t) .filter(|p| p[0] > t || p[1] > t || p[2] > t)
.count(); .count();
let alpha = rgba.chunks_exact(4).filter(|p| p[3] > t).count(); let alpha = rgba.as_chunks::<4>().0.iter().filter(|p| p[3] > t).count();
(rgb, alpha) (rgb, alpha)
} }
@@ -69,7 +71,7 @@ fn main() {
] { ] {
let with = ui_layout::derived_paint_order(&b, &by); let with = ui_layout::derived_paint_order(&b, &by);
let without = order_without_rule(&b, &by); let without = order_without_rule(&b, &by);
let a = ui_layout::compose_with_order(&b, &by, opts.clone(), None, Some(&with)); let a = ui_layout::compose_with_order(&b, &by, opts, None, Some(&with));
let c = ui_layout::compose_with_order(&b, &by, opts, None, Some(&without)); let c = ui_layout::compose_with_order(&b, &by, opts, None, Some(&without));
println!( println!(
"\n== GP_TITLE entry {entry}{label} ({}x{})", "\n== GP_TITLE entry {entry}{label} ({}x{})",
@@ -85,8 +87,10 @@ fn main() {
} }
let changed = a let changed = a
.rgba .rgba
.chunks_exact(4) .as_chunks::<4>()
.zip(c.rgba.chunks_exact(4)) .0
.iter()
.zip(c.rgba.as_chunks::<4>().0.iter())
.filter(|(x, y)| x != y) .filter(|(x, y)| x != y)
.count(); .count();
println!(" exact-RGBA changed pixels between the two orders: {changed}"); println!(" exact-RGBA changed pixels between the two orders: {changed}");

View File

@@ -85,19 +85,23 @@ fn main() {
.map(|el| el.name.as_str()) .map(|el| el.name.as_str())
.collect(); .collect();
let a = ui_layout::compose_with_order(&b, &by, opts.clone(), None, Some(&with)); let a = ui_layout::compose_with_order(&b, &by, opts, None, Some(&with));
let c = ui_layout::compose_with_order(&b, &by, opts.clone(), None, Some(&without)); let c = ui_layout::compose_with_order(&b, &by, opts, None, Some(&without));
let n = a let n = a
.rgba .rgba
.chunks_exact(4) .as_chunks::<4>()
.zip(c.rgba.chunks_exact(4)) .0
.iter()
.zip(c.rgba.as_chunks::<4>().0.iter())
.filter(|(x, y)| x != y) .filter(|(x, y)| x != y)
.count(); .count();
// Control: does this build put any ink down at all, against the bare // Control: does this build put any ink down at all, against the bare
// backdrop? A build that renders to nothing cannot show a reorder. // backdrop? A build that renders to nothing cannot show a reorder.
let ink = a let ink = a
.rgba .rgba
.chunks_exact(4) .as_chunks::<4>()
.0
.iter()
.filter(|p| p[..3] != [0, 0, 0]) .filter(|p| p[..3] != [0, 0, 0])
.count(); .count();
let total = a.rgba.len() / 4; let total = a.rgba.len() / 4;

View File

@@ -26,7 +26,7 @@ fn census(name: &str, img: &t8ad::T8adImage) {
.map(|a| (hist[a], a)) .map(|a| (hist[a], a))
.filter(|&(c, _)| c > 0) .filter(|&(c, _)| c > 0)
.collect(); .collect();
top.sort_unstable_by(|a, b| b.0.cmp(&a.0)); top.sort_unstable_by_key(|a| std::cmp::Reverse(a.0));
let top5: Vec<String> = top let top5: Vec<String> = top
.iter() .iter()
.take(5) .take(5)

View File

@@ -27,7 +27,7 @@ fn score(idx: &[u32], pos: &[[f32; 3]], nrm: &[[f32; 3]]) -> (usize, f32, usize)
let mut degen = 0usize; let mut degen = 0usize;
let mut agree = 0usize; let mut agree = 0usize;
let mut counted = 0usize; let mut counted = 0usize;
for t in idx.chunks_exact(3) { for t in idx.as_chunks::<3>().0 {
let (a, b, c) = (t[0] as usize, t[1] as usize, t[2] as usize); let (a, b, c) = (t[0] as usize, t[1] as usize, t[2] as usize);
if a == b || b == c || a == c { if a == b || b == c || a == c {
degen += 1; degen += 1;

View File

@@ -4,14 +4,14 @@
//! //!
//! This is the diagnostic for the 2026-07-31 negative result (Stage_S02 capture, //! This is the diagnostic for the 2026-07-31 negative result (Stage_S02 capture,
//! zero parts correlated). It separates three hypotheses: //! zero parts correlated). It separates three hypotheses:
//! 1. LOD/variant vcount not covered by the correlator's variant list //! 1. LOD/variant vcount not covered by the correlator's variant list
//! → the big draws DO map to named resources, just not to the `_m`/`_l`/`_d` //! → the big draws DO map to named resources, just not to the `_m`/`_l`/`_d`
//! set the correlator tries; //! set the correlator tries;
//! 2. position validation over-rejects //! 2. position validation over-rejects
//! → the vcounts match the very parts we asked for (so the vcount key was //! → the vcounts match the very parts we asked for (so the vcount key was
//! fine and the rejection happened later); //! fine and the rejection happened later);
//! 3. a different draw path (instanced/batched/merged buffers) //! 3. a different draw path (instanced/batched/merged buffers)
//! → the big draws match NO resource in the container at all. //! → the big draws match NO resource in the container at all.
//! //!
//! Usage: //! Usage:
//! SYLPHEED_ISO=... cargo run --release --example invert_capture -- \ //! SYLPHEED_ISO=... cargo run --release --example invert_capture -- \
@@ -171,7 +171,7 @@ fn main() {
) )
}) })
.collect(); .collect();
sizes.sort_unstable_by(|a, b| b.0.cmp(&a.0)); sizes.sort_unstable_by_key(|a| std::cmp::Reverse(a.0));
println!("\nlargest resources in {stage}.xpr → drawn in the capture?"); println!("\nlargest resources in {stage}.xpr → drawn in the capture?");
for (v, name) in sizes.iter().take(top_n.min(sizes.len())) { for (v, name) in sizes.iter().take(top_n.min(sizes.len())) {
let n = draw_count.get(v).copied().unwrap_or(0); let n = draw_count.get(v).copied().unwrap_or(0);

View File

@@ -63,7 +63,7 @@ fn main() {
} }
} }
println!("GP_TITLE: {builds} parseable builds of {n} entries\n"); println!("GP_TITLE: {builds} parseable builds of {n} entries\n");
println!("{:<10} {}", "kind", "elements by file suffix"); println!("{:<10} elements by file suffix", "kind");
for (k, m) in &table { for (k, m) in &table {
let s: Vec<String> = m.iter().map(|(sfx, c)| format!("{sfx}x{c}")).collect(); let s: Vec<String> = m.iter().map(|(sfx, c)| format!("{sfx}x{c}")).collect();
println!("0x{k:<8X} {}", s.join(" ")); println!("0x{k:<8X} {}", s.join(" "));

View File

@@ -13,7 +13,7 @@ fn main() {
..Default::default() ..Default::default()
}; };
let n = b.elements.len(); let n = b.elements.len();
let base = ui_layout::compose(&b, &by, o.clone(), None); let base = ui_layout::compose(&b, &by, o, None);
std::fs::write(format!("{dir}/base.raw"), &base.rgba).unwrap(); std::fs::write(format!("{dir}/base.raw"), &base.rgba).unwrap();
println!("canvas {}x{} elements {n}", base.width, base.height); println!("canvas {}x{} elements {n}", base.width, base.height);
for i in 0..n { for i in 0..n {
@@ -22,7 +22,7 @@ fn main() {
// only bother with elements whose rest pose can touch the band // only bother with elements whose rest pose can touch the band
let mut v = vec![true; n]; let mut v = vec![true; n];
v[i] = false; v[i] = false;
let c = ui_layout::compose(&b, &by, o.clone(), Some(&v)); let c = ui_layout::compose(&b, &by, o, Some(&v));
std::fs::write(format!("{dir}/wo-{i}.raw"), &c.rgba).unwrap(); std::fs::write(format!("{dir}/wo-{i}.raw"), &c.rgba).unwrap();
println!( println!(
"{i}\t{}\t{}\t({},{})\ta={}", "{i}\t{}\t{}\t({},{})\ta={}",

View File

@@ -37,7 +37,7 @@ fn main() {
let Some(b) = ui_layout::parse_build(&by) else { let Some(b) = ui_layout::parse_build(&by) else {
continue; continue;
}; };
for (_, (off, size)) in &b.records { for (off, size) in b.records.values() {
let rec = &by[*off..(*off + *size).min(by.len())]; let rec = &by[*off..(*off + *size).min(by.len())];
if rec.len() < 0x10 || &rec[0..4] != b"RATC" { if rec.len() < 0x10 || &rec[0..4] != b"RATC" {
continue; continue;

View File

@@ -18,8 +18,8 @@ fn main() {
let by = ar.read(&ar.entries()[5]).expect("entry 5"); let by = ar.read(&ar.entries()[5]).expect("entry 5");
let b = ui_layout::parse_build(&by).expect("build"); let b = ui_layout::parse_build(&by).expect("build");
println!( println!(
"{:<26} {:>6} {:>6} {:>7} {:>7} {}", "{:<26} {:>6} {:>6} {:>7} {:>7} sprite",
"element", "x", "y", "pivot_x", "pivot_y", "sprite" "element", "x", "y", "pivot_x", "pivot_y"
); );
let mut rows: Vec<(i32, i32, String, String)> = b let mut rows: Vec<(i32, i32, String, String)> = b
.elements .elements

View File

@@ -17,7 +17,7 @@ fn be16(b: &[u8], at: usize) -> u32 {
/// folded to `max(na, 1-na)` so both authored windings read as ≈1. /// folded to `max(na, 1-na)` so both authored windings read as ≈1.
fn winding(idx: &[u32], pos: &[[f32; 3]], nrm: &[[f32; 3]]) -> f32 { fn winding(idx: &[u32], pos: &[[f32; 3]], nrm: &[[f32; 3]]) -> f32 {
let (mut agree, mut n) = (0usize, 0usize); let (mut agree, mut n) = (0usize, 0usize);
for t in idx.chunks_exact(3) { for t in idx.as_chunks::<3>().0 {
let (a, b, c) = (t[0] as usize, t[1] as usize, t[2] as usize); let (a, b, c) = (t[0] as usize, t[1] as usize, t[2] as usize);
if a == b || b == c || a == c || a.max(b).max(c) >= pos.len() || a >= nrm.len() { if a == b || b == c || a == c || a.max(b).max(c) >= pos.len() || a >= nrm.len() {
continue; continue;
@@ -51,7 +51,9 @@ fn winding(idx: &[u32], pos: &[[f32; 3]], nrm: &[[f32; 3]]) -> f32 {
} }
fn degenerate(idx: &[u32]) -> usize { fn degenerate(idx: &[u32]) -> usize {
idx.chunks_exact(3) idx.as_chunks::<3>()
.0
.iter()
.filter(|t| t[0] == t[1] || t[1] == t[2] || t[0] == t[2]) .filter(|t| t[0] == t[1] || t[1] == t[2] || t[0] == t[2])
.count() .count()
} }

View File

@@ -23,11 +23,11 @@ fn main() {
if tok == &key { if tok == &key {
let lo = i.saturating_sub(6); let lo = i.saturating_sub(6);
let hi = (i + 7).min(t.len()); let hi = (i + 7).min(t.len());
for j in lo..hi { for (j, tok_j) in t.iter().enumerate().skip(lo).take(hi - lo) {
println!( println!(
" [{j}]{} {:?}", " [{j}]{} {:?}",
if j == i { " <-- key" } else { " " }, if j == i { " <-- key" } else { " " },
t[j] tok_j
); );
} }
println!(); println!();

View File

@@ -29,7 +29,7 @@ fn forced(b: &ui_layout::UiBuild, el: &ui_layout::Element, tmax: u32, hold: bool
if el.sprite.is_some() { if el.sprite.is_some() {
return None; return None;
} }
if (el.pivot_x * 2) < b.design_w as u32 || (el.pivot_y * 2) < b.design_h as u32 { if (el.pivot_x * 2) < b.design_w || (el.pivot_y * 2) < b.design_h {
return None; return None;
} }
if tmax == 0 { if tmax == 0 {

View File

@@ -64,7 +64,7 @@ fn main() {
let mut prev = None; let mut prev = None;
for t in 0..=span { for t in 0..=span {
if let Some(k) = le.pose_at(t) { if let Some(k) = le.pose_at(t) {
if prev.map_or(false, |p| p != k.x) { if prev.is_some_and(|p| p != k.x) {
last_move = t last_move = t
} }
prev = Some(k.x); prev = Some(k.x);

View File

@@ -106,7 +106,7 @@ fn main() {
if let Some(out) = std::env::args().nth(2) { if let Some(out) = std::env::args().nth(2) {
// Dependency-free PPM (P6, RGB — alpha already composited over the backdrop). // Dependency-free PPM (P6, RGB — alpha already composited over the backdrop).
let mut buf = format!("P6\n{} {}\n255\n", screen.width, screen.height).into_bytes(); let mut buf = format!("P6\n{} {}\n255\n", screen.width, screen.height).into_bytes();
for px in screen.rgba.chunks_exact(4) { for px in screen.rgba.as_chunks::<4>().0 {
buf.extend_from_slice(&px[..3]); buf.extend_from_slice(&px[..3]);
} }
std::fs::write(&out, buf).unwrap(); std::fs::write(&out, buf).unwrap();

View File

@@ -78,12 +78,12 @@ fn main() {
println!(" {fb_visible} of those rest at alpha > 0 -- i.e. VISIBLE\n"); println!(" {fb_visible} of those rest at alpha > 0 -- i.e. VISIBLE\n");
println!("PER ARCHIVE — fallback fires / of those, rests VISIBLE:"); println!("PER ARCHIVE — fallback fires / of those, rests VISIBLE:");
let mut rows: Vec<_> = per_pak.into_iter().collect(); let mut rows: Vec<_> = per_pak.into_iter().collect();
rows.sort_by(|a, b| b.1 .1.cmp(&a.1 .1)); rows.sort_by_key(|a| std::cmp::Reverse(a.1 .1));
for (pak, (fires, vis)) in &rows { for (pak, (fires, vis)) in &rows {
println!(" {pak:34} {fires:5} fires {vis:5} visible"); println!(" {pak:34} {fires:5} fires {vis:5} visible");
} }
println!(); println!();
worst.sort_by(|a, b| b.0.cmp(&a.0)); worst.sort_by_key(|a| std::cmp::Reverse(a.0));
for (a, pak, el) in worst.iter().take(6) { for (a, pak, el) in worst.iter().take(6) {
println!(" a={a:3} {pak} {el}"); println!(" a={a:3} {pak} {el}");
} }

View File

@@ -32,8 +32,8 @@ fn main() {
}; };
println!("=== {pak} entry {build} ==="); println!("=== {pak} entry {build} ===");
println!( println!(
"{:<22} {:>10} {:>7} {:>7} {:>12} {}", "{:<22} {:>10} {:>7} {:>7} {:>12} at 1x/2x of pivot*2",
"element", "pivot(w,h)", "sx%", "sy%", "drawn px", "at 1x/2x of pivot*2" "element", "pivot(w,h)", "sx%", "sy%", "drawn px"
); );
for e in &b.elements { for e in &b.elements {
let k = match e.rest() { let k = match e.rest() {

View File

@@ -33,7 +33,7 @@ fn main() {
println!("\nunion of all element keyframe times: {ts:?}"); println!("\nunion of all element keyframe times: {ts:?}");
let gaps: Vec<(u32, u32, u32)> = ts.windows(2).map(|w| (w[1] - w[0], w[0], w[1])).collect(); let gaps: Vec<(u32, u32, u32)> = ts.windows(2).map(|w| (w[1] - w[0], w[0], w[1])).collect();
let mut g = gaps.clone(); let mut g = gaps.clone();
g.sort_by(|a, b| b.0.cmp(&a.0)); g.sort_by_key(|a| std::cmp::Reverse(a.0));
println!("widest gaps: {:?}", &g[..g.len().min(4)]); println!("widest gaps: {:?}", &g[..g.len().min(4)]);
println!("settle_window() reports {:?}", build.settle_window()); println!("settle_window() reports {:?}", build.settle_window());
} }

View File

@@ -38,7 +38,7 @@ fn main() {
hi[k] = hi[k].max(v[k]); hi[k] = hi[k].max(v[k]);
} }
} }
for t in sub.indices.chunks_exact(3) { for t in sub.indices.as_chunks::<3>().0 {
tris.push([w[t[0] as usize], w[t[1] as usize], w[t[2] as usize]]); tris.push([w[t[0] as usize], w[t[1] as usize], w[t[2] as usize]]);
} }
} }

View File

@@ -61,7 +61,7 @@ fn main() {
.or_default() .or_default()
.push((m.name.clone(), thin)); .push((m.name.clone(), thin));
} }
for (id, parts) in &by_ship { for parts in by_ship.values() {
if parts.len() < 3 { if parts.len() < 3 {
continue; // no meaningful median continue; // no meaningful median
} }

View File

@@ -18,7 +18,7 @@ fn main() {
}; };
has_riff += 1; has_riff += 1;
if ri > slb::HEADERLESS_DATA_OFFSET if ri > slb::HEADERLESS_DATA_OFFSET
&& (ri - slb::HEADERLESS_DATA_OFFSET) % slb::XMA1_PACKET == 0 && (ri - slb::HEADERLESS_DATA_OFFSET).is_multiple_of(slb::XMA1_PACKET)
{ {
hybrid += 1; hybrid += 1;
if b[slb::HEADERLESS_DATA_OFFSET..ri].iter().any(|x| *x != 0) { if b[slb::HEADERLESS_DATA_OFFSET..ri].iter().any(|x| *x != 0) {

View File

@@ -21,9 +21,12 @@
use std::path::PathBuf; use std::path::PathBuf;
use sylpheed_formats::{pak::PakArchive, t8ad, ui_layout}; use sylpheed_formats::{pak::PakArchive, t8ad, ui_layout};
/// One captured quad: (name, x, y, w, h, index).
type CapturedQuad = (&'static str, f64, f64, f64, f64, usize);
/// The oracle. Verbatim from the header of `docs/re/data/splash-quad-timeline.txt`, /// The oracle. Verbatim from the header of `docs/re/data/splash-quad-timeline.txt`,
/// which read them off the vertex buffer. Quantised to 0.01 by that file. /// which read them off the vertex buffer. Quantised to 0.01 by that file.
const CAPTURED: &[(&str, f64, f64, f64, f64, usize)] = &[ const CAPTURED: &[CapturedQuad] = &[
// name, x0, x1, y0, y1, draws submitted in // name, x0, x1, y0, y1, draws submitted in
("Q0", -0.520, 0.520, -0.100, 0.080, 111), ("Q0", -0.520, 0.520, -0.100, 0.080, 111),
("Q1", -0.390, 0.390, 0.350, 0.550, 87), ("Q1", -0.390, 0.390, 0.350, 0.550, 87),
@@ -83,14 +86,13 @@ fn main() {
// a step plus the pixel grid: 0.01 NDC is 6.4 px in x, 3.6 px in y. // a step plus the pixel grid: 0.01 NDC is 6.4 px in x, 3.6 px in y.
const TOL: f64 = 0.010; const TOL: f64 = 0.010;
println!( println!(
"{:<26} {:<4} {:>8} {:>9} {:>7} {}", "{:<26} {:<4} {:>8} {:>9} {:>7} verdict",
"sprite (disc)", "quad", "max|d|", "runner-up", "draws", "verdict" "sprite (disc)", "quad", "max|d|", "runner-up", "draws"
); );
let (mut ok, mut bad) = (0, 0); let (mut ok, mut bad) = (0, 0);
let mut used: Vec<&str> = Vec::new(); let mut used: Vec<&str> = Vec::new();
for p in &predicted { for p in &predicted {
let mut ds: Vec<(f64, &(&str, f64, f64, f64, f64, usize))> = let mut ds: Vec<(f64, &CapturedQuad)> = CAPTURED.iter().map(|c| (dist(p, c), c)).collect();
CAPTURED.iter().map(|c| (dist(p, c), c)).collect();
ds.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap()); ds.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap());
let (d0, best) = (ds[0].0, ds[0].1); let (d0, best) = (ds[0].0, ds[0].1);
let d1 = ds[1].0; let d1 = ds[1].0;

View File

@@ -27,7 +27,7 @@ fn main() {
let Some(b) = ui_layout::parse_build(&by) else { let Some(b) = ui_layout::parse_build(&by) else {
continue; continue;
}; };
for (_, (off, size)) in &b.records { for (off, size) in b.records.values() {
let rec = &by[*off..(*off + *size).min(by.len())]; let rec = &by[*off..(*off + *size).min(by.len())];
if rec.len() < 0x10 || &rec[0..4] != b"RATC" { if rec.len() < 0x10 || &rec[0..4] != b"RATC" {
continue; continue;

View File

@@ -24,7 +24,7 @@ use ui_layout::{ComposeOptions, UiBuild};
/// Pixels that differ, and the largest per-channel difference. /// Pixels that differ, and the largest per-channel difference.
fn diff(a: &[u8], b: &[u8]) -> (usize, u8) { fn diff(a: &[u8], b: &[u8]) -> (usize, u8) {
let (mut n, mut worst) = (0usize, 0u8); let (mut n, mut worst) = (0usize, 0u8);
for (pa, pb) in a.chunks_exact(4).zip(b.chunks_exact(4)) { for (pa, pb) in a.as_chunks::<4>().0.iter().zip(b.as_chunks::<4>().0.iter()) {
if pa != pb { if pa != pb {
n += 1; n += 1;
for k in 0..4 { for k in 0..4 {
@@ -51,8 +51,10 @@ fn ink_mask(
let mut vis = vec![true; n_el.max(build.elements.len())]; let mut vis = vec![true; n_el.max(build.elements.len())];
vis[build.elements[ei].index] = false; vis[build.elements[ei].index] = false;
let without = ui_layout::compose_with_order(build, bundle, opts, Some(&vis), Some(order)); let without = ui_layout::compose_with_order(build, bundle, opts, Some(&vis), Some(order));
base.chunks_exact(4) base.as_chunks::<4>()
.zip(without.rgba.chunks_exact(4)) .0
.iter()
.zip(without.rgba.as_chunks::<4>().0.iter())
.map(|(x, y)| x != y) .map(|(x, y)| x != y)
.collect() .collect()
} }
@@ -77,7 +79,7 @@ fn swapped(order: &[usize], a: usize, b: usize) -> Vec<usize> {
fn rect(e: &ui_layout::Element, at: Option<u32>) -> Option<(i32, i32, i32, i32)> { fn rect(e: &ui_layout::Element, at: Option<u32>) -> Option<(i32, i32, i32, i32)> {
let kf = match at { let kf = match at {
Some(t) => e.pose_at(t)?, Some(t) => e.pose_at(t)?,
None => e.rest()?.clone(), None => *e.rest()?,
}; };
if kf.fade >> 24 == 0 || kf.scale_x == 0 || kf.scale_y == 0 { if kf.fade >> 24 == 0 || kf.scale_x == 0 || kf.scale_y == 0 {
return None; return None;
@@ -183,7 +185,7 @@ fn control_pair(build: &UiBuild, bytes: &[u8], at: Option<u32>) -> Option<(usize
let ox = ((ra.0 + ra.2).min(rb.0 + rb.2) - ra.0.max(rb.0)) as i64; let ox = ((ra.0 + ra.2).min(rb.0 + rb.2) - ra.0.max(rb.0)) as i64;
let oy = ((ra.1 + ra.3).min(rb.1 + rb.3) - ra.1.max(rb.1)) as i64; let oy = ((ra.1 + ra.3).min(rb.1 + rb.3) - ra.1.max(rb.1)) as i64;
let area = ox * oy; let area = ox * oy;
if best.map_or(true, |(x, _, _)| area > x) { if best.is_none_or(|(x, _, _)| area > x) {
best = Some((area, a, b)); best = Some((area, a, b));
} }
} }

View File

@@ -25,7 +25,7 @@ fn rect(e: &ui_layout::Element, t: u32) -> Option<(i32, i32, i32, i32)> {
Some((kf.x, kf.y, w, h)) Some((kf.x, kf.y, w, h))
} }
fn live_pairs(b: &UiBuild, bytes: &[u8], keys: &[u32], t: u32) -> usize { fn live_pairs(b: &UiBuild, _bytes: &[u8], keys: &[u32], t: u32) -> usize {
let mut n = 0; let mut n = 0;
for a in 0..keys.len() { for a in 0..keys.len() {
for c in (a + 1)..keys.len() { for c in (a + 1)..keys.len() {

View File

@@ -85,7 +85,7 @@ fn main() {
} }
// spanning? // spanning?
let span_adv_end = 437547264u64; let span_adv_end = 437547264u64;
let spans = start < span_adv_end && end > span_adv_end || (start / 1_000 != end / 1_000); let _spans = start < span_adv_end && end > span_adv_end || (start / 1_000 != end / 1_000);
println!("cue {id} ({mov}): region[{start}..{end}] {} bytes, {} riff(s), Σ={:.1}s | movie={} parts={:?}", println!("cue {id} ({mov}): region[{start}..{end}] {} bytes, {} riff(s), Σ={:.1}s | movie={} parts={:?}",
end-start, riffs.len(), total, movdur(&disc,mov), parts); end-start, riffs.len(), total, movdur(&disc,mov), parts);
} }

View File

@@ -60,7 +60,7 @@ fn main() {
println!( println!(
" {n} chunk(s): {:>3} region(s) {}", " {n} chunk(s): {:>3} region(s) {}",
ms.len(), ms.len(),
ms.iter().cloned().collect::<Vec<_>>().join(" ") ms.to_vec().join(" ")
); );
} }
println!( println!(

View File

@@ -31,8 +31,8 @@ fn main() {
.collect(); .collect();
println!( println!(
"{:10} {:>8} {:>12} {:>10} {}", "{:10} {:>8} {:>12} {:>10} verdict",
"movie", "chunks", "first chunk", "clip pkts", "verdict" "movie", "chunks", "first chunk", "clip pkts"
); );
let (mut clipped, mut clean, mut skipped) = (0, 0, 0); let (mut clipped, mut clean, mut skipped) = (0, 0, 0);
for movie in movies { for movie in movies {

View File

@@ -44,8 +44,8 @@ fn main() {
let entries = PakArchive::parse_toc(&stoc).expect("toc"); let entries = PakArchive::parse_toc(&stoc).expect("toc");
println!( println!(
"{:10} {:>6} {:>12} {:>12} {:>12} {:>10} {:>9} {}", "{:10} {:>6} {:>12} {:>12} {:>12} {:>10} {:>9} note",
"movie", "id", "anchor", "pred(id-1)", "pred(before)", "span", "chosen", "note" "movie", "id", "anchor", "pred(id-1)", "pred(before)", "span", "chosen"
); );
for m in movie_manifest::parse(&manifest) { for m in movie_manifest::parse(&manifest) {
let movie = m.movie; let movie = m.movie;

View File

@@ -37,7 +37,7 @@ fn all_descriptors(buf: &[u8]) -> Vec<(usize, u32)> {
let mut o = 0; let mut o = 0;
while o <= end { while o <= end {
let id = be(o); let id = be(o);
if id >= 1 && id < ID_MAX && be(o + 4) == DESC_MARK && be(o + DESC_REPEAT) == id { if (1..ID_MAX).contains(&id) && be(o + 4) == DESC_MARK && be(o + DESC_REPEAT) == id {
out.push((o, id)); out.push((o, id));
} }
o += 4; o += 4;

View File

@@ -30,7 +30,7 @@ fn all_descriptors(buf: &[u8]) -> Vec<(usize, u32)> {
let mut o = 0; let mut o = 0;
while o <= end { while o <= end {
let id = be(o); let id = be(o);
if id >= 1 && id < ID_MAX && be(o + 4) == DESC_MARK && be(o + DESC_REPEAT) == id { if (1..ID_MAX).contains(&id) && be(o + 4) == DESC_MARK && be(o + DESC_REPEAT) == id {
out.push((o, id)); out.push((o, id));
} }
o += 4; o += 4;

View File

@@ -15,6 +15,9 @@ use std::path::{Path, PathBuf};
use sylpheed_formats::mesh::Xbg7Model; use sylpheed_formats::mesh::Xbg7Model;
/// Every place one model name was seen: (span, verts, tris, container).
type Sightings = BTreeMap<String, Vec<([i64; 3], usize, usize, String)>>;
fn disc_root() -> Option<PathBuf> { fn disc_root() -> Option<PathBuf> {
if let Ok(p) = std::env::var("SYLPHEED_DISC") { if let Ok(p) = std::env::var("SYLPHEED_DISC") {
let p = PathBuf::from(p); let p = PathBuf::from(p);
@@ -69,7 +72,7 @@ fn shared_resources_decode_identically_in_every_container() {
files.sort(); files.sort();
// name -> (verts, tris) -> set of spans seen // name -> (verts, tris) -> set of spans seen
let mut seen: BTreeMap<String, Vec<([i64; 3], usize, usize, String)>> = BTreeMap::new(); let mut seen: Sightings = BTreeMap::new();
for f in &files { for f in &files {
let Ok(bytes) = std::fs::read(f) else { let Ok(bytes) = std::fs::read(f) else {
continue; continue;

View File

@@ -341,7 +341,7 @@ fn hero_ship_grouped_pool_decodes() {
let mut agree = 0usize; let mut agree = 0usize;
let mut counted = 0usize; let mut counted = 0usize;
for tri in m.indices.chunks_exact(3) { for tri in m.indices.as_chunks::<3>().0 {
let (a, b, c) = (tri[0] as usize, tri[1] as usize, tri[2] as usize); let (a, b, c) = (tri[0] as usize, tri[1] as usize, tri[2] as usize);
let (pa, pb, pc) = (m.positions[a], m.positions[b], m.positions[c]); let (pa, pb, pc) = (m.positions[a], m.positions[b], m.positions[c]);
let u = [pb[0] - pa[0], pb[1] - pa[1], pb[2] - pa[2]]; let u = [pb[0] - pa[0], pb[1] - pa[1], pb[2] - pa[2]];
@@ -478,7 +478,7 @@ fn stage_models_quality_audit() {
hi[a] = hi[a].max(p[a]); hi[a] = hi[a].max(p[a]);
} }
} }
for tri in sub.indices.chunks_exact(3) { for tri in sub.indices.as_chunks::<3>().0 {
let (a, b, c) = (tri[0] as usize, tri[1] as usize, tri[2] as usize); let (a, b, c) = (tri[0] as usize, tri[1] as usize, tri[2] as usize);
if a >= sub.positions.len() || b >= sub.positions.len() || c >= sub.positions.len() if a >= sub.positions.len() || b >= sub.positions.len() || c >= sub.positions.len()
{ {
@@ -567,7 +567,9 @@ fn decoded_index_runs_have_almost_no_degenerate_triangles() {
for sm in &m.meshes { for sm in &m.meshes {
let d = sm let d = sm
.indices .indices
.chunks_exact(3) .as_chunks::<3>()
.0
.iter()
.filter(|t| t[0] == t[1] || t[1] == t[2] || t[0] == t[2]) .filter(|t| t[0] == t[1] || t[1] == t[2] || t[0] == t[2])
.count(); .count();
if d > 0 { if d > 0 {

View File

@@ -1,7 +1,7 @@
//! Real-disc test for the movie manifest → voice binding. Skipped without //! Real-disc test for the movie manifest → voice binding. Skipped without
//! `SYLPHEED_DISC`. //! `SYLPHEED_DISC`.
use std::path::PathBuf; use std::path::{Path, PathBuf};
use sylpheed_formats::movie_manifest; use sylpheed_formats::movie_manifest;
use sylpheed_formats::slb::VoiceLang; use sylpheed_formats::slb::VoiceLang;
@@ -13,7 +13,7 @@ fn disc_root() -> Option<PathBuf> {
} }
/// Read the manifest + `eng\sounds.tbl` out of `tables.pak`. /// Read the manifest + `eng\sounds.tbl` out of `tables.pak`.
fn load_manifest_and_sounds(root: &PathBuf) -> (Vec<u8>, Vec<u8>) { fn load_manifest_and_sounds(root: &Path) -> (Vec<u8>, Vec<u8>) {
let pak = PakArchive::open(root.join("dat/tables.pak")).unwrap(); let pak = PakArchive::open(root.join("dat/tables.pak")).unwrap();
let manifest = pak let manifest = pak
.entries() .entries()

View File

@@ -20,7 +20,7 @@ fn stage02_has_a_main_objective_for_each_phase() {
return; return;
}; };
let text = TextIndex::build(&pak); let text = TextIndex::build(&pak);
assert!(text.len() > 0, "text index is empty"); assert!(!text.is_empty(), "text index is empty");
for stage in ["S01", "S02"] { for stage in ["S01", "S02"] {
for phase in 1..=3u32 { for phase in 1..=3u32 {

View File

@@ -3,7 +3,7 @@
use std::fs::File; use std::fs::File;
use std::io::{Read, Seek, SeekFrom}; use std::io::{Read, Seek, SeekFrom};
use std::path::PathBuf; use std::path::{Path, PathBuf};
use sylpheed_formats::hash::name_hash; use sylpheed_formats::hash::name_hash;
use sylpheed_formats::slb::{self, VoiceLang}; use sylpheed_formats::slb::{self, VoiceLang};
@@ -15,7 +15,7 @@ fn disc_root() -> Option<PathBuf> {
} }
/// Read `[off, off+size)` from `dat/sound.p00..` (segments concatenated). /// Read `[off, off+size)` from `dat/sound.p00..` (segments concatenated).
fn read_range(root: &PathBuf, mut off: u64, size: usize) -> Vec<u8> { fn read_range(root: &Path, mut off: u64, size: usize) -> Vec<u8> {
let mut out = Vec::with_capacity(size); let mut out = Vec::with_capacity(size);
let mut need = size; let mut need = size;
for i in 0..100u32 { for i in 0..100u32 {

View File

@@ -125,7 +125,7 @@ fn leading_data_offset_is_derived_not_assumed() {
"{path}: leading stream is not a whole packet count" "{path}: leading stream is not a whole packet count"
); );
assert!( assert!(
got == slb::HEADERLESS_DATA_OFFSET || got > slb::HEADERLESS_DATA_OFFSET, got >= slb::HEADERLESS_DATA_OFFSET,
"{path}: offsets below the old constant are unexplained" "{path}: offsets below the old constant are unexplained"
); );
} }

View File

@@ -95,8 +95,8 @@ async fn xpr_pipeline_over_disc_sample() {
// Sanity: does the decoded data length match the descriptor // Sanity: does the decoded data length match the descriptor
// dimensions (what the GPU upload will require)? // dimensions (what the GPU upload will require)?
let bs = t.format.block_size() as u32; let bs = t.format.block_size() as u32;
let bw = ((t.width + bs - 1) / bs).max(1) as usize; let bw = t.width.div_ceil(bs).max(1) as usize;
let bh = ((t.height + bs - 1) / bs).max(1) as usize; let bh = t.height.div_ceil(bs).max(1) as usize;
let need = bw * bh * t.format.bytes_per_block(); let need = bw * bh * t.format.bytes_per_block();
let size_ok = if need == t.data.len() { let size_ok = if need == t.data.len() {
"ok" "ok"

View File

@@ -202,8 +202,7 @@ fn forced_backdrops_are_full_screen_and_plentiful() {
element.name element.name
); );
assert!( assert!(
element.pivot_x * 2 >= b.design_w as u32 element.pivot_x * 2 >= b.design_w && element.pivot_y * 2 >= b.design_h,
&& element.pivot_y * 2 >= b.design_h as u32,
"{}: a quad that does not cover the screen cannot occlude it", "{}: a quad that does not cover the screen cannot occlude it",
element.name element.name
); );

View File

@@ -170,7 +170,13 @@ fn title_background_is_full_screen() {
Some(&visible), Some(&visible),
); );
assert_eq!(screen.drawn, vec![base.index]); assert_eq!(screen.drawn, vec![base.index]);
let uncovered = screen.rgba.chunks_exact(4).filter(|p| p[3] == 0).count(); let uncovered = screen
.rgba
.as_chunks::<4>()
.0
.iter()
.filter(|p| p[3] == 0)
.count();
assert_eq!( assert_eq!(
uncovered, uncovered,
0, 0,

View File

@@ -198,7 +198,7 @@ fn the_derived_order_puts_primitives_last_and_that_wipes_screens() {
}; };
let flatness = |c: &ui_layout::ComposedScreen| { let flatness = |c: &ui_layout::ComposedScreen| {
let mut hist = std::collections::HashMap::<[u8; 3], usize>::new(); let mut hist = std::collections::HashMap::<[u8; 3], usize>::new();
for p in c.rgba.chunks_exact(4) { for p in c.rgba.as_chunks::<4>().0 {
*hist.entry([p[0], p[1], p[2]]).or_default() += 1; *hist.entry([p[0], p[1], p[2]]).or_default() += 1;
} }
*hist.values().max().unwrap_or(&0) as f64 / (c.width * c.height) as f64 *hist.values().max().unwrap_or(&0) as f64 / (c.width * c.height) as f64