Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Getting started

Build a complete round trip, then choose the API that fits your application. Requires Rust 1.89+.

Install

cargo new zstd-demo
cd zstd-demo
cargo add mzstd@0.2.13

Or add this to Cargo.toml:

[dependencies]
mzstd = "0.2.13"

Compress and decompress

Replace src/main.rs with this complete program:

use mzstd::{Compressor, Decompressor, EncoderConfig, Level};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let input = "hello, smaller world! ".repeat(1000);
    let config = EncoderConfig::default().with_level(Level::try_from(3)?);
    let mut encoder = Compressor::new(config)?;
    let compressed = encoder.compress(input.as_bytes())?;

    let mut decoder = Decompressor::default();
    let restored = decoder.decompress(&compressed)?;
    assert_eq!(restored, input.as_bytes());

    println!(
        "{} input bytes → {} compressed bytes",
        input.len(),
        compressed.len()
    );
    Ok(())
}
cargo run --release

Choose the level explicitly: the default is level 3. Higher positive levels spend more CPU searching for compression opportunities. Compare speed and output size on your data; the benchmark pages show how results vary with input and level.

Reuse the workspace and output

A codec retains working memory between calls. compress_into appends a stream and returns its range; clear the destination when you want to reuse it for a new payload.

use mzstd::{Compressor, Decompressor, EncoderConfig, Level};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut encoder = Compressor::new(EncoderConfig::default().with_level(Level::try_from(3)?))?;
    let mut decoder = Decompressor::default();
    let mut output = Vec::new();

    for payload in [b"first message".as_slice(), b"second message".as_slice()] {
        output.clear();
        let stream = encoder.compress_into(payload, &mut output)?;
        assert_eq!(decoder.decompress(&output[stream])?, payload);
    }
    Ok(())
}

See retention policies to control which workspace allocations remain after an operation. Caller output capacity is separate.

Stream through Write

Write plain input into the adapter, then call finish to obtain a complete Zstandard stream. Dropping the writer does not finalize it.

use mzstd::{Compressor, Decompressor, EncoderConfig, InputSize, Level};
use std::io::Write;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let input = b"a payload arriving in two writes";
    let mut encoder = Compressor::new(EncoderConfig::default().with_level(Level::try_from(3)?))?;
    let stream = InputSize::Exact(input.len() as u64).into();
    let mut writer = encoder.writer(Vec::new(), stream);
    writer.write_all(&input[..10])?;
    writer.write_all(&input[10..])?;
    let compressed = writer
        .finish()
        .map_err(mzstd::io::FinishError::into_error)?;

    let mut decoder = Decompressor::default();
    assert_eq!(decoder.decompress(&compressed)?, input);
    Ok(())
}

For a retryable sink failure, FinishError::into_parts returns the error and writer. into_error discards the writer, as this in-memory example does. The streaming guide explains completion, backpressure, reader read-ahead, and direct sessions.

Choose features

The default features enable std and both codecs. To build only one codec, drop std, or enable framing containers, see Cargo features.

Next steps