From adb6928f049999928f5e0e6ea1b1243e174fd1dc Mon Sep 17 00:00:00 2001 From: ddidderr Date: Sat, 18 Jul 2026 13:27:34 +0200 Subject: [PATCH] feat(compress): move literal compression policy to Rust ZSTD_literalsCompressionIsDisabled() previously switched on the private ZSTD_CCtx_params layout in a header inline helper. Replace that switch with a scalar ABI call that extracts only literalCompressionMode, strategy, and targetLength in C. The Rust helper preserves the enable and disable results, the fast-strategy auto rule, and C's debug assertion plus release fallthrough for invalid modes. Keep callers and compression state ownership in C, and cover the policy truth table and debug invalid-mode invariant in Rust. Test Plan: - Compression-feature clippy for the library, benches, and tests before and after nightly formatting -- passed. - `cargo +nightly fmt --manifest-path rust/Cargo.toml` -- passed. - `cargo test --manifest-path rust/Cargo.toml --no-default-features --features compression zstd_compress_params` -- passed (43 tests). - `make -B -C lib -j2 lib` -- passed. - `make -C tests test-rust-lib-smoke` -- passed. - `tests/fuzzer -s4560 -t47 -i48 -v` and `-s4560 -t56 -i57 -v` -- passed. - `make -C tests -j2 test-zstream` -- passed (84 named, 5,416, and 8,387 randomized cases). - `git diff --check` and `git diff --cached --check` -- passed. --- lib/compress/zstd_compress_internal.h | 19 +++----- rust/src/zstd_compress_params.rs | 70 +++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 11 deletions(-) diff --git a/lib/compress/zstd_compress_internal.h b/lib/compress/zstd_compress_internal.h index 443b5c6b1..d4610c6a7 100644 --- a/lib/compress/zstd_compress_internal.h +++ b/lib/compress/zstd_compress_internal.h @@ -668,19 +668,16 @@ MEM_STATIC size_t ZSTD_minGain(size_t srcSize, ZSTD_strategy strat) return (srcSize >> minlog) + 2; } +int ZSTD_rust_params_literalsCompressionIsDisabled(int literalCompressionMode, + int strategy, + U32 targetLength); + MEM_STATIC int ZSTD_literalsCompressionIsDisabled(const ZSTD_CCtx_params* cctxParams) { - switch (cctxParams->literalCompressionMode) { - case ZSTD_ps_enable: - return 0; - case ZSTD_ps_disable: - return 1; - default: - assert(0 /* impossible: pre-validated */); - ZSTD_FALLTHROUGH; - case ZSTD_ps_auto: - return (cctxParams->cParams.strategy == ZSTD_fast) && (cctxParams->cParams.targetLength > 0); - } + return ZSTD_rust_params_literalsCompressionIsDisabled( + (int)cctxParams->literalCompressionMode, + (int)cctxParams->cParams.strategy, + cctxParams->cParams.targetLength); } /*! ZSTD_safecopyLiterals() : diff --git a/rust/src/zstd_compress_params.rs b/rust/src/zstd_compress_params.rs index 3fab8a83f..0cf067a76 100644 --- a/rust/src/zstd_compress_params.rs +++ b/rust/src/zstd_compress_params.rs @@ -449,6 +449,37 @@ pub extern "C" fn ZSTD_rust_params_resolveExternalSequenceValidation(mode: c_int resolve_external_sequence_validation(mode) } +#[inline] +fn literals_compression_is_disabled( + literal_compression_mode: c_int, + strategy: c_int, + target_length: u32, +) -> c_int { + match literal_compression_mode { + ZSTD_RUST_PS_ENABLE => 0, + ZSTD_RUST_PS_DISABLE => 1, + ZSTD_RUST_PS_AUTO => c_int::from(strategy == ZSTD_FAST && target_length > 0), + _ => { + debug_assert!(false, "invalid ZSTD_ParamSwitch_e literal mode"); + c_int::from(strategy == ZSTD_FAST && target_length > 0) + } + } +} + +/// C ABI for `ZSTD_literalsCompressionIsDisabled()`. +/// +/// The C wrapper extracts these scalar fields so the private +/// `ZSTD_CCtx_params` layout does not cross the Rust boundary. Invalid modes +/// retain C's debug assertion and release-mode fallthrough to the auto policy. +#[no_mangle] +pub extern "C" fn ZSTD_rust_params_literalsCompressionIsDisabled( + literal_compression_mode: c_int, + strategy: c_int, + target_length: u32, +) -> c_int { + literals_compression_is_disabled(literal_compression_mode, strategy, target_length) +} + #[inline] fn cdict_indices_are_tagged(cparams: ZSTD_compressionParameters) -> bool { cparams.strategy == ZSTD_FAST || cparams.strategy == ZSTD_DFAST @@ -1835,6 +1866,45 @@ mod tests { } } + #[test] + fn literal_compression_policy_matches_mode_strategy_and_target_length() { + for strategy in [ZSTD_FAST, ZSTD_DFAST, ZSTD_BTULTRA2] { + for target_length in [0, 1] { + assert_eq!( + ZSTD_rust_params_literalsCompressionIsDisabled( + ZSTD_RUST_PS_ENABLE, + strategy, + target_length, + ), + 0 + ); + assert_eq!( + ZSTD_rust_params_literalsCompressionIsDisabled( + ZSTD_RUST_PS_DISABLE, + strategy, + target_length, + ), + 1 + ); + assert_eq!( + ZSTD_rust_params_literalsCompressionIsDisabled( + ZSTD_RUST_PS_AUTO, + strategy, + target_length, + ), + c_int::from(strategy == ZSTD_FAST && target_length > 0) + ); + } + } + } + + #[cfg(debug_assertions)] + #[test] + #[should_panic] + fn literal_compression_policy_rejects_invalid_mode_in_debug() { + literals_compression_is_disabled(99, ZSTD_FAST, 1); + } + #[test] fn level_tables_match_representative_clevels_entries() { let large = select_cparams(3, ZSTD_CONTENTSIZE_UNKNOWN, 0, ZSTD_RUST_CPM_UNKNOWN);