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