structured_zstd/lib.rs
1//! Pure-Rust Zstandard codec with a production-grade decoder, dictionary
2//! handle reuse, and an actively-improved encoder.
3//!
4//! The crate ships:
5//!
6//! * [`decoding`] — [RFC 8878] decoder ([`decoding::StreamingDecoder`],
7//! [`decoding::FrameDecoder`], dictionary-backed paths via
8//! [`decoding::DictionaryHandle`]).
9//! * [`encoding`] — frame compressor, streaming encoder, named and numeric
10//! compression levels ([`encoding::CompressionLevel`]).
11//! * [`dictionary`] (feature `dict_builder`) — COVER / FastCOVER training
12//! plus raw-to-finalized dictionary helpers.
13//!
14//! No FFI, no cmake, no system zstd. `no_std` builds are supported by
15//! disabling the default `std` feature.
16//!
17//! The packaged README is included below for the docs.rs landing page; the
18//! API anchors above link straight into the per-module documentation.
19//!
20//! [RFC 8878]: https://www.rfc-editor.org/rfc/rfc8878
21// Keep crate docs aligned with the packaged README via the crate-local symlink in `zstd/README.md`.
22#![doc = include_str!("../README.md")]
23#![no_std]
24#![deny(trivial_casts, trivial_numeric_casts, rust_2018_idioms)]
25#![cfg_attr(docsrs, feature(doc_cfg))]
26
27#[cfg(feature = "std")]
28extern crate std;
29
30#[cfg(not(feature = "rustc-dep-of-std"))]
31extern crate alloc;
32
33#[cfg(feature = "std")]
34pub(crate) const VERBOSE: bool = false;
35
36macro_rules! vprintln {
37 ($($x:expr),*) => {
38 #[cfg(feature = "std")]
39 if crate::VERBOSE {
40 std::println!($($x),*);
41 }
42 }
43}
44
45mod bit_io;
46mod common;
47mod cpu_kernel;
48pub mod decoding;
49#[cfg(feature = "dict_builder")]
50#[cfg_attr(docsrs, doc(cfg(feature = "dict_builder")))]
51pub mod dictionary;
52pub mod encoding;
53mod histogram;
54
55#[cfg(feature = "lsm")]
56#[cfg_attr(docsrs, doc(cfg(feature = "lsm")))]
57pub mod skippable;
58
59pub(crate) mod blocks;
60
61#[cfg(feature = "fuzz_exports")]
62pub mod fse;
63#[cfg(feature = "fuzz_exports")]
64pub mod huff0;
65
66// `pub fn init_state<K: CpuKernel>` and friends inside the
67// fuzz_exports-public `huff0` module name `crate::cpu_kernel::CpuKernel`
68// in their signatures. Without a publicly-reachable path to `CpuKernel`
69// the bound triggers `private_bounds` / `private_interfaces`. Re-export
70// under the same feature gate so the fuzz harness build is clean.
71#[cfg(feature = "fuzz_exports")]
72pub use crate::cpu_kernel::{CpuKernel, ScalarKernel};
73
74#[cfg(not(feature = "fuzz_exports"))]
75pub(crate) mod fse;
76#[cfg(not(feature = "fuzz_exports"))]
77pub(crate) mod huff0;
78
79#[cfg(feature = "std")]
80pub mod io_std;
81
82#[cfg(feature = "std")]
83pub use io_std as io;
84
85#[cfg(not(feature = "std"))]
86pub mod io_nostd;
87
88#[cfg(not(feature = "std"))]
89pub use io_nostd as io;
90
91#[cfg(test)]
92mod tests;
93
94/// Re-exports of internal types used by benchmarks.
95///
96/// Gated behind the `bench_internals` feature so normal builds do not
97/// widen the public API surface. Not part of the stable API; items may
98/// change or disappear without notice.
99#[cfg(feature = "bench_internals")]
100#[doc(hidden)]
101pub mod testing {
102 pub use crate::bit_io::BitReaderReversed;
103 // `BitReaderReversed` is generic over `K: CpuKernel = ScalarKernel`,
104 // so both the trait bound and the default need a `pub` path to
105 // match the re-exported type's visibility. Without this the
106 // bench-build trips `private_bounds` / `private_interfaces`.
107 pub use crate::cpu_kernel::{CpuKernel, ScalarKernel};
108
109 /// Bench-only facade for the decoder wildcopy implementation.
110 ///
111 /// # Safety
112 /// Caller must satisfy the same safety contract as
113 /// `decoding::copy_bytes_overshooting_for_bench`.
114 #[inline(always)]
115 pub unsafe fn copy_bytes_overshooting_for_bench(
116 src: (*const u8, usize),
117 dst: (*mut u8, usize),
118 copy_at_least: usize,
119 ) {
120 // Keep decoder internals crate-private and expose only this bench shim.
121 unsafe { crate::decoding::copy_bytes_overshooting_for_bench(src, dst, copy_at_least) };
122 }
123
124 /// Maximum block size per RFC 8878 §3.1.1.2.3 (128 KiB).
125 /// Exposed for parity tests that feed exactly-one-block chunks
126 /// into the donor splitter comparator.
127 pub const MAX_BLOCK_SIZE: u32 = crate::common::MAX_BLOCK_SIZE;
128
129 /// Run our donor-port block splitter on a 128 KB chunk.
130 ///
131 /// `split_level` mirrors donor `ZSTD_splitBlock(level)`: `0` selects
132 /// the borders heuristic (`ZSTD_splitBlock_fromBorders`), `1..=4`
133 /// select `ZSTD_splitBlock_byChunks` at the corresponding sampling
134 /// level. Returns the split position (or `block.len()` if no split).
135 ///
136 /// Crate-internal facade for the donor-parity comparator test —
137 /// the underlying functions stay `fn` so they don't widen the
138 /// stable API surface.
139 pub fn block_splitter_decision(block: &[u8], split_level: usize) -> usize {
140 crate::encoding::frame_compressor::block_splitter_decision_for_bench(block, split_level)
141 }
142}
143
144/// SIMD wildcopy overshoot slack carried by every decoder backend
145/// (currently **32 bytes**). Sized so the AVX2 chunked kernel in
146/// `simd_copy::copy_bytes_overshooting` (32-byte stride on x86-64) can
147/// fire on tail copies near the end of a fixed-capacity output buffer.
148/// Donor zstd's `WILDCOPY_OVERLENGTH` is also 32 bytes today; this
149/// matches that contract.
150///
151/// Public so callers sizing an output slice for
152/// [`crate::decoding::FrameDecoder::decode_all`] can size
153/// `frame_content_size + WILDCOPY_OVERLENGTH` symbolically without
154/// duplicating the value. Use the const reference rather than a
155/// hardcoded literal — `simd_copy::copy_bytes_overshooting` already
156/// ships an AVX-512 64-byte chunked kernel, and the slack may grow
157/// further to reliably enable that wider kernel at buffer tails
158/// (mirroring how the bump from 16 → 32 enabled the AVX2 32-byte
159/// kernel at the tail).
160pub const WILDCOPY_OVERLENGTH: usize = crate::decoding::buffer_backend::WILDCOPY_OVERLENGTH;