lint: deny clippy::unwrap_used in audiofiles-core (completes ratchet)
Final crate in the deny(unwrap_used) ratchet; every audiofiles crate now
carries #![cfg_attr(not(test), deny(clippy::unwrap_used))]. Five production
sites, all argmin/argmax or peek on provably-non-empty collections, given
justification via .expect():
- analysis/cluster.rs (x4): min_by/max_by over points (non-empty by caller)
and 0..k (k >= 1; zero-k returns early), plus the medoid min_by over the
non-empty idxs (empty clusters skipped).
- vp_tree.rs: heap.peek() inside `heap.len() == k`, where k >= 1 is enforced
at the public search entry (empty/k==0 returns early before recursion).
640 core tests green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
3 files changed,
+10 insertions,
-5 deletions
| 109 |
109 |
|
|
| 110 |
110 |
|
let first = (0..points.len())
|
| 111 |
111 |
|
.min_by(|&a, &b| sq_dist(&points[a], &mean).total_cmp(&sq_dist(&points[b], &mean)))
|
| 112 |
|
- |
.unwrap();
|
|
112 |
+ |
.expect("points is non-empty (guaranteed by caller)");
|
| 113 |
113 |
|
|
| 114 |
114 |
|
let mut centroids = vec![points[first].clone()];
|
| 115 |
115 |
|
let mut min_d: Vec<f64> = points.iter().map(|p| sq_dist(p, &points[first])).collect();
|
| 117 |
117 |
|
while centroids.len() < k {
|
| 118 |
118 |
|
let next = (0..points.len())
|
| 119 |
119 |
|
.max_by(|&a, &b| min_d[a].total_cmp(&min_d[b]))
|
| 120 |
|
- |
.unwrap();
|
|
120 |
+ |
.expect("points is non-empty (guaranteed by caller)");
|
| 121 |
121 |
|
centroids.push(points[next].clone());
|
| 122 |
122 |
|
for (i, p) in points.iter().enumerate() {
|
| 123 |
123 |
|
min_d[i] = min_d[i].min(sq_dist(p, &points[next]));
|
| 150 |
150 |
|
for (i, p) in points.iter().enumerate() {
|
| 151 |
151 |
|
let best = (0..k)
|
| 152 |
152 |
|
.min_by(|&a, &b| sq_dist(p, ¢roids[a]).total_cmp(&sq_dist(p, ¢roids[b])))
|
| 153 |
|
- |
.unwrap();
|
|
153 |
+ |
.expect("k >= 1 (empty/zero-k inputs return early)");
|
| 154 |
154 |
|
if best != assign[i] {
|
| 155 |
155 |
|
assign[i] = best;
|
| 156 |
156 |
|
changed = true;
|
| 194 |
194 |
|
.min_by(|&&a, &&b| {
|
| 195 |
195 |
|
sq_dist(&points[a], ¢roids[c]).total_cmp(&sq_dist(&points[b], ¢roids[c]))
|
| 196 |
196 |
|
})
|
| 197 |
|
- |
.unwrap();
|
|
197 |
+ |
.expect("idxs is non-empty (empty clusters are skipped above)");
|
| 198 |
198 |
|
clusters.push(Cluster {
|
| 199 |
199 |
|
id: c,
|
| 200 |
200 |
|
medoid_hash: hashes[medoid].clone(),
|
| 34 |
34 |
|
//! - [`error`] — Unified error type ([`error::CoreError`]) and shared utilities
|
| 35 |
35 |
|
//! - [`util`] — Path/file helpers and audio extension whitelist
|
| 36 |
36 |
|
|
|
37 |
+ |
// Completes the deny(unwrap_used) ratchet across the audiofiles workspace.
|
|
38 |
+ |
// Forbid bare unwrap in production code; tests opt out. `expect` with a
|
|
39 |
+ |
// justification stays allowed for documented invariants.
|
|
40 |
+ |
#![cfg_attr(not(test), deny(clippy::unwrap_used))]
|
|
41 |
+ |
|
| 37 |
42 |
|
pub mod analysis;
|
| 38 |
43 |
|
pub mod collections;
|
| 39 |
44 |
|
pub mod db;
|
| 292 |
292 |
|
heap.pop();
|
| 293 |
293 |
|
}
|
| 294 |
294 |
|
if heap.len() == k {
|
| 295 |
|
- |
*tau = heap.peek().unwrap().distance;
|
|
295 |
+ |
*tau = heap.peek().expect("heap holds k >= 1 entries here").distance;
|
| 296 |
296 |
|
}
|
| 297 |
297 |
|
}
|
| 298 |
298 |
|
|