compress_lib/lib.rs
1//! # compress_lib
2//!
3//! DEFLATE (RFC 1951), zlib (RFC 1950), and gzip (RFC 1952) for Rust
4//! services, with the per-message rules of WebSocket permessage-deflate
5//! (RFC 7692).
6//!
7//! The engine is sans-IO: the caller pushes input and pulls output through
8//! buffers it owns. Memory is fixed when an engine is built and never grows
9//! with input, and every decoder enforces an absolute output cap while it
10//! decodes, so a decompression bomb costs at most the cap. There is no
11//! `unsafe` code and no third-party runtime dependency.
12//!
13//! ## Tier 1
14//!
15//! Add it with Cargo's rename, `compress = { package = "compress-lib", version
16//! = "0.3" }`, and code reads `compress::`. One call decompresses a complete
17//! raw DEFLATE stream, capped at 64 MiB of output by default:
18//!
19//! ```
20//! use compress_lib as compress;
21//!
22//! let data = compress::deflate::decompress(&[0xCB, 0x48, 0xCD, 0xC9, 0xC9, 0x07, 0x00])?;
23//! assert_eq!(data, b"hello");
24//!
25//! let small = compress::Limits::new().with_max_output(1 << 20);
26//! let data = compress::deflate::decompress_with(&[0x03, 0x00], small)?;
27//! assert!(data.is_empty());
28//! # Ok::<(), compress_lib::Error>(())
29//! ```
30//!
31//! ## Streaming
32//!
33//! [`deflate::Inflater`] takes input and output buffers you own and says
34//! where it stopped ([`Status`]); memory is fixed when it is built (about
35//! 11 KiB of tables plus a window of `2^window_bits` bytes), and every limit
36//! is checked before output is written.
37//!
38//! ```
39//! use compress_lib::deflate::{Inflater, Status};
40//!
41//! let mut inflater = Inflater::new().with_window_bits(12)?;
42//! let mut out = [0u8; 4096];
43//! let p = inflater.finish(&[0xCB, 0x48, 0xCD, 0xC9, 0xC9, 0x07, 0x00], &mut out)?;
44//! assert_eq!(p.status, Status::Done);
45//! assert_eq!(&out[..p.produced], b"hello");
46//! # Ok::<(), compress_lib::Error>(())
47//! ```
48//!
49//! Every failure is an [`Error`] with a matchable [`ErrorKind`] and a stable
50//! code for logs and metrics. [`checksum`] has CRC-32 and Adler-32.
51//!
52//! ## Status
53//!
54//! `0.3.0`, the raw DEFLATE inflater. The deflater and the RFC 7692 helpers
55//! arrive in `0.4`, zlib and gzip in `0.5`; the complete planned API, each
56//! item with its version, is `docs/API.md` in the
57//! [repository](https://github.com/jamesgober/compress-lib).
58
59#![doc(html_root_url = "https://docs.rs/compress-lib")]
60#![cfg_attr(docsrs, feature(doc_cfg))]
61#![cfg_attr(not(feature = "std"), no_std)]
62#![forbid(unsafe_code)]
63#![deny(missing_docs)]
64#![cfg_attr(
65 not(test),
66 deny(
67 clippy::unwrap_used,
68 clippy::expect_used,
69 clippy::panic,
70 clippy::todo,
71 clippy::unimplemented,
72 clippy::unreachable,
73 clippy::dbg_macro
74 )
75)]
76
77extern crate alloc;
78
79/// Crate version string, populated by Cargo at build time.
80pub const VERSION: &str = env!("CARGO_PKG_VERSION");
81
82pub mod checksum;
83pub mod deflate;
84
85mod error;
86mod inflate;
87mod level;
88mod limits;
89mod stream;
90
91pub use error::{Error, ErrorKind};
92pub use level::Level;
93pub use limits::Limits;
94pub use stream::{Progress, Status};
95
96#[cfg(test)]
97mod tests {
98 use super::VERSION;
99
100 #[test]
101 fn test_version_matches_manifest() {
102 assert_eq!(VERSION, env!("CARGO_PKG_VERSION"));
103 let core = VERSION.split(['-', '+']).next().unwrap_or_default();
104 assert_eq!(core.split('.').count(), 3);
105 assert!(core.split('.').all(|part| part.parse::<u64>().is_ok()));
106 }
107}