feat(compress): move CCtx parameter policy leaf to Rust

ZSTD_getCParamsFromCCtxParams previously kept its context-free selection,
LDM window override, nonzero-field override, and final adjustment orchestration
in C. Move that pipeline into a scalar Rust ABI leaf while keeping the private
ZSTD_CCtx_params snapshot in C. The ABI passes the compression parameters by
value, the source-size hint, mode switches, and the LDM default window log.

The active ZSTD_EXCLUDE_* definitions remain owned by the C preprocessor and
are encoded as a mask. Rust applies that mask before each adjustment stage,
including the existing standalone adjustment callers, so reduced compressor
builds retain the original fallback cascade without duplicating CCtx state or
compile-time configuration in Rust.

Test Plan:
- `cargo test --manifest-path rust/Cargo.toml --no-default-features --features compression`
  -- passed, 337 tests.
- All three compression clippy commands passed before and after
  `cargo +nightly fmt --manifest-path rust/Cargo.toml`.
- `make -C lib -j2 lib-mt` and `make -C lib -j2 lib-nomt` -- passed.
- `make -C tests -j2 test-zstream` -- passed 84 deterministic tests,
  5,191 standard randomized cases, and 9,382 new-API randomized cases.
- `git diff --cached --check` -- passed.
This commit is contained in:
2026-07-18 14:27:24 +02:00
parent 3bd4dba2ee
commit 837e4f0998
2 changed files with 398 additions and 65 deletions
+62 -56
View File
@@ -121,11 +121,11 @@ size_t ZSTD_rust_checkBufferStability(
/* Context-free compression-parameter selection and sizing leaves live in
* Rust (rust/src/zstd_compress_params.rs). This file retains
* configuration-sensitive policy: the excluded-block-compressor strategy
* cascade, private ZSTD_CCtx_params handling, and sanitizer workspace
* policy, which it feeds to the leaves as explicit scalar inputs. The
* ZSTD_CParamMode_e and ZSTD_ParamSwitch_e enums are passed as int; the
* Rust side mirrors their values. */
* configuration-sensitive policy: the C-preprocessor construction of the
* excluded-block-compressor mask, private ZSTD_CCtx_params handling, and
* sanitizer workspace policy, which it feeds to the leaves as explicit
* scalar inputs. The ZSTD_CParamMode_e and ZSTD_ParamSwitch_e enums are
* passed as int; the Rust side mirrors their values. */
int ZSTD_rust_params_maxCLevel(void);
int ZSTD_rust_params_minCLevel(void);
int ZSTD_rust_params_defaultCLevel(void);
@@ -143,6 +143,13 @@ ZSTD_compressionParameters
ZSTD_rust_params_adjustCParams(ZSTD_compressionParameters cParams, U64 srcSize,
size_t dictSize, int mode,
int useRowMatchFinder);
ZSTD_compressionParameters ZSTD_rust_params_applyStrategyExclusions(
ZSTD_compressionParameters cParams, U32 exclusionMask);
ZSTD_compressionParameters ZSTD_rust_params_getCParamsFromCCtxParams(
int compressionLevel, int cctxSrcSizeHint, U64 srcSizeHint,
size_t dictSize, int mode, int enableLdm, U32 ldmDefaultWindowLog,
ZSTD_compressionParameters overrides, int useRowMatchFinder,
U32 exclusionMask);
ZSTD_parameters ZSTD_rust_params_makeParams(ZSTD_compressionParameters cParams);
size_t ZSTD_rust_params_maxNbSeq(size_t blockSize, U32 minMatch,
int useSequenceProducer);
@@ -1141,6 +1148,8 @@ U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat)
return ZSTD_rust_params_cycleLog(hashLog, (int)strat);
}
static U32 ZSTD_getCParamsExclusionMask(void);
/** ZSTD_adjustCParams_internal() :
* optimize `cPar` for a specified input (`srcSize` and `dictSize`).
* mostly downsize to reduce memory consumption and initialization latency.
@@ -1158,46 +1167,10 @@ ZSTD_adjustCParams_internal(ZSTD_compressionParameters cPar,
assert(ZSTD_checkCParams(cPar)==0);
/* Cascade the selected strategy down to the next-highest one built into
* this binary. */
#ifdef ZSTD_EXCLUDE_BTULTRA_BLOCK_COMPRESSOR
if (cPar.strategy == ZSTD_btultra2) {
cPar.strategy = ZSTD_btultra;
}
if (cPar.strategy == ZSTD_btultra) {
cPar.strategy = ZSTD_btopt;
}
#endif
#ifdef ZSTD_EXCLUDE_BTOPT_BLOCK_COMPRESSOR
if (cPar.strategy == ZSTD_btopt) {
cPar.strategy = ZSTD_btlazy2;
}
#endif
#ifdef ZSTD_EXCLUDE_BTLAZY2_BLOCK_COMPRESSOR
if (cPar.strategy == ZSTD_btlazy2) {
cPar.strategy = ZSTD_lazy2;
}
#endif
#ifdef ZSTD_EXCLUDE_LAZY2_BLOCK_COMPRESSOR
if (cPar.strategy == ZSTD_lazy2) {
cPar.strategy = ZSTD_lazy;
}
#endif
#ifdef ZSTD_EXCLUDE_LAZY_BLOCK_COMPRESSOR
if (cPar.strategy == ZSTD_lazy) {
cPar.strategy = ZSTD_greedy;
}
#endif
#ifdef ZSTD_EXCLUDE_GREEDY_BLOCK_COMPRESSOR
if (cPar.strategy == ZSTD_greedy) {
cPar.strategy = ZSTD_dfast;
}
#endif
#ifdef ZSTD_EXCLUDE_DFAST_BLOCK_COMPRESSOR
if (cPar.strategy == ZSTD_dfast) {
cPar.strategy = ZSTD_fast;
cPar.targetLength = 0;
}
#endif
* this binary. The C preprocessor constructs the mask so Rust does not
* need to mirror this build's active ZSTD_EXCLUDE_* definitions. */
cPar = ZSTD_rust_params_applyStrategyExclusions(
cPar, ZSTD_getCParamsExclusionMask());
/* The remaining adjustment logic is context-free and lives in Rust. The
* short-cache and row-hash tag widths the leaf assumes are fixed
@@ -1221,20 +1194,53 @@ ZSTD_adjustCParams(ZSTD_compressionParameters cPar,
static ZSTD_compressionParameters ZSTD_getCParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize, ZSTD_CParamMode_e mode);
static ZSTD_parameters ZSTD_getParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize, ZSTD_CParamMode_e mode);
enum {
ZSTD_RUST_PARAMS_EXCLUDE_BTULTRA = 1u << 0,
ZSTD_RUST_PARAMS_EXCLUDE_BTOPT = 1u << 1,
ZSTD_RUST_PARAMS_EXCLUDE_BTLAZY2 = 1u << 2,
ZSTD_RUST_PARAMS_EXCLUDE_LAZY2 = 1u << 3,
ZSTD_RUST_PARAMS_EXCLUDE_LAZY = 1u << 4,
ZSTD_RUST_PARAMS_EXCLUDE_GREEDY = 1u << 5,
ZSTD_RUST_PARAMS_EXCLUDE_DFAST = 1u << 6
};
static U32 ZSTD_getCParamsExclusionMask(void)
{
U32 mask = 0;
#ifdef ZSTD_EXCLUDE_BTULTRA_BLOCK_COMPRESSOR
mask |= ZSTD_RUST_PARAMS_EXCLUDE_BTULTRA;
#endif
#ifdef ZSTD_EXCLUDE_BTOPT_BLOCK_COMPRESSOR
mask |= ZSTD_RUST_PARAMS_EXCLUDE_BTOPT;
#endif
#ifdef ZSTD_EXCLUDE_BTLAZY2_BLOCK_COMPRESSOR
mask |= ZSTD_RUST_PARAMS_EXCLUDE_BTLAZY2;
#endif
#ifdef ZSTD_EXCLUDE_LAZY2_BLOCK_COMPRESSOR
mask |= ZSTD_RUST_PARAMS_EXCLUDE_LAZY2;
#endif
#ifdef ZSTD_EXCLUDE_LAZY_BLOCK_COMPRESSOR
mask |= ZSTD_RUST_PARAMS_EXCLUDE_LAZY;
#endif
#ifdef ZSTD_EXCLUDE_GREEDY_BLOCK_COMPRESSOR
mask |= ZSTD_RUST_PARAMS_EXCLUDE_GREEDY;
#endif
#ifdef ZSTD_EXCLUDE_DFAST_BLOCK_COMPRESSOR
mask |= ZSTD_RUST_PARAMS_EXCLUDE_DFAST;
#endif
return mask;
}
ZSTD_compressionParameters ZSTD_getCParamsFromCCtxParams(
const ZSTD_CCtx_params* CCtxParams, U64 srcSizeHint, size_t dictSize, ZSTD_CParamMode_e mode)
{
ZSTD_compressionParameters cParams;
if (srcSizeHint == ZSTD_CONTENTSIZE_UNKNOWN && CCtxParams->srcSizeHint > 0) {
assert(CCtxParams->srcSizeHint>=0);
srcSizeHint = (U64)CCtxParams->srcSizeHint;
}
cParams = ZSTD_getCParams_internal(CCtxParams->compressionLevel, srcSizeHint, dictSize, mode);
if (CCtxParams->ldmParams.enableLdm == ZSTD_ps_enable) cParams.windowLog = ZSTD_LDM_DEFAULT_WINDOW_LOG;
ZSTD_rust_params_overrideCParams(&cParams, &CCtxParams->cParams);
assert(!ZSTD_checkCParams(cParams));
/* srcSizeHint == 0 means 0 */
return ZSTD_adjustCParams_internal(cParams, srcSizeHint, dictSize, mode, CCtxParams->useRowMatchFinder);
return ZSTD_rust_params_getCParamsFromCCtxParams(
CCtxParams->compressionLevel, CCtxParams->srcSizeHint,
srcSizeHint, dictSize, (int)mode,
(int)CCtxParams->ldmParams.enableLdm,
ZSTD_LDM_DEFAULT_WINDOW_LOG, CCtxParams->cParams,
(int)CCtxParams->useRowMatchFinder,
ZSTD_getCParamsExclusionMask());
}
static size_t