diff --git a/Cargo.toml b/Cargo.toml index d0b116c..b5c0211 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libfreemkv" -version = "0.19.1" +version = "0.20.0" edition = "2024" rust-version = "1.86" license = "AGPL-3.0-only" diff --git a/src/lib.rs b/src/lib.rs index 7e1434d..5e1d4f8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -165,8 +165,8 @@ pub use decrypt::{DecryptKeys, decrypt_sectors}; // structured representation; never compare against display strings. // Note: `disc::Stream` here is the codec enum (audio / video / sub kind) // — not the `pes::Stream` trait re-exported below as `PesStream`. Two -// different concepts, the same short name; both stay because both are -// load-bearing in their respective domains. +// different concepts, the same short name; the trait gets the `Pes` +// prefix at the crate root to keep both addressable. pub use disc::{ AacsState, AudioChannels, AudioStream, Clip, Codec, ColorSpace, ContentFormat, DamageSeverity, Disc, DiscFormat, DiscId, DiscTitle, Extent, FrameRate, HdrFormat, KeySource, LabelPurpose, @@ -179,7 +179,7 @@ pub use disc::{ // All stream types implement `pes::Stream` — read PES frames from a source, // write PES frames to a sink. Pick the right type at construction: // -// - `DiscStream` — physical drive or ISO (any `SectorReader`). Always read. +// - `DiscStream` — physical drive or ISO (any `SectorReader`). Read-only. // - `MkvStream` — Matroska container. Read on `open()`, write on `create()`. // - `M2tsStream` — Blu-ray Transport Stream. Read on `open()`, write on `create()`. // - `NetworkStream` — TCP. Read on `listen()`, write on `connect()`. @@ -189,14 +189,11 @@ pub use disc::{ // Most consumers use the URL resolvers (`input()` / `output()`) which pick // the right type from a scheme:// URL. Direct construction is for callers // that need to wire custom readers (e.g. autorip's drive-session reuse). -// 0.18 trait split: `FrameSource` (read-only) and `FrameSink` (write-only) -// supersede the unified `pes::Stream`. The old `Stream` re-export below -// stays available for the deprecation window — re-exported as -// `PesStream` to disambiguate from `disc::Stream` (the codec-kind enum -// re-exported above), which would otherwise collide at the crate root. -#[allow(deprecated)] +// The trait is re-exported as `PesStream` here to disambiguate from +// `disc::Stream` (the codec-kind enum re-exported above), which would +// otherwise collide at the crate root. +pub use pes::PesFrame; pub use pes::Stream as PesStream; -pub use pes::{FrameSink, FrameSource, PesFrame}; pub use mux::DiscStream; pub use mux::M2tsStream; diff --git a/src/mux/disc.rs b/src/mux/disc.rs index 2d651f8..c9cebd4 100644 --- a/src/mux/disc.rs +++ b/src/mux/disc.rs @@ -403,7 +403,6 @@ impl DiscStream { } } -#[allow(deprecated)] // 0.18 trait split: migrate to FrameSource/FrameSink in follow-up commit. impl crate::pes::Stream for DiscStream { fn read(&mut self) -> io::Result> { if let Some(frame) = self.pending_frames.pop_front() { @@ -584,23 +583,18 @@ impl crate::pes::Stream for DiscStream { #[cfg(test)] mod tests { - //! `DiscStream` is the only meaningful `FrameSource` impl in tree (every - //! other concrete `pes::Stream` impl in `mux/*` is a sink). The 0.18 - //! round-1 blanket `impl pes::FrameSource for T` - //! covers `DiscStream` for free as long as it is `Send`. These tests - //! lock that down: a static `Send` assertion plus a `Box` - //! round trip exercising every `FrameSource` method through the trait - //! object, so future Send-breaking edits to `DiscStream`'s interior - //! types fail at compile time and the trait-bridge dispatch is verified - //! at runtime. - #![allow(deprecated)] // exercising the 0.18 deprecation-window blanket bridge. + //! `DiscStream` is the only read-only `Stream` impl in tree (every + //! other concrete impl in `mux/*` is bidirectional or write-only). + //! These tests lock down a static `Send` assertion plus a + //! `Box` round trip exercising every method through the + //! trait object, so future Send-breaking edits to `DiscStream`'s + //! interior types fail at compile time. use super::*; use crate::disc::{ContentFormat, DiscTitle}; - use crate::pes::FrameSource; + use crate::pes::Stream; - /// Static-assert `DiscStream: Send`. The blanket - /// `impl pes::FrameSource for T` only fires for - /// `Send` types — if a future field on `DiscStream` is non-`Send` (e.g. + /// Static-assert `DiscStream: Send`. The `Stream` trait has `Send` as a + /// supertrait — if a future field on `DiscStream` is non-`Send` (e.g. /// a `Box` instead of `Box`), this fails /// at compile time, before the runtime trait-object test below. fn _assert_disc_stream_is_send() { @@ -644,13 +638,11 @@ mod tests { } } - /// Smallest credible witness that `DiscStream` flows through the - /// `FrameSource` blanket impl: build a `Box`, drive - /// `read()` to EOF, exercise `info()` / `headers_ready()` / - /// `codec_private()` through the trait object. The trait-bridge - /// correctness is what's being verified — not demuxer behaviour. + /// Smallest credible witness that `DiscStream` flows through `dyn Stream`: + /// build a `Box`, drive `read()` to EOF, exercise `info()` / + /// `headers_ready()` / `codec_private()` through the trait object. #[test] - fn frame_source_via_dyn_object() { + fn stream_via_dyn_object() { let reader = ZeroReader { capacity: 8 }; let title = synthetic_title(8); let stream = DiscStream::new( @@ -661,7 +653,7 @@ mod tests { ContentFormat::BdTs, ); - let mut src: Box = Box::new(stream); + let mut src: Box = Box::new(stream); // Empty-title fixture has no streams configured, so headers are // trivially ready and codec_private() yields nothing on track 0. diff --git a/src/mux/m2ts.rs b/src/mux/m2ts.rs index 731e06d..48fa3a8 100644 --- a/src/mux/m2ts.rs +++ b/src/mux/m2ts.rs @@ -173,7 +173,6 @@ impl M2tsStream { } } -#[allow(deprecated)] // 0.18 trait split: migrate to FrameSource/FrameSink in follow-up commit. impl crate::pes::Stream for M2tsStream { fn read(&mut self) -> io::Result> { if let Some(frame) = self.pending_frames.pop_front() { @@ -284,27 +283,3 @@ impl crate::pes::Stream for M2tsStream { true } } - -/// FrameSink sibling to the deprecated Stream impl; both coexist during the -/// 0.18 deprecation window. Caller may pick either at the trait-object -/// boundary — `Box` (deprecated) or `Box` (new). -/// Use `M2tsStream::create(writer, title)` to construct the write half; -/// calling `FrameSink::write` on an `M2tsStream::open(reader)` instance -/// returns `StreamReadOnly`. -#[allow(deprecated)] // delegating to deprecated Stream during the 0.18 deprecation window so callers don't see the deprecation twice. -impl crate::pes::FrameSink for M2tsStream { - fn write(&mut self, frame: &crate::pes::PesFrame) -> io::Result<()> { - ::write(self, frame) - } - - fn finish(self: Box) -> io::Result<()> { - // Why: Stream::finish takes &mut self, FrameSink::finish takes Box. - // Re-borrow inside the box, call Stream::finish, drop the box. - let mut s: Self = *self; - ::finish(&mut s) - } - - fn info(&self) -> &crate::disc::DiscTitle { - ::info(self) - } -} diff --git a/src/mux/mkvstream.rs b/src/mux/mkvstream.rs index bd09c0a..764df76 100644 --- a/src/mux/mkvstream.rs +++ b/src/mux/mkvstream.rs @@ -92,7 +92,6 @@ impl MkvStream { } } -#[allow(deprecated)] // 0.18 trait split: migrate to FrameSource/FrameSink in follow-up commit. impl crate::pes::Stream for MkvStream { fn read(&mut self) -> io::Result> { let rs = match self.mode { @@ -189,35 +188,6 @@ impl crate::pes::Stream for MkvStream { } } -/// FrameSink sibling to the deprecated Stream impl; both coexist during the -/// 0.18 deprecation window. Caller may pick either at the trait-object -/// boundary — `Box` (deprecated) or `Box` (new). -/// Use `MkvStream::create(writer, title)` to construct the write half; -/// calling `FrameSink::write` on a `MkvStream::open(reader)` instance returns -/// `StreamReadOnly`. `finish` is where the Cues index is written, so it must -/// be called for the resulting MKV to be seekable. -#[allow(deprecated)] // delegating to deprecated Stream during the 0.18 deprecation window so callers don't see the deprecation twice. -impl crate::pes::FrameSink for MkvStream { - fn write(&mut self, frame: &crate::pes::PesFrame) -> io::Result<()> { - ::write(self, frame) - } - - fn finish(self: Box) -> io::Result<()> { - // Why: Stream::finish takes &mut self, FrameSink::finish takes Box. - // Re-borrow inside the box, call Stream::finish, drop the box. - // The inner `MkvMuxer` is owned via `Option`, and `Stream::finish` - // already takes it via `Option::take()` — moving `*self` out of the - // box hands it the same field by-value, so the muxer's own - // by-value `finish()` runs correctly. - let mut s: Self = *self; - ::finish(&mut s) - } - - fn info(&self) -> &crate::disc::DiscTitle { - ::info(self) - } -} - // ── MKV header parsing (read side) ──────────────────────────── /// Returns (DiscTitle, codec_privates: Vec<(track_number, codec_private_bytes)>) diff --git a/src/mux/network.rs b/src/mux/network.rs index f4c8059..c69e019 100644 --- a/src/mux/network.rs +++ b/src/mux/network.rs @@ -70,7 +70,6 @@ impl NetworkStream { } } -#[allow(deprecated)] // 0.18 trait split: migrate to FrameSource/FrameSink in follow-up commit. impl crate::pes::Stream for NetworkStream { fn read(&mut self) -> io::Result> { match &mut self.mode { @@ -109,30 +108,6 @@ impl crate::pes::Stream for NetworkStream { } } -/// FrameSink sibling to the deprecated Stream impl; both coexist during the -/// 0.18 deprecation window. Caller may pick either at the trait-object -/// boundary — `Box` (deprecated) or `Box` (new). -/// Use `NetworkStream::connect(addr).meta(title)` to construct the write -/// half; calling `FrameSink::write` on `NetworkStream::listen(addr)` returns -/// `StreamReadOnly`. -#[allow(deprecated)] // delegating to deprecated Stream during the 0.18 deprecation window so callers don't see the deprecation twice. -impl crate::pes::FrameSink for NetworkStream { - fn write(&mut self, frame: &crate::pes::PesFrame) -> io::Result<()> { - ::write(self, frame) - } - - fn finish(self: Box) -> io::Result<()> { - // Why: Stream::finish takes &mut self, FrameSink::finish takes Box. - // Re-borrow inside the box, call Stream::finish, drop the box. - let mut s: Self = *self; - ::finish(&mut s) - } - - fn info(&self) -> &DiscTitle { - ::info(self) - } -} - // NetworkStream is PES-only — no IOStream/Read/Write byte interface. #[cfg(test)] @@ -182,7 +157,6 @@ mod tests { #[test] #[ignore] // Requires TCP; may be flaky in CI environments - #[allow(deprecated)] // 0.18 trait split: migrate to FrameSource/FrameSink in follow-up commit. fn network_pes_roundtrip() { use crate::pes; diff --git a/src/mux/null.rs b/src/mux/null.rs index 091e00d..3ededd0 100644 --- a/src/mux/null.rs +++ b/src/mux/null.rs @@ -16,7 +16,6 @@ impl NullStream { } } -#[allow(deprecated)] // 0.18 trait split: migrate to FrameSink in follow-up commit. impl crate::pes::Stream for NullStream { fn read(&mut self) -> io::Result> { Ok(None) @@ -32,43 +31,16 @@ impl crate::pes::Stream for NullStream { } } -/// FrameSink sibling to the deprecated Stream impl; both coexist during the -/// 0.18 deprecation window. Caller may pick either at the trait-object -/// boundary — `Box` (deprecated) or `Box` (new). -/// The deprecation-window callers eventually migrate; this impl exists so -/// new callers can target `FrameSink` without waiting for the rest of the -/// migration to complete. -#[allow(deprecated)] // delegating to deprecated Stream during the 0.18 deprecation window so callers don't see the deprecation twice. -impl crate::pes::FrameSink for NullStream { - fn write(&mut self, frame: &crate::pes::PesFrame) -> io::Result<()> { - ::write(self, frame) - } - - fn finish(self: Box) -> io::Result<()> { - // Why: Stream::finish takes &mut self, FrameSink::finish takes Box. - // Re-borrow inside the box, call Stream::finish, drop the box. - let mut s: Self = *self; - ::finish(&mut s) - } - - fn info(&self) -> &DiscTitle { - ::info(self) - } -} - #[cfg(test)] mod tests { use super::*; - use crate::pes::FrameSink; + use crate::pes::Stream; - /// Smallest credible witness that the new FrameSink impl on a concrete - /// `mux/*` sink works through the trait object: build a boxed - /// `dyn FrameSink`, write a frame, finish it. The trait-bridge correctness - /// is what's being verified — not NullStream-specific behaviour. + /// Verify NullStream routes through the `Stream` trait object cleanly. #[test] - fn frame_sink_via_dyn_object_writes_and_finishes() { + fn stream_via_dyn_object_writes_and_finishes() { let title = DiscTitle::empty(); - let mut sink: Box = Box::new(NullStream::new(&title)); + let mut sink: Box = Box::new(NullStream::new(&title)); let frame = crate::pes::PesFrame { track: 0, @@ -77,9 +49,7 @@ mod tests { data: vec![0x01, 0x02, 0x03], }; sink.write(&frame).unwrap(); - // info() routes through the trait object. let _ = sink.info(); - // finish() consumes the Box — must compile and run. sink.finish().unwrap(); } } diff --git a/src/mux/resolve.rs b/src/mux/resolve.rs index 92a8a5a..044ffb9 100644 --- a/src/mux/resolve.rs +++ b/src/mux/resolve.rs @@ -167,7 +167,6 @@ pub struct InputOptions { } /// Open a PES input stream (produces PES frames). -#[allow(deprecated)] // 0.18 trait split: migrate to FrameSource in follow-up commit. pub fn input(url: &str, opts: &InputOptions) -> io::Result> { let parsed = parse_url(url); match parsed { @@ -239,7 +238,6 @@ pub fn input(url: &str, opts: &InputOptions) -> io::Result io::Result> { self.ensure_header_read()?; @@ -105,26 +104,3 @@ impl crate::pes::Stream for StdioStream { self.header_read || self.writer.is_some() } } - -/// FrameSink sibling to the deprecated Stream impl; both coexist during the -/// 0.18 deprecation window. Caller may pick either at the trait-object -/// boundary — `Box` (deprecated) or `Box` (new). -/// Use `StdioStream::output(title)` to construct the write half; calling -/// `FrameSink::write` on a `StdioStream::input()` returns `StreamReadOnly`. -#[allow(deprecated)] // delegating to deprecated Stream during the 0.18 deprecation window so callers don't see the deprecation twice. -impl crate::pes::FrameSink for StdioStream { - fn write(&mut self, frame: &crate::pes::PesFrame) -> io::Result<()> { - ::write(self, frame) - } - - fn finish(self: Box) -> io::Result<()> { - // Why: Stream::finish takes &mut self, FrameSink::finish takes Box. - // Re-borrow inside the box, call Stream::finish, drop the box. - let mut s: Self = *self; - ::finish(&mut s) - } - - fn info(&self) -> &DiscTitle { - ::info(self) - } -} diff --git a/src/pes.rs b/src/pes.rs index 7f30a50..e03c000 100644 --- a/src/pes.rs +++ b/src/pes.rs @@ -78,19 +78,20 @@ impl PesFrame { } } -/// Deprecated; use [`FrameSource`] for read-only sources or [`FrameSink`] -/// for write-only sinks. The runtime direction-error semantics -/// (`StreamReadOnly` / `StreamWriteOnly` from a wrong-direction call) are -/// removed in 0.18 — direction is type-checked. -#[deprecated( - since = "0.18.0", - note = "use FrameSource (read-only) or FrameSink (write-only) instead" -)] -pub trait Stream { - /// Read the next frame, or `Ok(None)` at end of stream. +/// A PES frame stream. One trait per format — same type opens for read +/// (`open()` / `listen()` / `input()`) or write (`create()` / `connect()` / +/// `output()`). Calling the wrong-direction method returns a typed +/// `StreamReadOnly` / `StreamWriteOnly` error. +/// +/// `Send` is required so streams can move across the producer/consumer +/// threads in autorip's mux pipeline. +pub trait Stream: Send { + /// Read the next frame, or `Ok(None)` at end of stream. Returns + /// `StreamWriteOnly` on a stream opened for writing. fn read(&mut self) -> std::io::Result>; - /// Write a frame to the sink. + /// Write a frame to the sink. Returns `StreamReadOnly` on a stream + /// opened for reading. fn write(&mut self, frame: &PesFrame) -> std::io::Result<()>; /// Finalize the stream: flush buffered frames, write any container @@ -116,115 +117,10 @@ pub trait Stream { } } -/// Read-only source of PES frames. -/// -/// Replaces the read half of the deprecated [`Stream`] trait. Implementors -/// produce frames via [`read`](FrameSource::read) and never accept writes — -/// passing a `FrameSource` where a sink is expected is a compile error, -/// not a runtime `E9001`. -/// -/// `info()` returns the source's `DiscTitle` metadata (track list, codec -/// info, duration). It must be stable across the lifetime of the source. -/// -/// `codec_private(track)` exposes per-track codec initialization data -/// (H.264 SPS/PPS, HEVC VPS/SPS/PPS, AC-3 fscod, etc.) that downstream -/// muxers may need before any frame is written. `headers_ready()` returns -/// false until enough input frames have been seen to populate every video -/// track's codec-private blob — callers buffer frames they read until -/// `headers_ready()` returns true. -pub trait FrameSource: Send { - /// Read the next frame, or `Ok(None)` at end of stream. - fn read(&mut self) -> std::io::Result>; - - /// Source metadata. Stable across reads — implementors must return a - /// consistent reference for the lifetime of the source. - fn info(&self) -> &crate::disc::DiscTitle; - - /// Codec initialization data for a track (SPS/PPS, AC-3 fscod, etc.). - /// `None` for tracks that don't need codec_private (raw passthrough). - fn codec_private(&self, _track: usize) -> Option> { - None - } - - /// True when `codec_private` is available for every video track — - /// callers buffer input frames until this flips, since some output - /// formats (MKV) can't write frames without codec init data. - fn headers_ready(&self) -> bool { - true - } -} - -/// Write-only sink of PES frames. -/// -/// Replaces the write half of the deprecated [`Stream`] trait. Implementors -/// accept frames via [`write`](FrameSink::write) and finalize via -/// [`finish`](FrameSink::finish) — passing a `FrameSink` where a source is -/// expected is a compile error, not a runtime `E9000`. -/// -/// `finish` takes `Box` (rather than `&mut self` like `Stream::finish`) -/// so that finalization is a one-shot terminal operation: callers cannot use -/// the sink after `finish` returns. This is the standard idiom for terminal -/// methods on `dyn Trait` objects. -pub trait FrameSink: Send { - /// Write a frame to the sink. - fn write(&mut self, frame: &PesFrame) -> std::io::Result<()>; - - /// Finalize the sink: flush buffered frames, write any container index - /// (e.g. MKV `Cues`), close the underlying file/socket. Consumes the - /// sink — callers cannot use it afterwards. - fn finish(self: Box) -> std::io::Result<()>; - - /// Sink metadata. Stable across writes — implementors must return a - /// consistent reference for the lifetime of the sink. - fn info(&self) -> &crate::disc::DiscTitle; -} - -// Bridge: any **`Send`** type implementing the deprecated `Stream` trait -// is also a `FrameSource`. This lets existing concrete `Stream` impls in -// `mux/*` satisfy `FrameSource` bounds without per-type migration during -// the 0.18 deprecation window. -// -// **Send caveat (read me before tightening `Stream` itself).** This -// blanket carries a `T: Send` bound rather than promoting `Send` to a -// supertrait of `Stream`, because not every concrete in-tree `Stream` -// impl is `Send`: `MkvStream` and `M2tsStream` carry `Box` -// and `Box` fields whose trait objects don't include `Send`. -// Adding `Stream: Send` would force a wider audit (every `Box` -// becomes `Box`) than this commit is taking on, and -// the type-level migration target is `FrameSource` / `FrameSink` -// directly anyway. Consequence: coercing a non-Send `Box` -// (the return shape of `crate::mux::input` / `output`) to -// `Box` will fail with a `T: Send` trait-bound error. -// The fix on the consumer side is to construct a Send-compliant -// `FrameSource` / `FrameSink` directly rather than relying on this -// bridge for non-Send streams. -// -// Note: `FrameSink` cannot be blanket-impl'd from `Stream` because -// `Stream::finish` takes `&mut self` while `FrameSink::finish` takes -// `Box`; concrete types will be migrated in a follow-up commit. -#[allow(deprecated)] -impl FrameSource for T { - fn read(&mut self) -> std::io::Result> { - ::read(self) - } - - fn info(&self) -> &crate::disc::DiscTitle { - ::info(self) - } - - fn codec_private(&self, track: usize) -> Option> { - ::codec_private(self, track) - } - - fn headers_ready(&self) -> bool { - ::headers_ready(self) - } -} - /// Wraps any output stream and counts bytes written. /// /// Progress tracking is a CLI concern — streams don't know their size. -/// Wrap the output with CountingStream, then query bytes_written(). +/// Wrap the output with `CountingStream`, then query `bytes_written()`. /// /// ```text /// let mut output = CountingStream::new(libfreemkv::output(dest, &title)?); @@ -233,13 +129,11 @@ impl FrameSource for T { /// let pct = output.bytes_written() as f64 / total as f64; /// } /// ``` -#[allow(deprecated)] pub struct CountingStream { inner: Box, written: u64, } -#[allow(deprecated)] impl CountingStream { pub fn new(inner: Box) -> Self { Self { inner, written: 0 } @@ -251,7 +145,6 @@ impl CountingStream { } } -#[allow(deprecated)] impl Stream for CountingStream { fn read(&mut self) -> std::io::Result> { self.inner.read() @@ -293,88 +186,35 @@ mod tests { } } - /// Direct `FrameSource` impl (not via the deprecated `Stream` blanket). - struct MockSource { - frames: std::vec::IntoIter, + /// Minimal in-memory `Stream` for trait-shape tests. `read` replays + /// pre-seeded frames; `write` collects them. + struct MockStream { + read_queue: std::vec::IntoIter, + written: Vec, title: DiscTitle, } - impl MockSource { - fn new(frames: Vec) -> Self { + impl MockStream { + fn new(read_frames: Vec) -> Self { Self { - frames: frames.into_iter(), + read_queue: read_frames.into_iter(), + written: Vec::new(), title: DiscTitle::empty(), } } } - impl FrameSource for MockSource { + impl Stream for MockStream { fn read(&mut self) -> std::io::Result> { - Ok(self.frames.next()) + Ok(self.read_queue.next()) } - fn info(&self) -> &DiscTitle { - &self.title - } - } - - /// Direct `FrameSink` impl (not via the deprecated `Stream` blanket). - struct MockSink { - collected: Vec, - title: DiscTitle, - } - - impl MockSink { - fn new() -> Self { - Self { - collected: Vec::new(), - title: DiscTitle::empty(), - } - } - } - - impl FrameSink for MockSink { fn write(&mut self, frame: &PesFrame) -> std::io::Result<()> { - self.collected.push(frame.clone()); + self.written.push(frame.clone()); Ok(()) } - fn finish(self: Box) -> std::io::Result<()> { - // Drop self; in real sinks this is where flush/fsync/close happens. - Ok(()) - } - - fn info(&self) -> &DiscTitle { - &self.title - } - } - - /// Variant of `MockSink` whose `finish` returns the collected frames so - /// the test can assert on them after the consuming `Box` call. - struct CollectingSink { - collected: Vec, - title: DiscTitle, - } - - impl CollectingSink { - fn new() -> Self { - Self { - collected: Vec::new(), - title: DiscTitle::empty(), - } - } - } - - impl FrameSink for CollectingSink { - fn write(&mut self, frame: &PesFrame) -> std::io::Result<()> { - self.collected.push(frame.clone()); - Ok(()) - } - - fn finish(self: Box) -> std::io::Result<()> { - // Real CollectingSink consumers would expose `take()` before - // finish; this trait method just confirms the boxed signature - // compiles and runs. + fn finish(&mut self) -> std::io::Result<()> { Ok(()) } @@ -384,72 +224,43 @@ mod tests { } #[test] - fn frame_source_yields_frames_then_eof() { + fn stream_read_yields_frames_then_eof() { let frames = vec![make_frame(0, 0), make_frame(1, 1_000), make_frame(0, 2_000)]; - let mut src = MockSource::new(frames.clone()); + let mut s = MockStream::new(frames.clone()); - let f0 = src.read().unwrap().expect("first frame"); + let f0 = s.read().unwrap().expect("first frame"); assert_eq!(f0.track, frames[0].track); assert_eq!(f0.pts, frames[0].pts); assert!(f0.keyframe); - let f1 = src.read().unwrap().expect("second frame"); - assert_eq!(f1.track, frames[1].track); + let f1 = s.read().unwrap().expect("second frame"); assert_eq!(f1.pts, frames[1].pts); - let f2 = src.read().unwrap().expect("third frame"); - assert_eq!(f2.track, frames[2].track); + let f2 = s.read().unwrap().expect("third frame"); assert_eq!(f2.pts, frames[2].pts); - assert!(src.read().unwrap().is_none()); - assert!(src.read().unwrap().is_none()); // idempotent at EOF + assert!(s.read().unwrap().is_none()); + assert!(s.read().unwrap().is_none()); // idempotent at EOF } #[test] - fn frame_sink_collects_then_finishes() { - let mut sink = MockSink::new(); + fn stream_write_collects_then_finishes() { + let mut s = MockStream::new(Vec::new()); let frames = [make_frame(0, 0), make_frame(1, 100), make_frame(2, 200)]; for f in &frames { - sink.write(f).unwrap(); + s.write(f).unwrap(); } - assert_eq!(sink.collected.len(), 3); - assert_eq!(sink.collected[0].pts, 0); - assert_eq!(sink.collected[1].pts, 100); - assert_eq!(sink.collected[2].pts, 200); - - // Box-and-finish — the `self: Box` shape must compile and run. - Box::new(sink).finish().unwrap(); + assert_eq!(s.written.len(), 3); + s.finish().unwrap(); } #[test] - fn frame_sink_via_dyn_object() { - let frames = [make_frame(0, 0), make_frame(0, 33)]; - let mut sink: Box = Box::new(CollectingSink::new()); - - for f in &frames { - sink.write(f).unwrap(); - } - // info() routes through the trait object. - let _ = sink.info(); - sink.finish().unwrap(); - } - - /// The deprecated blanket impl: any concrete `Stream` should also act as - /// a `FrameSource`. `NullStream` has the simplest constructor of every - /// concrete `Stream` impl in `mux/*`, so it's the smallest credible - /// witness that the bridge compiles and dispatches correctly. - #[test] - #[allow(deprecated)] - fn deprecated_stream_satisfies_frame_source() { - let title = DiscTitle::empty(); - let mut null = crate::mux::NullStream::new(&title); - - let src: &mut dyn FrameSource = &mut null; - // NullStream::read returns Ok(None) — it's a write-only sink. - assert!(src.read().unwrap().is_none()); - // info() forwards through the blanket impl. - let _ = src.info(); - assert!(src.headers_ready()); + fn stream_via_dyn_object() { + let mut s: Box = Box::new(MockStream::new(vec![make_frame(0, 0)])); + let frame = s.read().unwrap().expect("first frame"); + s.write(&frame).unwrap(); + let _ = s.info(); + s.finish().unwrap(); } } diff --git a/tests/integration_progress_and_halt.rs b/tests/integration_progress_and_halt.rs index 685b9d7..54530fe 100644 --- a/tests/integration_progress_and_halt.rs +++ b/tests/integration_progress_and_halt.rs @@ -1,11 +1,6 @@ //! Integration tests for progress reporting, halt behavior, drop safety, //! and the file-backed sector reader round trip. -// 0.18 trait split: this suite still drives the deprecated `pes::Stream` -// trait directly. It will be migrated to `FrameSource`/`FrameSink` in the -// follow-up that ports concrete impls. -#![allow(deprecated)] - use libfreemkv::disc::{CopyOptions, DiscRegion}; use libfreemkv::error::Result; use libfreemkv::pes::Stream as PesStream; diff --git a/tests/streams.rs b/tests/streams.rs index 2dd6607..2cd2139 100644 --- a/tests/streams.rs +++ b/tests/streams.rs @@ -1,10 +1,5 @@ //! Integration tests for the PES stream pipeline. -// 0.18 trait split: this suite still drives the deprecated `pes::Stream` -// trait directly. It will be migrated to `FrameSource`/`FrameSink` in the -// follow-up that ports concrete impls. -#![allow(deprecated)] - use libfreemkv::mux::meta::M2tsMeta; use libfreemkv::pes::Stream as PesStream; use libfreemkv::*;