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
- Sans I/O compression and decompression: caller buffers, progress counts, and completion.
- Read / Write I/O: readers and writers for raw, parallel, and framed streams.
- Parallel compression: scoped threads, Rayon, files, and streaming.
- Framing containers: multiple resources, metadata, and indexed reads.
- Choose your API: every entry point for both codecs, with its guide.
- Configuration and features: level, parameters, and Cargo features.
- Decompression and limits: budgets for untrusted input.
- Examples: pick a recipe and run the repository examples.