compress-lib 0.7.0

DEFLATE, zlib, and gzip for Rust services: streaming and sans-IO with bounded memory, hard limits against decompression bombs, WebSocket permessage-deflate (RFC 7692) support, no unsafe code, and zero third-party dependencies.
Documentation

Scope

Raw DEFLATE inflate and deflate with window bits 8 to 15 and levels 0 to 9; sync, full, and finish flushes; zlib and gzip framing with checksums always verified; preset dictionaries; per-message compression for WebSocket servers and clients (context takeover on or off); CRC-32 and Adler-32; std::io adapters. Brotli follows after 1.0. It does not negotiate HTTP or WebSocket headers (http-net and ws-net do) and it does not read archives.

Quick start

[dependencies]
compress = { package = "compress-lib", version = "0.7" }

One call each way, capped at 64 MiB of output by default:

let packed = compress::gzip::compress(body);          // Vec<u8>, level 6
let body = compress::gzip::decompress(&packed)?;      // all members, checksums verified
let z = compress::zlib::compress(data);               // HTTP's "deflate" coding
let raw = compress::deflate::compress(data);          // raw DEFLATE
let any = compress::decompress(&packed)?;             // gzip or zlib, detected

Limits for untrusted input:

let limits = compress::Limits::new().with_max_output(8 << 20).with_max_ratio(50);
let body = compress::gzip::decompress_with(&wire, limits)?;   // OutputLimit, RatioLimit

WebSocket permessage-deflate (RFC 7692), one direction each:

use compress::message::{Compressor, Decompressor, MessageConfig};

let config = MessageConfig::new().with_window_bits(12);   // no context takeover by default
let mut tx = Compressor::new(config)?;
let mut rx = Decompressor::new(config)?;
tx.compress_message(text, &mut payload)?;               // sync flush, tail removed
rx.decompress_message(&payload, &mut message, max)?;    // budget checked while inflating

Streaming, with buffers you own, for any format:

use compress::{Decoder, Format, deflate::Status};

let mut decoder = Decoder::new(Format::Gzip);
let p = decoder.decompress(chunk, &mut output)?;       // push input, pull output
match p.status {
    Status::NeedsInput => { /* feed chunk[p.consumed..] and more; finish() with the last */ }
    Status::NeedsOutput => { /* drain output[..p.produced], call again */ }
    _ => { /* Status::Done */ }
}

And std::io: compress::io::Reader, Writer, Encoder, DecodeWriter.

The complete planned API, with the version each item arrives in, is in docs/API.md.

Contributing

See dev/DIRECTIVES.md for engineering standards and the definition of done. Before a PR: cargo fmt --all, cargo clippy --all-targets --all-features -- -D warnings, and cargo test --all-features must be clean.