flate2/lib.rs
1//! A DEFLATE-based stream compression/decompression library
2//!
3//! This library provides support for compression and decompression of
4//! DEFLATE-based streams:
5//!
6//! * the DEFLATE format itself
7//! * the zlib format
8//! * gzip
9//!
10//! These three formats are all closely related and largely only differ in their
11//! headers/footers. This crate has three types in each submodule for dealing
12//! with these three formats.
13//!
14//! # Implementation
15//!
16//! In addition to supporting three formats, this crate supports several different
17//! backends, controlled through this crate's features:
18//!
19//! * `default`, or `rust_backend` - this implementation uses the `miniz_oxide`
20//! crate which is a port of `miniz.c` to Rust. This feature does not
21//! require a C compiler, and only uses safe Rust code.
22//!
23//! * `zlib-rs` - this implementation utilizes the `zlib-rs` crate, a Rust rewrite of zlib.
24//! This backend is the fastest, at the cost of some `unsafe` Rust code.
25//!
26//! Several backends implemented in C are also available.
27//! These are useful in case you are already using a specific C implementation
28//! and need the result of compression to be bit-identical.
29//! See the crate's README for details on the available C backends.
30//!
31//! The `zlib-rs` backend typically outperforms all the C implementations.
32//!
33//! # Organization
34//!
35//! This crate consists of three main modules: `bufread`, `read`, and `write`. Each module
36//! implements DEFLATE, zlib, and gzip for [`std::io::BufRead`] input types, [`std::io::Read`] input
37//! types, and [`std::io::Write`] output types respectively.
38//!
39//! Use the [`mod@bufread`] implementations if you can provide a `BufRead` type for the input.
40//! The `&[u8]` slice type implements the `BufRead` trait.
41//!
42//! The [`mod@read`] implementations conveniently wrap a `Read` type in a `BufRead` implementation.
43//! However, the `read` implementations may
44//! [read past the end of the input data](https://github.com/rust-lang/flate2-rs/issues/338),
45//! making the `Read` type useless for subsequent reads of the input. If you need to re-use the
46//! `Read` type, wrap it in a [`std::io::BufReader`], use the `bufread` implementations,
47//! and perform subsequent reads on the `BufReader`.
48//!
49//! The [`mod@write`] implementations are most useful when there is no way to create a `BufRead`
50//! type, notably when reading async iterators (streams).
51//!
52//! ```
53//! use futures::{Stream, StreamExt};
54//! use std::io::{Result, Write as _};
55//!
56//! async fn decompress_gzip_stream<S, I>(stream: S) -> Result<Vec<u8>>
57//! where
58//! S: Stream<Item = I>,
59//! I: AsRef<[u8]>
60//! {
61//! let mut stream = std::pin::pin!(stream);
62//! let mut w = Vec::<u8>::new();
63//! let mut decoder = flate2::write::GzDecoder::new(w);
64//! while let Some(input) = stream.next().await {
65//! decoder.write_all(input.as_ref())?;
66//! }
67//! decoder.finish()
68//! }
69//! ```
70//!
71//!
72//! Note that types which operate over a specific trait often implement the mirroring trait as well.
73//! For example a `bufread::DeflateDecoder<T>` *also* implements the
74//! [`Write`] trait if `T: Write`. That is, the "dual trait" is forwarded directly
75//! to the underlying object if available.
76//!
77//! # About multi-member Gzip files
78//!
79//! While most `gzip` files one encounters will have a single *member* that can be read
80//! with the [`GzDecoder`], there may be some files which have multiple members.
81//!
82//! A [`GzDecoder`] will only read the first member of gzip data, which may unexpectedly
83//! provide partial results when a multi-member gzip file is encountered. `GzDecoder` is appropriate
84//! for data that is designed to be read as single members from a multi-member file. `bufread::GzDecoder`
85//! and `write::GzDecoder` also allow non-gzip data following gzip data to be handled.
86//!
87//! The [`MultiGzDecoder`] on the other hand will decode all members of a `gzip` file
88//! into one consecutive stream of bytes, which hides the underlying *members* entirely.
89//! If a file contains non-gzip data after the gzip data, MultiGzDecoder will
90//! emit an error after decoding the gzip data. This behavior matches the `gzip`,
91//! `gunzip`, and `zcat` command line tools.
92//!
93//! [`Bufread`]: std::io::BufRead
94//! [`BufReader`]: std::io::BufReader
95//! [`Read`]: std::io::Read
96//! [`Write`]: std::io::Write
97//! [`GzDecoder`]: bufread::GzDecoder
98//! [`MultiGzDecoder`]: bufread::MultiGzDecoder
99#![doc(html_root_url = "https://docs.rs/flate2/0.2")]
100#![deny(missing_docs)]
101#![deny(missing_debug_implementations)]
102#![allow(trivial_numeric_casts)]
103#![cfg_attr(test, deny(warnings))]
104#![cfg_attr(docsrs, feature(doc_cfg))]
105
106#[cfg(not(feature = "any_impl",))]
107compile_error!("You need to choose a zlib backend");
108
109pub use crate::crc::{Crc, CrcReader, CrcWriter};
110pub use crate::gz::GzBuilder;
111pub use crate::gz::GzHeader;
112pub use crate::mem::{Compress, CompressError, Decompress, DecompressError, Status};
113pub use crate::mem::{FlushCompress, FlushDecompress};
114
115mod bufreader;
116mod crc;
117mod deflate;
118mod ffi;
119mod gz;
120mod mem;
121mod zio;
122mod zlib;
123
124/// Types which operate over [`Read`] streams, both encoders and decoders for
125/// various formats.
126///
127/// Note that the `read` decoder types may read past the end of the compressed
128/// data while decoding. If the caller requires subsequent reads to start
129/// immediately following the compressed data wrap the `Read` type in a
130/// [`BufReader`] and use the `BufReader` with the equivalent decoder from the
131/// `bufread` module and also for the subsequent reads.
132///
133/// [`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html
134/// [`BufReader`]: https://doc.rust-lang.org/std/io/struct.BufReader.html
135pub mod read {
136 pub use crate::deflate::read::DeflateDecoder;
137 pub use crate::deflate::read::DeflateEncoder;
138 pub use crate::gz::read::GzDecoder;
139 pub use crate::gz::read::GzEncoder;
140 pub use crate::gz::read::MultiGzDecoder;
141 pub use crate::zlib::read::ZlibDecoder;
142 pub use crate::zlib::read::ZlibEncoder;
143}
144
145/// Types which operate over [`Write`] streams, both encoders and decoders for
146/// various formats.
147///
148/// [`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
149pub mod write {
150 pub use crate::deflate::write::DeflateDecoder;
151 pub use crate::deflate::write::DeflateEncoder;
152 pub use crate::gz::write::GzDecoder;
153 pub use crate::gz::write::GzEncoder;
154 pub use crate::gz::write::MultiGzDecoder;
155 pub use crate::zlib::write::ZlibDecoder;
156 pub use crate::zlib::write::ZlibEncoder;
157}
158
159/// Types which operate over [`BufRead`] streams, both encoders and decoders for
160/// various formats.
161///
162/// [`BufRead`]: https://doc.rust-lang.org/std/io/trait.BufRead.html
163pub mod bufread {
164 pub use crate::deflate::bufread::DeflateDecoder;
165 pub use crate::deflate::bufread::DeflateEncoder;
166 pub use crate::gz::bufread::GzDecoder;
167 pub use crate::gz::bufread::GzEncoder;
168 pub use crate::gz::bufread::MultiGzDecoder;
169 pub use crate::zlib::bufread::ZlibDecoder;
170 pub use crate::zlib::bufread::ZlibEncoder;
171}
172
173fn _assert_send_sync() {
174 fn _assert_send_sync<T: Send + Sync>() {}
175
176 _assert_send_sync::<read::DeflateEncoder<&[u8]>>();
177 _assert_send_sync::<read::DeflateDecoder<&[u8]>>();
178 _assert_send_sync::<read::ZlibEncoder<&[u8]>>();
179 _assert_send_sync::<read::ZlibDecoder<&[u8]>>();
180 _assert_send_sync::<read::GzEncoder<&[u8]>>();
181 _assert_send_sync::<read::GzDecoder<&[u8]>>();
182 _assert_send_sync::<read::MultiGzDecoder<&[u8]>>();
183 _assert_send_sync::<write::DeflateEncoder<Vec<u8>>>();
184 _assert_send_sync::<write::DeflateDecoder<Vec<u8>>>();
185 _assert_send_sync::<write::ZlibEncoder<Vec<u8>>>();
186 _assert_send_sync::<write::ZlibDecoder<Vec<u8>>>();
187 _assert_send_sync::<write::GzEncoder<Vec<u8>>>();
188 _assert_send_sync::<write::GzDecoder<Vec<u8>>>();
189}
190
191/// When compressing data, the compression level can be specified by a value in
192/// this struct.
193#[derive(Copy, Clone, PartialEq, Eq, Debug)]
194pub struct Compression(u32);
195
196impl Compression {
197 /// Creates a new description of the compression level with an explicitly
198 /// specified integer.
199 ///
200 /// The integer here is typically on a scale of 0-9 where 0 means "no
201 /// compression" and 9 means "take as long as you'd like".
202 pub const fn new(level: u32) -> Compression {
203 Compression(level)
204 }
205
206 /// No compression is to be performed, this may actually inflate data
207 /// slightly when encoding.
208 pub const fn none() -> Compression {
209 Compression(0)
210 }
211
212 /// Optimize for the best speed of encoding.
213 pub const fn fast() -> Compression {
214 Compression(1)
215 }
216
217 /// Optimize for the size of data being encoded.
218 pub const fn best() -> Compression {
219 Compression(9)
220 }
221
222 /// Returns an integer representing the compression level, typically on a
223 /// scale of 0-9. See [`new`](Self::new) for details about compression levels.
224 pub fn level(&self) -> u32 {
225 self.0
226 }
227}
228
229impl Default for Compression {
230 fn default() -> Compression {
231 Compression(6)
232 }
233}
234
235#[cfg(test)]
236fn random_bytes() -> impl Iterator<Item = u8> {
237 use rand::Rng;
238 use std::iter;
239
240 iter::repeat(()).map(|_| rand::rng().random())
241}