Thanks for your interest. This crate has a few hard constraints that every change must respect — please read them before opening a PR.
no_std. The library is#![no_std]. Usecoreand, when you need the heap,alloc(gated behind theallocfeature). Never reach forstdoutside thestd/tokiofeature-gated modules (compcol::io,compcol::tokio_io).#![forbid(unsafe_code)]. Nounsafe, anywhere, ever. It is set crate-wide via[lints.rust] unsafe_code = "forbid".- Zero runtime dependencies.
[dependencies]carries onlytokio, and that is optional (pulled in solely by thetokiofeature). Do not add runtime dependencies. Dev-dependencies for tests are acceptable when justified.
Decoders process untrusted input and must never panic, read out of bounds, or allocate unboundedly on malformed data:
- Use checked arithmetic (
checked_add,checked_mul, …) and bounds-checked indexing/slicing — nounwrap()/expect()on attacker-controlled lengths, offsets, or counts. - Reject malformed input by returning an appropriate
[
crate::Error] variant (Corrupt,BadHeader,InvalidHuffmanTree,InvalidDistance,Unsupported, …) — never by panicking. - Bound output. Don't pre-allocate from an attacker-supplied size
field without a sanity cap. Output limiting for callers is provided by
compcol::limit::LimitedDecoder; your decoder must still not blow up internally. - Every decoder gets a fuzz target asserting "no panic on arbitrary input" (see below).
- Module: create
src/<codec>/(orsrc/<codec>.rsfor a tiny one). - Internal traits: implement the private
RawEncoder/RawDecoderfromsrc/traits.rs. A blanket impl auto-derives the publicEncoder/Decoderfrom these — do not implement the public traits directly. If the format has no encoder (decoder-only, or license-restricted), the encoder'sraw_encode/raw_finishreturnError::Unsupported. - Marker type: add a zero-sized type implementing
Algorithm(const NAME,type Encoder/Decoder,type EncoderConfig/DecoderConfig,encoder_with/decoder_with). Use()for configs with no tunables. Seesrc/rle.rsfor the smallest complete example. - Cargo feature: add a
<codec> = ["alloc"]entry inCargo.toml(or= []if genuinelyalloc-free likerle), with a doc comment, and add the feature to theallmeta-feature list. - Declare it: add
#[cfg(feature = "<codec>")] pub mod <codec>;tosrc/lib.rs. - Register it: in
src/factory.rs, add#[cfg(feature = "<codec>")]arms for the marker type'sNAMEinencoder_by_name,decoder_by_name(andencoder_by_name_with_levelif it has a level), and add it to bothnames()andextension()so it shows up in by-name listing and gets a CLI output suffix. - Tests: add
tests/<codec>.rs(round-trip if there's an encoder; reference-tool cross-validation or hex fixtures for decoder-only formats). - Fuzz: add
fuzz/fuzz_targets/decoder_<codec>.rsdriving the decoder over arbitrary bytes and asserting it never panics (copy an existing target, e.g.decoder_lz4.rs, as the template).
The crate is MIT and stays clean-room:
- Implement codecs from public specifications and facts-only functional descriptions only.
- Do not copy code or data tables from LGPL/GPL sources — notably
The Unarchiver / XADMaster — or from RARLAB's
unRARdistribution. RARLAB's license forbids using its source to recreate the RAR compression algorithm, which is why every RAR encoder is permanentlyUnsupported. - If a codec genuinely needs a fixed interoperability table that exists
only in a license-incompatible source, treat it like the existing
rar1/ StuffIt situations: ship the well-defined building blocks clean-room, keep any non-clean-room table out of the spec-derived material, and either leave the decoderUnsupported(therar1case) or supply the table as a separately-licensed, maintainer-sanctioned adjunct kept out of the clean-room corpus (thesit13case). Document the provenance in the module docs, assrc/rar1/andsrc/sit13/do.
CI (.github/workflows/ci.yml) runs on Linux/macOS/Windows and denies
warnings. Before pushing:
cargo fmt --all --check
cargo clippy --all-targets --all-features -- -D warnings
cargo test --all-features
cargo build --no-default-features # bare no_std
cargo build --no-default-features --features all # every algo, still no_std
RUSTDOCFLAGS="-D warnings -D rustdoc::broken-intra-doc-links" cargo doc --no-deps --all-featuresCI also runs clippy on narrow feature subsets (lz4-only, zstd-only)
to catch dead-code regressions in the shared bits / checksum /
huffman modules — keep those #[cfg]-gated correctly.
Do not edit CHANGELOG.md in your PR; releases are managed by
release-plz.