···66//! `Reader`/`Writer` variants untouched for pipeline stages. These helpers
77//! consolidate that plumbing so each backend only expresses its codec choice.
8899-use crate::utils::{CmprssInput, CmprssOutput, Result};
99+use crate::progress::{OutputTarget, ProgressArgs, copy_with_progress};
1010+use crate::utils::{CmprssInput, CmprssOutput, Result, WriteWrapper};
1011use anyhow::bail;
1112use std::fs::File;
1212-use std::io::{BufReader, BufWriter, Read, Write};
1313+use std::io::{self, BufReader, BufWriter, Read, Write};
13141415/// Resolve a `CmprssInput` into a single boxed `Read` stream for single-stream
1516/// codecs. Returns the stream together with the input file's size when known
···4849 Ok(())
4950}
50515151-/// Open a `CmprssOutput` as a boxed `Write`.
5252-///
5353-/// Callers must destructure `CmprssOutput::Writer` themselves before calling
5454-/// this — the in-memory `Writer` is already a boxed `Write` and doesn't need
5555-/// an additional buffering layer.
5656-pub fn open_output(output: &CmprssOutput) -> Result<Box<dyn Write + Send + '_>> {
5252+/// Resolve a `CmprssOutput` into an owned boxed writer plus an `OutputTarget`
5353+/// describing how it should be treated by the copy path (progress bar vs. no
5454+/// progress, etc.). This consumes the output, so callers that still need to
5555+/// inspect the `CmprssOutput` variant should capture what they need before
5656+/// calling.
5757+pub fn prepare_output(output: CmprssOutput) -> Result<(Box<dyn Write + Send>, OutputTarget)> {
5758 match output {
5858- CmprssOutput::Path(path) => Ok(Box::new(BufWriter::new(File::create(path)?))),
5959- CmprssOutput::Pipe(stdout) => Ok(Box::new(BufWriter::new(stdout))),
6060- CmprssOutput::Writer(_) => {
6161- unreachable!("open_output called with CmprssOutput::Writer; destructure it first")
6262- }
5959+ CmprssOutput::Writer(WriteWrapper(w)) => Ok((w, OutputTarget::InMemory)),
6060+ CmprssOutput::Pipe(stdout) => Ok((Box::new(BufWriter::new(stdout)), OutputTarget::Stdout)),
6161+ CmprssOutput::Path(path) => Ok((
6262+ Box::new(BufWriter::new(File::create(path)?)),
6363+ OutputTarget::File,
6464+ )),
6365 }
6466}
6767+6868+/// Copy bytes from `reader` through `writer`, branching on `target`:
6969+/// pipeline-internal stages use a bare `io::copy` (no progress), while
7070+/// user-facing outputs go through `copy_with_progress` to show a progress bar
7171+/// when configured.
7272+pub fn copy_stream<R: Read, W: Write>(
7373+ mut reader: R,
7474+ mut writer: W,
7575+ file_size: Option<u64>,
7676+ progress_args: &ProgressArgs,
7777+ target: OutputTarget,
7878+) -> Result {
7979+ if target == OutputTarget::InMemory {
8080+ io::copy(&mut reader, &mut writer)?;
8181+ } else {
8282+ copy_with_progress(
8383+ reader,
8484+ writer,
8585+ progress_args.chunk_size.size_in_bytes,
8686+ file_size,
8787+ progress_args.progress,
8888+ target,
8989+ )?;
9090+ }
9191+ Ok(())
9292+}