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}