From 9dbfb70f7e1b46a1359cea96799746afb2db84b1 Mon Sep 17 00:00:00 2001 From: Matthew Jackson <1085847+MattJackson@users.noreply.github.com> Date: Fri, 17 Jul 2026 21:45:33 -0700 Subject: [PATCH] narrow leaked-internal pub surface to pub(crate) Verified zero callers across all consumer crates AND libfreemkv integration tests: MUX_APP, Disc::{aacs_disc_hash,encrypted_content_ranges,inject_unit_keys}, locate_ranges, mapfile::{MapEntry,entries}, diag::dump_mkv_track, DiscStream::{errors,lost_bytes} (read via accessors). Removed the unused mux DemuxSink/FviSink crate-root re-exports (constructed internally by output() via the direct module path). Staged demux option variants marked allow(dead_code). --- src/diag.rs | 2 +- src/disc/mapfile.rs | 4 ++-- src/disc/mod.rs | 11 +++++++---- src/lib.rs | 2 +- src/mux/demux_sink.rs | 7 +++++++ src/mux/disc.rs | 4 ++-- src/mux/mod.rs | 5 +++-- 7 files changed, 23 insertions(+), 12 deletions(-) diff --git a/src/diag.rs b/src/diag.rs index 25eaec5..8c4ed1e 100644 --- a/src/diag.rs +++ b/src/diag.rs @@ -336,7 +336,7 @@ fn frame_record(track_idx: usize, pts_ns: i64, keyframe: bool, data: &[u8]) -> V /// `track_number` is the 1-based MKV track number; `track` is the built /// [`crate::mux::mkv::MkvTrack`] whose fields map one-to-one onto the emitted /// elements (see `MkvMuxer::new`). No-op unless the diag target is on. -pub fn dump_mkv_track(track_number: u64, track: &crate::mux::mkv::MkvTrack) { +pub(crate) fn dump_mkv_track(track_number: u64, track: &crate::mux::mkv::MkvTrack) { if !diag_enabled() { return; } diff --git a/src/disc/mapfile.rs b/src/disc/mapfile.rs index c202d14..dd0d69f 100644 --- a/src/disc/mapfile.rs +++ b/src/disc/mapfile.rs @@ -77,7 +77,7 @@ impl SectorStatus { /// One contiguous range of bytes with a status. #[derive(Debug, Clone, PartialEq, Eq)] -pub struct MapEntry { +pub(crate) struct MapEntry { pub pos: u64, pub size: u64, pub status: SectorStatus, @@ -498,7 +498,7 @@ impl Mapfile { /// All map entries, sorted ascending by `pos` and (after load) /// guaranteed disjoint and non-overflowing. - pub fn entries(&self) -> &[MapEntry] { + pub(crate) fn entries(&self) -> &[MapEntry] { &self.entries } diff --git a/src/disc/mod.rs b/src/disc/mod.rs index 30953b2..170ee82 100644 --- a/src/disc/mod.rs +++ b/src/disc/mod.rs @@ -683,7 +683,10 @@ fn range_chapter(lba: u32, title: &DiscTitle) -> (Option, Option) { /// This is the single place range→chapter/time annotation happens; autorip used /// to own it and read the mapfile to do so. Now the library computes it from /// its in-memory mapfile + title, and the client renders the result verbatim. -pub fn locate_ranges(raw: &[(u64, u64)], title: &DiscTitle) -> crate::progress::LocatedProgress { +pub(crate) fn locate_ranges( + raw: &[(u64, u64)], + title: &DiscTitle, +) -> crate::progress::LocatedProgress { use crate::consts::{MILLIS_PER_SEC, SECTOR_BYTES_U64}; use crate::progress::{LocatedProgress, LocatedRange}; const MAX_LOCATED: usize = 50; @@ -2424,7 +2427,7 @@ impl Disc { /// /// Empty when the disc has no parsed titles (CSS / unencrypted / unscanned); /// callers treat an empty map as "no content gate" and fall back accordingly. - pub fn encrypted_content_ranges(&self) -> Vec<(u32, u32)> { + pub(crate) fn encrypted_content_ranges(&self) -> Vec<(u32, u32)> { merged_extents(self.titles.iter().flat_map(|t| &t.extents)) } @@ -2432,7 +2435,7 @@ impl Disc { /// empty when this disc has no captured AACS state. Used to name the disc in /// a [`Error::NoDiscKey`] so the application can tell the user which disc to /// add to the keydb. - pub fn aacs_disc_hash(&self) -> String { + pub(crate) fn aacs_disc_hash(&self) -> String { self.aacs .as_ref() .map(|a| crate::hex::strip_hex_prefix(&a.disc_hash).to_string()) @@ -2699,7 +2702,7 @@ impl Disc { /// file-backed mux. Without this, a keyed disc swept without a keydb would /// recover its UK yet still report E8005 (no usable `decrypt_keys`) at /// remux. No-op for an unencrypted or CSS (DVD) disc. - pub fn inject_unit_keys(&mut self, keys: Vec<(u32, [u8; 16])>) { + pub(crate) fn inject_unit_keys(&mut self, keys: Vec<(u32, [u8; 16])>) { if let Some(aacs) = self.aacs.as_mut() { aacs.unit_keys = keys; aacs.key_source = KeyOrigin::ExternalUk; diff --git a/src/lib.rs b/src/lib.rs index d6ddc79..ecbe520 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -98,7 +98,7 @@ pub const VERSION_LABEL: &str = concat!(env!("FREEMKV_VERSION"), env!("GIT_SUFFI /// The muxing/writing-application string written into MKV output /// (`"freemkv (g)"`). -pub const MUX_APP: &str = concat!("freemkv ", env!("FREEMKV_VERSION"), env!("GIT_SUFFIX")); +pub(crate) const MUX_APP: &str = concat!("freemkv ", env!("FREEMKV_VERSION"), env!("GIT_SUFFIX")); pub mod aacs; pub(crate) mod clpi; diff --git a/src/mux/demux_sink.rs b/src/mux/demux_sink.rs index 7a301f5..d106d70 100644 --- a/src/mux/demux_sink.rs +++ b/src/mux/demux_sink.rs @@ -31,6 +31,10 @@ use std::io::{self, BufWriter, Write}; use std::path::{Path, PathBuf}; /// Filename-naming strategy for the per-track files. +// `allow(dead_code)`: the sink honours all variants, but only the `#[default]` is +// constructed today (`output()` builds `DemuxOptions::default()`). The alternates +// are a staged option surface awaiting the CLI `--naming` flag (not yet wired). +#[allow(dead_code)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] pub enum Naming { /// ` [DELAY ms].` — human-readable. @@ -55,6 +59,9 @@ pub enum DelayMode { } /// Chapter export format. +// `allow(dead_code)`: only the `#[default]` XML variant is constructed today (via +// `DemuxOptions::default()`); OGM/Both await the CLI `--chapters` flag. +#[allow(dead_code)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] pub enum ChaptersFmt { /// mkvmerge chapter XML. diff --git a/src/mux/disc.rs b/src/mux/disc.rs index 5f79b8f..65b0426 100644 --- a/src/mux/disc.rs +++ b/src/mux/disc.rs @@ -139,14 +139,14 @@ pub struct DiscStream { // Adaptive batch sizer — preferred comes from the caller // (detect_max_batch_sectors), shrinks/grows based on read outcomes. adaptive: AdaptiveBatch, - pub errors: u64, + errors: u64, /// Cumulative bytes actually skipped (zero-filled) on read error. /// Distinct from `errors`, which counts skip *events*: one event can /// cover a whole AACS unit (`unit_align` sectors = 6144 bytes), so /// `errors * 2048` understates real loss by the alignment factor. /// Consumers estimating lost video time must scale by this, not by /// the event count. - pub lost_bytes: u64, + lost_bytes: u64, pub skip_errors: bool, /// When set and the token is cancelled, fill_extents returns Err(Halted) /// at the next retry boundary. Unlike skip_errors, this propagates the diff --git a/src/mux/mod.rs b/src/mux/mod.rs index 92af736..55d831c 100644 --- a/src/mux/mod.rs +++ b/src/mux/mod.rs @@ -108,9 +108,10 @@ pub(crate) mod tsmux; #[allow(dead_code)] pub(crate) mod videomap; -pub use demux_sink::{ChaptersFmt, DelayMode, DemuxOptions, DemuxSink, Naming}; +// `demux://` and `fvi://` sinks are constructed internally by `output()` via the +// direct `super::demux_sink::` / `super::fvi_sink::` paths — no re-export needed, +// and no consumer names these types, so they are not public API. pub use disc::DiscStream; -pub use fvi_sink::FviSink; pub use m2ts::M2tsStream; pub use mkvstream::MkvStream; pub use network::NetworkStream;