| Vulnerabilities | |||||
|---|---|---|---|---|---|
| Version | Suggest | Low | Medium | High | Critical |
2.1.1+zstd.1.5.7 - This version is safe to use because it has no known security vulnerabilities at this time. Find out if your coding project uses this component and get notified of any reported security vulnerabilities with Meterian-X Open Source Security Platform
Maintain your licence declarations and avoid unwanted licences to protect your IP the way you intended.
BSD-3-Clause - BSD 3-Clause "New" or "Revised" LicenseThis library is a rust binding for the zstd compression library.
$ cargo add zstd# Cargo.toml
[dependencies]
zstd = "0.14"This library provides Read and Write wrappers to handle (de)compression,
along with convenience functions to made common tasks easier.
For instance, stream::copy_encode and stream::copy_decode are easy-to-use
wrappers around std::io::copy. Check the stream example:
use std::io;
// This function use the convenient `copy_encode` method
fn compress(level: i32) {
zstd::stream::copy_encode(io::stdin(), io::stdout(), level).unwrap();
}
// This function does the same thing, directly using an `Encoder`:
fn compress_manually(level: i32) {
let mut encoder = zstd::stream::Encoder::new(io::stdout(), level).unwrap();
io::copy(&mut io::stdin(), &mut encoder).unwrap();
encoder.finish().unwrap();
}
fn decompress() {
zstd::stream::copy_decode(io::stdin(), io::stdout()).unwrap();
}The async-compression crate
provides an async-ready integration of various compression algorithms,
including zstd-rs.
The frame header can record how big the data will be once decompressed, and whoever reads it can then size their buffer in one go instead of growing it - worth roughly a factor of two to them. Only a compressor that knows the length up front can record it:
| you are compressing | into a Vec
|
into a Write
|
|---|---|---|
a slice or a Vec
|
bulk::compress |
compress_sized_into |
| a file | compress_file |
compress_file_into |
a Read whose length you know |
compress_sized |
compress_sized_into |
any other Read
|
encode_all (no size)
|
copy_encode (no size)
|
Everything but the last row records the size. Reach for the Write column
when the data is large enough that you would rather not hold a Vec of it -
these stream straight through, so only the compressor's own buffers are in
memory. For a source that is neither a file nor a slice, its length is the
one thing you have to supply yourself.
On the way back, decode_all reads that header and sizes its output for you,
and decompressed_size gives you the same number for a buffer of your own.
This wrapper adds little over the C library. On the same data at level 3, a
re-used bulk::Compressor and bulk::Decompressor land within a few percent
of what zstd -b3 reports for the same file. If you are seeing much less than
that, it is usually one of these:
--release; a debug build times this
crate's wrappers rather than zstd.Vec rather than sizing it. The convenience functions that
return a Vec start from an empty one. On decompression, sizing the output
up front - bulk::decompress, or copy_decode into a
Vec::with_capacity - was worth roughly a factor of two in our measurements.bulk API avoids a copy through the streaming buffers. It is
worth about ten percent on decompression, so it is a much smaller effect
than sizing the output - the Read/Write wrappers are not the problem
people usually assume they are.zstdmt feature and
several workers, compression of a 33 MB input went about three times faster
here. It is a loss on small inputs, where there is not enough data to keep
the workers busy.To measure all of these on your own data:
cargo run --release --features zstdmt --example throughput -- <file>
It prints the matching zstd -b<level> command so you can compare against the
C library directly.
Enabled by default: legacy, arrays, zdict_builder.
| Feature | Default | Description |
|---|---|---|
arrays |
yes | Use fixed-size arrays ([u8; N]) as output buffers. |
legacy |
yes | Decode frames written by zstd versions older than 0.8. |
zdict_builder |
yes | Train new dictionaries. Using a dictionary always works. |
experimental |
Expose zstd's experimental API. It has no stability guarantees, and may change between zstd releases. | |
zstdmt |
Multi-threaded compression inside the C library. | |
thin |
Build a smaller C library, at some cost in speed and error reporting. | |
debug |
Enable zstd's debug logs. | |
no_asm |
Do not build the x86-64 assembly. | |
fat-lto, thin-lto
|
Cross-language LTO. Only works if clang builds the C library. |
|
doc-cfg |
Mark feature-gated items in the generated documentation. Needs a nightly compiler. | |
wasm |
Does nothing; kept so that existing dependants keep building. |
The following change how the C library is obtained or built:
| Feature | Default | Description |
|---|---|---|
bindgen |
Generate the bindings at build time rather than using the pre-generated ones. Needs libclang. |
|
pkg-config |
Link against a system-installed libzstd instead of building the bundled source. | |
vendored |
Always build the bundled source, even when pkg-config is also enabled. Useful to force a static build from a dependent crate. |
|
cmake |
Build the C library with zstd's own CMake files instead of the cc crate, which handles cross-compilation better. Needs cmake. |
The zstd-sys readme also covers the build-time environment variables, and what to do if the linker complains about a hidden zstd symbol being "referenced by DSO".
zstd is included as a submodule. To get everything during your clone, use:
git clone https://github.com/gyscos/zstd-rs --recursive
Or, if you cloned it without the --recursive flag,
call this from inside the repository:
git submodule update --init
Then, running cargo build should take care
of building the C library and linking to it.
By default, zstd allocates its internal state (compression windows, match
finder tables, stream buffers, dictionaries) with the C runtime's
malloc/free, invisible to a custom #[global_allocator].
The with-rust-allocator feature makes every context and dictionary this
crate creates (Encoder, Decoder, bulk::Compressor, dictionaries, ...)
allocate through Rust's global allocator instead. It is crate-wide: enabling
it in your own Cargo.toml also covers zstd usage inside your
dependencies, since Cargo unifies features.
zstd = { version = "0.14", features = ["with-rust-allocator"] }The feature implies experimental on zstd-safe because it relies on zstd's
ZSTD_create*_advanced() constructors, which require static linking. It
applies to contexts and prepared dictionaries created by the Rust wrappers,
including clones. Direct calls to zstd_sys, dictionary training, legacy
frame decoding, objects from the seekable format, and explicit zstd thread
pools can still allocate through C.
Prepared compression dictionaries use fixed parameters derived from their compression level and dictionary size. Unlike the default C constructor, the custom-allocator constructor does not store the level for later parameter adjustments based on the input size. Compressed output remains interoperable, but enabling this feature can change compression ratio, speed, and memory usage for prepared dictionaries, especially with large inputs and small dictionaries.
The bindgen feature requires Rust 1.71 or newer and libclang.
The pre-generated bindings remain compatible with Rust 1.64.
This library includes a pre-generated bindings.rs file.
You can also generate new bindings at build-time, using the bindgen feature:
cargo build --features bindgen
This implementation is largely inspired by bozaro's lz4-rs.