rusty_zstd 0.1.0

A ground-up, pure-Rust Zstandard (RFC 8878) compressor and decompressor. Levels -7..22 with all nine libzstd strategies, dictionaries + trainer, long-distance matching, seekable frames, multi-threading. Interoperable both directions with facebook/zstd v1.5.7, dual-gated per commit. Zero dependencies, no C, no *-sys, no FFI; builds on no_std + alloc and wasm32. MIT OR Apache-2.0.
Documentation
  • Coverage
  • 100%
    190 out of 190 items documented2 out of 3 items with examples
  • Size
  • Source code size: 1.36 MB This is the summed size of all the files inside the crates.io package for this release.
  • Documentation size: 5.62 MB This is the summed size of all files generated by rustdoc for all configured targets
  • Ø build duration
  • this release: 11s Average build duration of successful builds.
  • all releases: 11s Average build duration of successful builds in releases after 2024-10-23.
  • Links
  • Homepage
  • Remade-With-Rust/rusty_zstd
    0 0 0
  • crates.io
  • Dependencies
  • Versions
  • Owners
  • Ttimmahlax

rusty_zstd

crates.io docs.rs CI License: MIT OR Apache-2.0 Remade With Rust By Mata Network

A ground-up, pure-Rust Zstandard (RFC 8878) compressor and decompressor. #![deny(unsafe_code)] everywhere but one audited SIMD island, zero dependencies, no C, no *-sys crate, no FFI. Every frame it emits decompresses in facebook/zstd v1.5.7 and every frame that emits decompresses here — dual-gated on the Silesia corpus every commit.

Part of Remade With Rust by Mata Network. Full README, benchmark boards and methodology: the repository.


Install

cargo add rusty_zstd
[dependencies]
rusty_zstd = "0.1"

# …or for embedded / wasm targets with no `std`:
rusty_zstd = { version = "0.1", default-features = false, features = ["alloc"] }

The minimum supported configuration is no_std + alloc — every entry point returns or fills a Vec, so alloc is required. MSRV is 1.85.

Feature Default What it adds
std std::io-shaped streaming, multi-threading, the trainer, runtime ISA dispatch
alloc implied by std; the minimum supported configuration
profile the in-process stage profiler and its counters (off = zero overhead)

Quick start

use rusty_zstd::{compress, decompress, DEFAULT_CLEVEL};

let data = b"the quick brown fox jumps over the lazy dog ".repeat(64);

let packed = compress(&data, DEFAULT_CLEVEL)?;   // level 3, as libzstd defaults
assert!(packed.len() < data.len());
assert_eq!(decompress(&packed)?, data);          // lossless, always
# Ok::<(), rusty_zstd::Error>(())

Levels run −7…22 with all nine libzstd strategies behind them. compress_with takes a CompressOptions for the checksum flag, content size and dictionary ID; compress_with_advanced exposes the full AdvancedOptions — window log, strategy, LDM, workers, job size, overlap.

Streaming, for data that does not fit in memory. The pump is libzstd-shaped: hand it an input slice and an output buffer, and it reports what it consumed and produced.

use rusty_zstd::{compress_stream_out_size, Compressor, Flush};

let mut enc = Compressor::new(3)?;
let mut out = Vec::new();
let mut buf = vec![0u8; compress_stream_out_size()];

for chunk in [b"first chunk ".as_slice(), b"second chunk".as_slice()] {
    let mut fed = 0;
    while fed < chunk.len() {
        let st = enc.stream(&chunk[fed..], &mut buf, Flush::Continue)?;
        fed += st.input_consumed;
        out.extend_from_slice(&buf[..st.output_produced]);
    }
}
loop {
    let st = enc.stream(&[], &mut buf, Flush::End)?;
    out.extend_from_slice(&buf[..st.output_produced]);
    if st.done {
        break;
    }
}
assert_eq!(rusty_zstd::decompress(&out)?, b"first chunk second chunk");
# Ok::<(), rusty_zstd::Error>(())

Dictionaries, trained from your own samples — the win that matters for many small records:

use rusty_zstd::{compress_using_dict, decompress_using_dict, train, Dictionary, TrainOptions};

let samples: Vec<Vec<u8>> = (0..256)
    .map(|i| format!("{{\"event\":\"click\",\"id\":{i},\"session\":\"abc123\"}}").into_bytes())
    .collect();
let refs: Vec<&[u8]> = samples.iter().map(|s| s.as_slice()).collect();

let raw = train(&refs, TrainOptions::default())?;    // fastcover, d=8 steps=4
let dict = Dictionary::from_bytes(&raw)?;

let packed = compress_using_dict(&samples[0], &dict, 3)?;
assert_eq!(decompress_using_dict(&packed, &dict)?, samples[0]);
# Ok::<(), rusty_zstd::Error>(())

What is in here

Area Surface
One-shot compress, decompress, decompress_into, compress_bound, content_size, find_frame_compressed_size
Options CompressOptions, AdvancedOptions, DecompressOptions, CompressionParameters, Strategy
Streaming Compressor, Decompressor, Flush, StreamStatus, and the four recommended-buffer-size helpers
Dictionaries Dictionary, compress_using_dict, decompress_using_dict, compress_using_prefix (patch-from), train + TrainOptions / TrainAlgo
Long-range LdmParams, DEFAULT_LONG_WINDOW_LOG
Seekable compress_seekable, decompress_frame_at, parse_seek_table, SeekTable, SeekEntry
Multi-thread compress_mt, default_nb_workers, resolve_job_size, overlap_size
Inspection get_frame_header, FrameHeader, FrameKind, inspect_frames, ListedFrame
Checksum xxh64 — the frame content hash, usable on its own

Items marked #[doc(hidden)] are campaign instrumentation for the repository's own benchmark harness. They carry no semver promise and may be renamed or removed in any release.

Correctness

Gated against facebook/zstd v1.5.7 as an external process, in both directions, every commit: C compresses → this decompresses bit-exact, and this compresses → C's zstd -t and zstd -d accept it. The XXH64 checksum is gated against the published vectors, and every SIMD kernel against its scalar twin.

License

MIT OR Apache-2.0, at your option. No GPL/LGPL and no C anywhere in the dependency tree — CI-enforced with cargo-deny.