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:
+64
-65
@@ -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
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user