Sweep the pinned toolchain to Rust 1.97

The Windows UI needs current winsafe, whose real minimum is 1.89 (its manifest
under-declares 1.87 while it uses NonNull::from_ref). Rather than stop at the
minimum, this goes to current stable and fixes what that costs.

The counter-intuitive result: 1.97 is CHEAPER than 1.89. libfreemkv had 54
clippy errors at 1.89 and 6 at 1.97, because clippy tightened the noisy
collapsible_if lint in between. Stopping at the minimum would have been the most
expensive choice available.

Roughly 47 lints across the eight repos, the large majority auto-fixed:
libfreemkv 6, freemkv-engine 14, bdemu 8, freemkv-keysources 7, autorip 6,
freemkv-unlock 3, freemkv-i18n 3. The hand-fixed ones are a descending sort to
sort_by_key(Reverse), four manual checked-division sites, a loop counter replaced
by enumerate, and a loop whose first let-else became a while-let.

Worth recording for whoever bumps next: clippy is MSRV-AWARE. Those 54 lints only
appear once the crate DECLARES 1.89 or later, because let-chains become
available. A bare `cargo +1.89 clippy` against a manifest still pinned at 1.87
reports clean and is meaningless — gate with the real precommit script, which is
also the only thing that covers build scripts.

The pin still sits below the Mac default, so it keeps doing its job: catching
lint drift locally before CI sees it.
This commit is contained in:
Matthew Jackson
2026-07-29 21:00:55 -07:00
parent a32373ff40
commit 5f8dc392c0
48 changed files with 444 additions and 452 deletions
+64 -65
View File
@@ -29,12 +29,11 @@ impl Disc {
for entry in &playlist_dir.entries {
if !entry.is_dir && entry.name.to_lowercase().ends_with(".mpls") {
let path = format!("/BDMV/PLAYLIST/{}", entry.name);
if let Ok(mpls_data) = udf_fs.read_file(reader, &path) {
if let Some(title) =
if let Ok(mpls_data) = udf_fs.read_file(reader, &path)
&& let Some(title) =
Self::parse_playlist(reader, udf_fs, &entry.name, &mpls_data)
{
titles.push(title);
}
{
titles.push(title);
}
}
}
@@ -92,54 +91,54 @@ impl Disc {
let mut pkt_count: u32 = 0;
let clpi_path = format!("/BDMV/CLIPINF/{}.clpi", play_item.clip_id);
if let Ok(clpi_data) = udf_fs.read_file(reader, &clpi_path) {
if let Ok(clip_info) = clpi::parse(&clpi_data) {
pkt_count = clip_info.source_packet_count;
if let Ok(clpi_data) = udf_fs.read_file(reader, &clpi_path)
&& let Ok(clip_info) = clpi::parse(&clpi_data)
{
pkt_count = clip_info.source_packet_count;
// Mark the clip seen ONLY after its .clpi parses — a transient
// read/parse failure on the first PlayItem referencing a clip
// must not permanently suppress its extents/size for a later
// PlayItem referencing the same clip that succeeds.
let first_ref = seen_clips.insert(play_item.clip_id.clone());
// Mark the clip seen ONLY after its .clpi parses — a transient
// read/parse failure on the first PlayItem referencing a clip
// must not permanently suppress its extents/size for a later
// PlayItem referencing the same clip that succeeds.
let first_ref = seen_clips.insert(play_item.clip_id.clone());
// Only fetch/push the physical extents and add to the
// total size the first time this clip_id is seen.
if first_ref {
total_size += pkt_count as u64 * 192;
// Only fetch/push the physical extents and add to the
// total size the first time this clip_id is seen.
if first_ref {
total_size += pkt_count as u64 * 192;
// Get stream file extents from UDF allocation descriptors.
// Dual-layer discs split files across layers — UDF knows the real layout.
//
// The clip's stream file is normally `.m2ts`, but AACS 2.1
// (FMTS) discs name the main feature `.fmts` and 3D discs
// use `.ssif` (see [`CLIP_STREAM_EXTS`]). A normal `.m2ts`
// clip is unchanged — the fallback only runs when `.m2ts`
// is absent, which is exactly when `file_extents` errors.
// 3D discs interleave the left (base) and right (MVC
// dependent) views in STREAM/SSIF/<clip>.ssif — note the
// SSIF/ subdir. Prefer it when present: the SSIF is one
// transport stream carrying BOTH eyes on distinct PIDs,
// so muxing it captures the full 3D. 2D clips fall back to
// the base .m2ts / .fmts as before.
let ssif = format!("/BDMV/STREAM/SSIF/{}.ssif", play_item.clip_id);
let file_exts = match udf_fs.file_extents(reader, &ssif) {
Ok(exts) => {
is_3d = true;
Some(exts)
}
Err(_) => CLIP_STREAM_EXTS.iter().find_map(|ext| {
let path = format!("/BDMV/STREAM/{}.{}", play_item.clip_id, ext);
udf_fs.file_extents(reader, &path).ok()
}),
};
if let Some(file_exts) = file_exts {
for (lba, sectors) in file_exts {
if sectors > 0 && lba > 0 {
extents.push(Extent {
start_lba: lba,
sector_count: sectors,
});
}
// Get stream file extents from UDF allocation descriptors.
// Dual-layer discs split files across layers — UDF knows the real layout.
//
// The clip's stream file is normally `.m2ts`, but AACS 2.1
// (FMTS) discs name the main feature `.fmts` and 3D discs
// use `.ssif` (see [`CLIP_STREAM_EXTS`]). A normal `.m2ts`
// clip is unchanged — the fallback only runs when `.m2ts`
// is absent, which is exactly when `file_extents` errors.
// 3D discs interleave the left (base) and right (MVC
// dependent) views in STREAM/SSIF/<clip>.ssif — note the
// SSIF/ subdir. Prefer it when present: the SSIF is one
// transport stream carrying BOTH eyes on distinct PIDs,
// so muxing it captures the full 3D. 2D clips fall back to
// the base .m2ts / .fmts as before.
let ssif = format!("/BDMV/STREAM/SSIF/{}.ssif", play_item.clip_id);
let file_exts = match udf_fs.file_extents(reader, &ssif) {
Ok(exts) => {
is_3d = true;
Some(exts)
}
Err(_) => CLIP_STREAM_EXTS.iter().find_map(|ext| {
let path = format!("/BDMV/STREAM/{}.{}", play_item.clip_id, ext);
udf_fs.file_extents(reader, &path).ok()
}),
};
if let Some(file_exts) = file_exts {
for (lba, sectors) in file_exts {
if sectors > 0 && lba > 0 {
extents.push(Extent {
start_lba: lba,
sector_count: sectors,
});
}
}
}
@@ -266,23 +265,23 @@ impl Disc {
// optional) but over-claims 3D for those frames. Real 3D main-feature
// playlists are single-clip or uniformly 3D, so this is not exercised;
// per-clip 3D would need per-clip stream sets (a larger change).
if is_3d {
if let Some(base) = streams.iter().find_map(|s| match s {
if is_3d
&& let Some(base) = streams.iter().find_map(|s| match s {
Stream::Video(v) => Some(v.clone()),
_ => None,
}) {
let dep_pid = base.pid.wrapping_add(1);
let have_dep = streams
.iter()
.any(|s| matches!(s, Stream::Video(v) if v.pid == dep_pid));
if !have_dep {
streams.push(Stream::Video(VideoStream {
pid: dep_pid,
secondary: true,
label: crate::disc::MVC_DEPENDENT_LABEL.to_string(),
..base
}));
}
})
{
let dep_pid = base.pid.wrapping_add(1);
let have_dep = streams
.iter()
.any(|s| matches!(s, Stream::Video(v) if v.pid == dep_pid));
if !have_dep {
streams.push(Stream::Video(VideoStream {
pid: dep_pid,
secondary: true,
label: crate::disc::MVC_DEPENDENT_LABEL.to_string(),
..base
}));
}
}
+4 -4
View File
@@ -104,10 +104,10 @@ fn max_substream_channels(data: &[u8]) -> Option<u8> {
};
let start = pos + rel;
let frame = &data[start..];
if let Some(ch) = ac3::acmod_channels(frame) {
if ch > 0 {
best = Some(best.map_or(ch, |b| b.max(ch)));
}
if let Some(ch) = ac3::acmod_channels(frame)
&& ch > 0
{
best = Some(best.map_or(ch, |b| b.max(ch)));
}
// Advance past this frame by its declared size when that is mappable;
// otherwise step 2 bytes past the sync and re-scan for the next one.
+18 -17
View File
@@ -165,13 +165,13 @@ impl Disc {
.iter()
.map(|p| p.size)
.fold(0u64, |a, b| a.saturating_add(b));
if let Some(available) = available_space(dest) {
if available < required {
return Err(Error::DirInsufficientSpace {
required,
available,
});
}
if let Some(available) = available_space(dest)
&& available < required
{
return Err(Error::DirInsufficientSpace {
required,
available,
});
}
// Create directories up-front so a leaf write never races a missing
@@ -388,12 +388,12 @@ fn plan_tree(
let child_rel = host_rel.join(&safe);
let child_disc = format!("{disc_path}/{}", entry.name);
// Collision: two distinct disc paths → same host path.
if let Some(prev) = seen_hosts.insert(child_rel.clone(), child_disc.clone()) {
if prev != child_disc {
return Err(Error::DirNameCollision {
host: child_rel.to_string_lossy().into_owned(),
});
}
if let Some(prev) = seen_hosts.insert(child_rel.clone(), child_disc.clone())
&& prev != child_disc
{
return Err(Error::DirNameCollision {
host: child_rel.to_string_lossy().into_owned(),
});
}
if entry.is_dir {
dirs.push(child_rel.clone());
@@ -756,10 +756,11 @@ fn is_windows_reserved(base: &str) -> bool {
}
let up = base.to_ascii_uppercase();
for prefix in ["COM", "LPT"] {
if let Some(rest) = up.strip_prefix(prefix) {
if rest.len() == 1 && matches!(rest.as_bytes()[0], b'1'..=b'9') {
return true;
}
if let Some(rest) = up.strip_prefix(prefix)
&& rest.len() == 1
&& matches!(rest.as_bytes()[0], b'1'..=b'9')
{
return true;
}
}
false
+6 -6
View File
@@ -305,12 +305,12 @@ fn collect_es(
}
}
PRIVATE_STREAM_1 => {
if let Some(sub) = pkt.sub_stream_id {
if (0xC0..=0xC7).contains(&sub) {
let slot = audio.entry(sub).or_default();
if slot.len() < EVO_ES_SAMPLE_CAP {
slot.extend_from_slice(&pkt.data);
}
if let Some(sub) = pkt.sub_stream_id
&& (0xC0..=0xC7).contains(&sub)
{
let slot = audio.entry(sub).or_default();
if slot.len() < EVO_ES_SAMPLE_CAP {
slot.extend_from_slice(&pkt.data);
}
}
}
+15 -15
View File
@@ -687,15 +687,15 @@ pub fn chapter_at_offset(
/// The 1-based chapter + movie-time offset an LBA falls in, or `(None, None)`
/// if it isn't inside the title.
fn range_chapter(lba: u32, title: &DiscTitle) -> (Option<u32>, Option<f64>) {
if let Some(byte_offset) = byte_offset_in_title(lba, title) {
if let Some((ch, t)) = chapter_at_offset(
if let Some(byte_offset) = byte_offset_in_title(lba, title)
&& let Some((ch, t)) = chapter_at_offset(
&title.chapters,
byte_offset,
title.duration_secs,
title.size_bytes,
) {
return (Some(ch as u32), Some(t));
}
)
{
return (Some(ch as u32), Some(t));
}
(None, None)
}
@@ -1726,7 +1726,7 @@ impl Disc {
{
Some(t) => {
let mut v = t.extents.clone();
v.sort_by(|a, b| b.sector_count.cmp(&a.sector_count));
v.sort_by_key(|e| std::cmp::Reverse(e.sector_count));
v
}
None => Vec::new(),
@@ -3049,15 +3049,15 @@ pub fn detect_max_batch_sectors(device_path: &str) -> u16 {
if let Some(bname) = block_name {
let sysfs_path = format!("/sys/block/{bname}/queue/max_hw_sectors_kb");
if let Ok(content) = std::fs::read_to_string(&sysfs_path) {
if let Ok(kb) = content.trim().parse::<u32>() {
// Convert KB to sectors (1 sector = 2 KB = 2048 bytes)
let sectors = (kb / 2).min(u16::MAX as u32) as u16;
// Align down to 3 (one aligned unit)
let aligned = (sectors / 3) * 3;
if aligned >= MIN_BATCH_SECTORS {
return aligned.min(MAX_BATCH_SECTORS);
}
if let Ok(content) = std::fs::read_to_string(&sysfs_path)
&& let Ok(kb) = content.trim().parse::<u32>()
{
// Convert KB to sectors (1 sector = 2 KB = 2048 bytes)
let sectors = (kb / 2).min(u16::MAX as u32) as u16;
// Align down to 3 (one aligned unit)
let aligned = (sectors / 3) * 3;
if aligned >= MIN_BATCH_SECTORS {
return aligned.min(MAX_BATCH_SECTORS);
}
}
}
+6 -7
View File
@@ -42,7 +42,7 @@ const CHUNK_SECTORS: u16 = 1023;
// The alignment requirement above is enforced, not just described.
const _: () = assert!(
CHUNK_SECTORS as u32 % crate::aacs::content::ALIGNED_UNIT_SECTORS == 0,
(CHUNK_SECTORS as u32).is_multiple_of(crate::aacs::content::ALIGNED_UNIT_SECTORS),
"probe chunks must be a whole number of AACS aligned units"
);
@@ -393,12 +393,11 @@ fn verdicts(evidence: &HashMap<u16, TrackEvidence>, conclusive: bool) -> HashMap
/// from the map was never observed and keeps its vendor-derived flag.
fn apply_verdicts(title: &mut DiscTitle, verdicts: &HashMap<u16, bool>) {
for s in &mut title.streams {
if let Stream::Subtitle(sub) = s {
if sub.codec == Codec::Pgs {
if let Some(&forced) = verdicts.get(&sub.pid) {
sub.forced = forced;
}
}
if let Stream::Subtitle(sub) = s
&& sub.codec == Codec::Pgs
&& let Some(&forced) = verdicts.get(&sub.pid)
{
sub.forced = forced;
}
}
}