Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
compcol
A collection of compression algorithms in pure Rust.
compcol puts every supported algorithm — RLE, deflate, Deflate64,
zlib, gzip, LZMA, xz, Zstandard, Brotli, LZ4, Snappy, LZW, LZO, LZX,
Amiga LZX, Quantum, LZFSE, ADC, bzip2, Microsoft Xpress / Xpress
Huffman, LZNT1, plus decoders for RAR 1/2/3/5 and PPMd — behind one
uniform streaming trait, with each algorithm gated by its own Cargo
feature so downstream crates only pay for what they pull in. A runtime
by-name factory makes algorithms selectable from configuration or a CLI
flag, and a compcol binary turns the library into a Unix-style filter.
Design principles
- Pure Rust. No
bindgen, no FFI, no C dependencies. The crate has zero runtime dependencies — nothing in[dependencies]. - 100% safe.
unsafe_code = "forbid"is set crate-wide; the library never opts out. no_std. The library is#![no_std].allocis used by everything except the bare-bonesrlealgorithm; algorithms that need large windows or work buffers pull inallocautomatically.- Streaming. The caller owns both buffers; the codec preserves its state across calls. Works in a 1-byte-on-both-sides streaming loop.
- Per-algorithm features.
default = ["alloc", "rle", "deflate", "zlib", "gzip", "factory"]. Everything else is opt-in. allmeta-feature.features = ["all"]is a single name that enables every algorithm — useful for downstream crates and the CLI install command instead of a 20-item feature list.
Supported algorithms
| Algorithm | Feature | Extension | Encoder | Decoder | Cross-validation |
|---|---|---|---|---|---|
| RLE | rle |
.rle |
full | full | — |
| Deflate (RFC 1951) | deflate |
.deflate |
full (lazy LZ77 + dynamic / fixed / stored Huffman; cross-block matching) | full | python3 -c "import zlib" |
| Deflate64 (PKWARE method 9) | deflate64 |
.deflate64 |
full (LZ77 + 64 KiB window + extended length/distance codes) | full | 7z a -tzip -mm=deflate64 |
| Zlib (RFC 1950) | zlib |
.zz |
full | full | python3 -c "import zlib" |
| Gzip (RFC 1952) | gzip |
.gz |
full | full | gzip(1) |
| LZ4 block format | lz4 |
.lz4 |
LZ77 hash matcher | full | — |
| Snappy | snappy |
.sz |
LZ77 hash matcher (raw block format) | full | — |
LZW (compress(1) .Z) |
lzw |
.lzw |
full | full | compress(1) / uncompress(1) |
LZMA (legacy .lzma) |
lzma |
.lzma |
full | full | python3 -m lzma (FORMAT_ALONE) |
| xz | xz |
.xz |
compressed-LZMA2 chunks + uncompressed fallback | full envelope + all reset variants | xz(1) both directions |
| Zstandard (RFC 8478) | zstd |
.zst |
LZ77 + Huffman literals + FSE_Compressed_Mode sequences + repeat offsets + RLE blocks | full Compressed_Block | zstd(1) both directions |
| Brotli (RFC 7932) | brotli |
.br |
LZ77 + length-limited Huffman + 704-symbol IC alphabet + static-dictionary refs | full (with 122 KiB static dictionary) | brotli(1) both directions |
| LZO (LZO1X-1) | lzo |
.lzo |
LZ77 hash matcher | full | python3 -c "import lzo" |
| LZX (Microsoft CAB / WIM) | lzx |
.lzx |
uncompressed blocks only | full (verbatim + aligned-offset + uncompressed; E8 filter) | — |
| Amiga LZX (original 1995 Forbes) | amiga_lzx |
— (.lzx claimed by MS LZX) |
uncompressed blocks only | full (verbatim + aligned + uncompressed; fixed 64 KiB window, no chunk reset, no E8 filter) | — |
| Quantum (Stac, old CAB) | quantum |
.q |
Unsupported (no public encoder exists) |
full (libmspack-equivalent) | libmspack regression fixtures |
| LZFSE (Apple) | lzfse |
.lzfse |
Unsupported (decoder-only) |
bvx- raw + bvxn (LZVN); bvx2 returns Unsupported |
hand-built fixtures (no Apple toolchain bundled) |
| ADC (Apple DMG) | adc |
.adc |
LZSS-style greedy match-finder | full | hand-built fixtures |
| bzip2 | bzip2 |
.bz2 |
full (RLE-1 + SA-IS BWT + MTF + RLE-2 + dynamic Huffman) | full | bzip2(1) both directions |
| PPMd (Shkarin's PPMII variant H) | ppmd |
.ppmd |
Unsupported (decoder-only; PPM model is intricate) |
full (used in 7z / RAR3+ / ZIP method 98) | python3 ppmd-cffi |
| Microsoft Xpress (plain LZ77) | xpress |
.xpress |
full | full (per [MS-XCA] §2.2) | hand-built fixtures |
| Microsoft Xpress Huffman | xpress_huffman |
.xph |
full (LZ77 + canonical Huffman) | full (per [MS-XCA] §2.1; used in WIM / CompactOS NTFS) | hand-built fixtures |
| LZNT1 (NTFS native compression) | lznt1 |
.lznt1 |
full | full (per [MS-XCA] §2.5; 4 KiB-chunked LZ77, no entropy coding) | hand-built fixtures |
| RAR 1.x | rar1 |
.rar |
Unsupported (license) |
building blocks only (Huffman tables not license-clean) | — |
| RAR 2.x | rar2 |
.rar |
Unsupported (license) |
full LZ77+Huffman + audio predictor | real rar-2.60 fixtures |
| RAR 3.x | rar3 |
.rar |
Unsupported (license) |
full LZ77+Huffman + E8 filter; PPMd & VM filters refused | libarchive RAR3 fixtures |
| RAR 5.x | rar5 |
.rar |
Unsupported (license) |
full LZ77+Huffman + x86 filter; Delta/ARM refused | RARLAB-CLI fixtures |
The RAR encoders are permanently Unsupported per RARLAB's unRAR
license terms (every clean-room RAR reader — libarchive, The
Unarchiver, 7-Zip — ships decoder-only for the same reason).
Every other algorithm decodes real-world output from its reference toolchain and produces output that the same reference toolchain accepts. Some encoders (zstd, brotli) lag the reference's compression ratio because they skip features like FSE-compressed Huffman weight tables (zstd) or encoder-side static-dictionary lookups for non-English text (brotli); the wire format is always conformant.
Library usage
# Cargo.toml
[]
= { = "0.4", = ["gzip", "factory"] }
The trait
use ;
One-shot helpers (compcol::vec)
For callers that already have the whole payload in memory:
use Gzip;
use ;
let plain = b"hello world hello world hello world";
let compressed = ?;
let decoded = ?;
assert_eq!;
// With explicit config:
let small = ?;
# Ok::
compress_to_vec_with / decompress_to_vec_with accept the
algorithm's EncoderConfig / DecoderConfig for tuning (level,
quality, etc.). Available under the alloc feature — no std
required.
Streaming through std::io (compcol::io)
For files, sockets, or any Read/Write source. All four
directions are covered; pick by which side you control and which
direction the bytes flow.
use ;
use ;
use ;
// Write plaintext, get a compressed file.
let file = create?;
let mut w = new;
w.write_all?;
let _file = w.finish?; // returns the inner File
// Read a compressed file as if it were plain text.
let file = open?;
let mut r = new;
let mut decoded = Stringnew;
r.read_to_string?;
# Ok::
EncoderReader (compressed source out of a plain reader) and
DecoderWriter (plain output out of a compressed writer) round out
the set. Writers call finish on Drop best-effort — call
finish() explicitly to catch errors. Requires the std feature.
Driving the trait directly
use ;
use ;
let input = b"hello world hello world hello world";
// Encode.
let mut enc = new;
let mut buf = ;
let mut encoded = Vecnew;
let mut consumed = 0;
while consumed < input.len
loop
// Decode.
let mut dec = new;
let mut decoded = Vecnew;
let mut c2 = 0;
while c2 < encoded.len
loop
assert_eq!;
Runtime selection via the factory
use ;
let mut enc = encoder_by_name
.expect;
let mut out = ;
let p = enc.encode.unwrap;
// ...
println!;
factory::extension(name) returns the conventional file extension for
each algorithm (e.g. "gz" for gzip, "zst" for zstd).
Skipping decompressed bytes
Useful for tar-style archive browsing — read a header, skip past the file body, read the next header:
use Decoder;
use Decoder as _;
let mut dec = new;
// Skip past the first 100 decompressed bytes…
let p = dec.skip.unwrap;
// …then decode the next 50:
let mut out = ;
let p = dec.decode.unwrap;
The default skip implementation just reads-and-discards through a
small scratch buffer, so it works for every algorithm. Individual
decoders are free to override with a smarter implementation when the
format allows it (e.g. fast-forwarding through stored deflate blocks
without LZ77 expansion).
CLI usage
The compcol binary ships with the crate. Install with:
…or pick a subset:
Usage: compcol -t ALGO [OPTIONS] [INPUT]
Required:
-t, --type ALGO Algorithm (use --list to see what's compiled in)
Mode:
-d, --decompress Decompress instead of compress
Output (mutually exclusive):
-c, --stdout Write to stdout, keep input file
-o, --output PATH Write to PATH
(default, INPUT given) Write to <INPUT>.<ext> on compress, or strip
<ext> on decompress; remove INPUT on success
(default, no INPUT) Read stdin, write stdout
Misc:
-k, --keep Keep input file even in in-place mode
-f, --force Overwrite an existing output file
-L, --list List available algorithms and exit
-V, --version Print version and exit
-h, --help Print this help and exit
Examples
# Pipe-style use (gzip via stdin → stdout)
|
# In-place compression (mirrors gzip(1) semantics: removes the original)
# Keep the original
# Decompress
# Force overwrite of an existing output file
# Round-trip into a pager
|
# Mix algorithms
# List what's compiled in
Exit codes: 0 success, 1 runtime / I/O error, 2 usage / argument
error.
Cargo feature topology
[]
= ["alloc", "rle", "deflate", "zlib", "gzip", "factory"]
# Meta-feature: pulls in every algorithm. Equivalent to `--all-features`.
= ["alloc", "factory",
"rle", "deflate", "zlib", "gzip",
"lzma", "xz",
"zstd", "brotli", "lz4", "snappy", "lzw",
"lzo", "lzx", "quantum", "lzfse", "adc",
"rar1", "rar2", "rar3", "rar5"]
= []
= ["alloc"] # std::io::{Read,Write} adapters in compcol::io
= ["alloc"] # by-name lookup, returns Box<dyn …>
= [] # no_std clean (alloc not required)
= ["alloc"]
= ["deflate"]
= ["deflate"]
= ["alloc"]
= ["lzma"]
= ["alloc"]
= ["alloc"]
= ["alloc"]
= ["alloc"]
= ["alloc"]
= ["alloc"]
= ["alloc"]
= ["alloc"]
= ["alloc"] # decoder-only, bvx2 returns Unsupported
= ["alloc"]
= ["alloc"]
= ["alloc"]
= ["alloc"]
= ["alloc"]
A bare --no-default-features build produces a library with just the
trait surface — useful for the most constrained embedded targets.
Adding rle gives an algorithm that doesn't need alloc. Adding any
other algorithm feature pulls in alloc and the codec.
The alloc feature also enables compcol::vec (one-shot
compress_to_vec / decompress_to_vec helpers). The std feature
adds compcol::io (the Read/Write adapters) plus
From<Error> for std::io::Error so adapter code can use ?
freely.
features = ["all"] enables every algorithm and is the most ergonomic
choice when you don't know in advance which formats you'll see.
The compcol binary is gated on features = ["factory"] so a
--no-default-features library build doesn't try to compile it.
Errors
compcol::Error is a single crate-wide enum so trait objects work
without GATs:
Development
The crate currently ships with ~566 tests across 23 test binaries,
including round-trip tests for every algorithm with an encoder,
cross-validation against system gzip / xz / zstd / brotli /
compress / lz4 / python3 lzo / python3 lzma, and hand-crafted
hex fixtures for every decoder-only format (RAR 2/3/5, Quantum, LZX).
A simple benchmark harness lives at examples/bench.rs. Run it with:
It measures each compiled-in algorithm's encoder/decoder throughput
and compression ratio on a small fixed corpus and compares against
the system reference when one is installed. A snapshot of the output
is kept in BENCH.md.
License
MIT. © 2026 Karpeles Lab Inc. See LICENSE. The MIT terms
cover this crate's own source code; they grant no rights in any
third-party trademark or compressed-format specification.
A note on RAR
RAR, WinRAR, and unRAR are trademarks of Alexander Roshal / RARLAB.
This project is not affiliated with or endorsed by RARLAB.
The rar2 / rar3 / rar5 decoders are clean-room reimplementations
written from public format descriptions and other clean-room readers
(libarchive, The Unarchiver). No source code or data tables from
RARLAB's unRAR distribution were used. RARLAB's unRAR license forbids
using its source to recreate the RAR compression algorithm, so every RAR
encoder in this crate is permanently Unsupported by design — the same
decoder-only posture taken by libarchive, The Unarchiver, and 7-Zip.
rar1 is Unsupported even for decoding: a working RAR1 decoder needs
static Huffman code-length tables that RAR1 does not transmit, and no
license-clean published form of those tables is available to reproduce
here (the building blocks ship, but the tables do not). See the module
docs in src/rar1/, src/rar2/, src/rar3/, and src/rar5/ for details.