Skip to main content

compress_lib/
io.rs

1//! `std::io` adapters over the streaming engines (feature `std`).
2//!
3//! | Type | Reads or writes | Does |
4//! |---|---|---|
5//! | [`Reader`] | reads from a compressed `Read` | decompresses |
6//! | [`Writer`] | writes to a `Write` | compresses |
7//! | [`Encoder`] | reads from a plain `Read` | compresses |
8//! | [`DecodeWriter`] | writes to a `Write` | decompresses |
9//!
10//! Each holds one 32 KiB buffer besides its engine. Decoders take
11//! [`Limits`]; errors come out as `std::io::Error` wrapping the crate's
12//! [`Error`](crate::Error).
13//!
14//! ```
15//! use std::io::{Read, Write};
16//!
17//! use compress_lib::{Format, Level, io};
18//!
19//! let mut w = io::Writer::new(Vec::new(), Format::Gzip, Level::DEFAULT);
20//! w.write_all(b"through std::io")?;
21//! let packed = w.finish()?;
22//!
23//! let mut r = io::Reader::new(&packed[..], Format::Gzip);
24//! let mut text = String::new();
25//! r.read_to_string(&mut text)?;
26//! assert_eq!(text, "through std::io");
27//! # Ok::<(), std::io::Error>(())
28//! ```
29
30use std::io::{self, Read, Write};
31
32use crate::{Decoder, Encoder as FormatEncoder, Format, Level, Limits, Status, deflate::Flush};
33
34const BUF: usize = 32 * 1024;
35
36/// Decompresses while reading from a compressed source.
37///
38/// Reading past the end of the compressed stream returns 0. Data after the
39/// stream is left unread in the source as far as the 32 KiB buffer allows
40/// (use [`Reader::into_inner`] with care), and the stream must be complete:
41/// a source that ends early is `UnexpectedEof`.
42///
43/// # Examples
44///
45/// ```
46/// use std::io::Read;
47///
48/// use compress_lib::{Format, io::Reader, zlib};
49///
50/// let packed = zlib::compress(b"read me");
51/// let mut out = Vec::new();
52/// Reader::new(&packed[..], Format::Zlib).read_to_end(&mut out)?;
53/// assert_eq!(out, b"read me");
54/// # Ok::<(), std::io::Error>(())
55/// ```
56#[derive(Debug)]
57pub struct Reader<R> {
58    inner: R,
59    decoder: Decoder,
60    buf: Box<[u8]>,
61    pos: usize,
62    len: usize,
63    eof: bool,
64}
65
66impl<R: Read> Reader<R> {
67    /// Reads `format` from `inner` with the default limits.
68    ///
69    /// # Examples
70    ///
71    /// ```
72    /// let r = compress_lib::io::Reader::new(&b""[..], compress_lib::Format::Gzip);
73    /// # let _ = r;
74    /// ```
75    pub fn new(inner: R, format: Format) -> Self {
76        Self {
77            inner,
78            decoder: Decoder::new(format),
79            buf: vec![0; BUF].into_boxed_slice(),
80            pos: 0,
81            len: 0,
82            eof: false,
83        }
84    }
85
86    /// Sets the limits checked while decoding.
87    ///
88    /// # Examples
89    ///
90    /// ```
91    /// use compress_lib::{Format, Limits, io::Reader};
92    ///
93    /// let r = Reader::new(&b""[..], Format::Gzip).with_limits(Limits::new().with_max_output(1 << 20));
94    /// # let _ = r;
95    /// ```
96    #[must_use]
97    pub fn with_limits(mut self, limits: Limits) -> Self {
98        self.decoder = self.decoder.with_limits(limits);
99        self
100    }
101
102    /// The source, consuming the reader.
103    ///
104    /// # Examples
105    ///
106    /// ```
107    /// let r = compress_lib::io::Reader::new(&b"xyz"[..], compress_lib::Format::Gzip);
108    /// let _source: &[u8] = r.into_inner();
109    /// ```
110    pub fn into_inner(self) -> R {
111        self.inner
112    }
113}
114
115impl<R: Read> Read for Reader<R> {
116    fn read(&mut self, out: &mut [u8]) -> io::Result<usize> {
117        if out.is_empty() || self.decoder.is_done() {
118            return Ok(0);
119        }
120        loop {
121            if self.pos == self.len && !self.eof {
122                self.len = self.inner.read(&mut self.buf)?;
123                self.pos = 0;
124                self.eof = self.len == 0;
125            }
126            let input = &self.buf[self.pos..self.len];
127            let p = if self.eof {
128                self.decoder.finish(input, out)?
129            } else {
130                self.decoder.decompress(input, out)?
131            };
132            self.pos += p.consumed;
133            if p.produced > 0 || p.status == Status::Done {
134                return Ok(p.produced);
135            }
136        }
137    }
138}
139
140/// Compresses while writing to a destination.
141///
142/// `flush` writes a sync point (everything so far becomes decodable) and
143/// flushes the destination; [`finish`](Writer::finish) ends the stream and
144/// returns the destination. Dropping a writer without `finish` tries to end
145/// the stream and ignores errors, as a drop cannot report them: call
146/// `finish`.
147///
148/// # Examples
149///
150/// ```
151/// use std::io::Write;
152///
153/// use compress_lib::{Format, Level, deflate, io::Writer};
154///
155/// let mut w = Writer::new(Vec::new(), Format::Raw, Level::FAST);
156/// w.write_all(b"written")?;
157/// assert_eq!(deflate::decompress(&w.finish()?).unwrap(), b"written");
158/// # Ok::<(), std::io::Error>(())
159/// ```
160#[derive(Debug)]
161pub struct Writer<W: Write> {
162    inner: Option<W>,
163    encoder: FormatEncoder,
164    buf: Box<[u8]>,
165    finished: bool,
166}
167
168impl<W: Write> Writer<W> {
169    /// Writes `format` at `level` to `inner`.
170    ///
171    /// # Examples
172    ///
173    /// ```
174    /// let w = compress_lib::io::Writer::new(Vec::new(), compress_lib::Format::Gzip, compress_lib::Level::FAST);
175    /// # let _ = w;
176    /// ```
177    pub fn new(inner: W, format: Format, level: Level) -> Self {
178        Self {
179            inner: Some(inner),
180            encoder: FormatEncoder::new(format, level),
181            buf: vec![0; BUF].into_boxed_slice(),
182            finished: false,
183        }
184    }
185
186    fn pump(&mut self, mut input: &[u8], flush: Flush) -> io::Result<usize> {
187        let mut taken = 0;
188        let Some(inner) = self.inner.as_mut() else {
189            return Err(io::Error::other("writer already finished"));
190        };
191        loop {
192            let p = self.encoder.compress(input, &mut self.buf, flush)?;
193            inner.write_all(&self.buf[..p.produced])?;
194            input = &input[p.consumed..];
195            taken += p.consumed;
196            if p.status != Status::NeedsOutput {
197                return Ok(taken);
198            }
199        }
200    }
201
202    /// Ends the stream and returns the destination.
203    ///
204    /// # Errors
205    ///
206    /// Errors of the destination.
207    ///
208    /// # Examples
209    ///
210    /// ```
211    /// use compress_lib::{Format, Level, io::Writer};
212    ///
213    /// let packed = Writer::new(Vec::new(), Format::Zlib, Level::DEFAULT).finish()?;
214    /// assert_eq!(compress_lib::zlib::decompress(&packed).unwrap(), b"");
215    /// # Ok::<(), std::io::Error>(())
216    /// ```
217    pub fn finish(mut self) -> io::Result<W> {
218        self.pump(&[], Flush::Finish)?;
219        self.finished = true;
220        let mut inner = self
221            .inner
222            .take()
223            .ok_or_else(|| io::Error::other("writer already finished"))?;
224        inner.flush()?;
225        Ok(inner)
226    }
227}
228
229impl<W: Write> Write for Writer<W> {
230    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
231        self.pump(data, Flush::None)
232    }
233
234    fn flush(&mut self) -> io::Result<()> {
235        self.pump(&[], Flush::Sync)?;
236        match self.inner.as_mut() {
237            Some(inner) => inner.flush(),
238            None => Ok(()),
239        }
240    }
241}
242
243impl<W: Write> Drop for Writer<W> {
244    fn drop(&mut self) {
245        if !self.finished && self.inner.is_some() {
246            let _ = self.pump(&[], Flush::Finish);
247        }
248    }
249}
250
251/// Compresses while reading: reads plain data from `inner` and returns it
252/// compressed.
253///
254/// # Examples
255///
256/// ```
257/// use std::io::Read;
258///
259/// use compress_lib::{Format, Level, gzip, io::Encoder};
260///
261/// let mut packed = Vec::new();
262/// Encoder::new(&b"plain source"[..], Format::Gzip, Level::DEFAULT).read_to_end(&mut packed)?;
263/// assert_eq!(gzip::decompress(&packed).unwrap(), b"plain source");
264/// # Ok::<(), std::io::Error>(())
265/// ```
266#[derive(Debug)]
267pub struct Encoder<R> {
268    inner: R,
269    encoder: FormatEncoder,
270    buf: Box<[u8]>,
271    pos: usize,
272    len: usize,
273    eof: bool,
274    done: bool,
275}
276
277impl<R: Read> Encoder<R> {
278    /// Compresses `inner` as `format` at `level`.
279    ///
280    /// # Examples
281    ///
282    /// ```
283    /// let e = compress_lib::io::Encoder::new(&b""[..], compress_lib::Format::Zlib, compress_lib::Level::FAST);
284    /// # let _ = e;
285    /// ```
286    pub fn new(inner: R, format: Format, level: Level) -> Self {
287        Self {
288            inner,
289            encoder: FormatEncoder::new(format, level),
290            buf: vec![0; BUF].into_boxed_slice(),
291            pos: 0,
292            len: 0,
293            eof: false,
294            done: false,
295        }
296    }
297}
298
299impl<R: Read> Read for Encoder<R> {
300    fn read(&mut self, out: &mut [u8]) -> io::Result<usize> {
301        if out.is_empty() || self.done {
302            return Ok(0);
303        }
304        loop {
305            if self.pos == self.len && !self.eof {
306                self.len = self.inner.read(&mut self.buf)?;
307                self.pos = 0;
308                self.eof = self.len == 0;
309            }
310            let flush = if self.eof { Flush::Finish } else { Flush::None };
311            let p = self
312                .encoder
313                .compress(&self.buf[self.pos..self.len], out, flush)?;
314            self.pos += p.consumed;
315            if p.status == Status::Done && self.eof {
316                self.done = true;
317            }
318            if p.produced > 0 || self.done {
319                return Ok(p.produced);
320            }
321        }
322    }
323}
324
325/// Decompresses while writing: compressed data written in comes out plain
326/// in `inner`.
327///
328/// Bytes after the end of the stream are refused (`InvalidData`).
329/// [`finish`](DecodeWriter::finish) checks that the stream was complete.
330///
331/// # Examples
332///
333/// ```
334/// use std::io::Write;
335///
336/// use compress_lib::{Format, gzip, io::DecodeWriter};
337///
338/// let mut w = DecodeWriter::new(Vec::new(), Format::Gzip);
339/// w.write_all(&gzip::compress(b"decoded on write"))?;
340/// assert_eq!(w.finish()?, b"decoded on write");
341/// # Ok::<(), std::io::Error>(())
342/// ```
343#[derive(Debug)]
344pub struct DecodeWriter<W: Write> {
345    inner: W,
346    decoder: Decoder,
347    buf: Box<[u8]>,
348}
349
350impl<W: Write> DecodeWriter<W> {
351    /// Decodes `format` into `inner` with the default limits.
352    ///
353    /// # Examples
354    ///
355    /// ```
356    /// let w = compress_lib::io::DecodeWriter::new(Vec::new(), compress_lib::Format::Zlib);
357    /// # let _ = w;
358    /// ```
359    pub fn new(inner: W, format: Format) -> Self {
360        Self {
361            inner,
362            decoder: Decoder::new(format),
363            buf: vec![0; BUF].into_boxed_slice(),
364        }
365    }
366
367    /// Sets the limits checked while decoding.
368    ///
369    /// # Examples
370    ///
371    /// ```
372    /// use compress_lib::{Format, Limits, io::DecodeWriter};
373    ///
374    /// let w = DecodeWriter::new(Vec::new(), Format::Zlib).with_limits(Limits::new().with_max_output(1 << 20));
375    /// # let _ = w;
376    /// ```
377    #[must_use]
378    pub fn with_limits(mut self, limits: Limits) -> Self {
379        self.decoder = self.decoder.with_limits(limits);
380        self
381    }
382
383    fn pump(&mut self, mut data: &[u8], last: bool) -> io::Result<usize> {
384        let mut taken = 0;
385        loop {
386            let p = if last {
387                self.decoder.finish(data, &mut self.buf)?
388            } else {
389                self.decoder.decompress(data, &mut self.buf)?
390            };
391            self.inner.write_all(&self.buf[..p.produced])?;
392            data = &data[p.consumed..];
393            taken += p.consumed;
394            match p.status {
395                Status::NeedsOutput => continue,
396                Status::Done if !data.is_empty() => {
397                    return Err(io::Error::new(
398                        io::ErrorKind::InvalidData,
399                        crate::Error::new(crate::ErrorKind::TrailingData, self.decoder.total_in()),
400                    ));
401                }
402                _ => return Ok(taken),
403            }
404        }
405    }
406
407    /// Checks that the stream ended and returns the destination.
408    ///
409    /// # Errors
410    ///
411    /// `UnexpectedEof` when the stream is incomplete; errors of the
412    /// destination.
413    ///
414    /// # Examples
415    ///
416    /// ```
417    /// use std::io::Write;
418    ///
419    /// use compress_lib::{Format, zlib, io::DecodeWriter};
420    ///
421    /// let packed = zlib::compress(b"whole");
422    /// let mut w = DecodeWriter::new(Vec::new(), Format::Zlib);
423    /// w.write_all(&packed[..packed.len() - 2])?;
424    /// assert_eq!(w.finish().unwrap_err().kind(), std::io::ErrorKind::UnexpectedEof);
425    /// # Ok::<(), std::io::Error>(())
426    /// ```
427    pub fn finish(mut self) -> io::Result<W> {
428        self.pump(&[], true)?;
429        self.inner.flush()?;
430        Ok(self.inner)
431    }
432}
433
434impl<W: Write> Write for DecodeWriter<W> {
435    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
436        self.pump(data, false)
437    }
438
439    fn flush(&mut self) -> io::Result<()> {
440        self.inner.flush()
441    }
442}