feat(compress): route complete stream frames through Rust

Route ordinary complete-input ZSTD_compressStream2 calls through the Rust frame compressor while retaining the C state machine for partial, advanced, and dictionary-backed streams. Track explicit maxBlockSize requests so the migrated path preserves the original byte-identical default behavior, and extend the C archive smoke test across context reuse and fallback cases.

Test Plan:

- cargo clippy --manifest-path rust/Cargo.toml

- cargo clippy --manifest-path rust/Cargo.toml --benches

- cargo clippy --manifest-path rust/Cargo.toml --tests

- cargo test --manifest-path rust/Cargo.toml --no-default-features --features compression (133 passed)

- make -B -C tests -j2 test-rust-lib-smoke and ./tests/rustLibSmoke

- make -B -C tests -j2 test-zstream (passed, including both APIs and maxBlockSize case 78)
This commit is contained in:
2026-07-18 01:52:28 +02:00
parent 96a0eabdb9
commit 23d45378bd
4 changed files with 232 additions and 11 deletions
+34 -6
View File
@@ -46,7 +46,12 @@ void ZSTD_rust_markSimpleCompression2Complete(void* cctx);
size_t ZSTD_compress2_c(ZSTD_CCtx* cctx,
void* dst, size_t dstCapacity,
const void* src, size_t srcSize);
size_t ZSTD_compressStream2_c(ZSTD_CCtx* cctx,
ZSTD_outBuffer* output,
ZSTD_inBuffer* input,
ZSTD_EndDirective endOp);
int ZSTD_rust_simpleCompress2Level(const void* cctx);
int ZSTD_rust_simpleCompressStream2Level(const void* cctx);
/* Context-free compression-parameter selection and sizing leaves live in
* Rust (rust/src/zstd_compress_params.rs). This file retains
@@ -949,7 +954,12 @@ size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int value)
default: RETURN_ERROR(parameter_unsupported, "unknown parameter");
}
return ZSTD_CCtxParams_setParameter(&cctx->requestedParams, param, value);
{ size_t const result = ZSTD_CCtxParams_setParameter(&cctx->requestedParams, param, value);
if (!ZSTD_isError(result) && param == ZSTD_c_maxBlockSize) {
cctx->rustSimpleCompress2MaxBlockSizeSet = 1;
}
return result;
}
}
size_t ZSTD_CCtx_getParameter(ZSTD_CCtx const* cctx, ZSTD_cParameter param, int* value)
@@ -1166,6 +1176,7 @@ size_t ZSTD_CCtx_reset(ZSTD_CCtx* cctx, ZSTD_ResetDirective reset)
RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong,
"Reset parameters is only possible during init stage.");
ZSTD_clearAllDicts(cctx);
cctx->rustSimpleCompress2MaxBlockSizeSet = 0;
return ZSTD_CCtxParams_reset(&cctx->requestedParams);
}
return 0;
@@ -4532,7 +4543,7 @@ int ZSTD_rust_simpleCompress2Level(const void* opaqueCctx)
|| params->targetCBlockSize != 0
|| params->srcSizeHint != 0
|| params->attachDictPref != ZSTD_dictDefaultAttach
|| params->literalCompressionMode != ZSTD_lcm_auto
|| params->literalCompressionMode != (ZSTD_ParamSwitch_e)ZSTD_lcm_auto
|| params->nbWorkers != 0
|| params->jobSize != 0
|| params->overlapLog != 0
@@ -4553,6 +4564,7 @@ int ZSTD_rust_simpleCompress2Level(const void* opaqueCctx)
|| params->postBlockSplitter != ZSTD_ps_auto
|| params->preBlockSplitter_level != 0
|| params->maxBlockSize != 0
|| cctx->rustSimpleCompress2MaxBlockSizeSet != 0
|| params->useRowMatchFinder != ZSTD_ps_auto
|| params->deterministicRefPrefix != 0
|| params->prefetchCDictTables != ZSTD_ps_auto
@@ -4570,6 +4582,22 @@ int ZSTD_rust_simpleCompress2Level(const void* opaqueCctx)
return params->compressionLevel;
}
/* Return the simple level only while a new stream frame can be initialized.
* Rust handles this complete-input case; all other stream states stay on the
* original implementation so partial output and advanced buffering remain
* governed by the C state machine. */
int ZSTD_rust_simpleCompressStream2Level(const void* opaqueCctx)
{
ZSTD_CCtx const* const cctx = (ZSTD_CCtx const*)opaqueCctx;
if (cctx == NULL
|| cctx->streamStage != zcss_init
|| cctx->pledgedSrcSizePlusOne != 0
|| cctx->rustSimpleCompress2Completed != 0) {
return (-2147483647 - 1);
}
return ZSTD_rust_simpleCompress2Level(opaqueCctx);
}
/* ZSTD_compress() is implemented by rust/src/zstd_compress.rs. */
@@ -5503,10 +5531,10 @@ static size_t ZSTD_CCtx_init_compressStream2(ZSTD_CCtx* cctx,
/* @return provides a minimum amount of data remaining to be flushed from internal buffers
*/
size_t ZSTD_compressStream2( ZSTD_CCtx* cctx,
ZSTD_outBuffer* output,
ZSTD_inBuffer* input,
ZSTD_EndDirective endOp)
size_t ZSTD_compressStream2_c( ZSTD_CCtx* cctx,
ZSTD_outBuffer* output,
ZSTD_inBuffer* input,
ZSTD_EndDirective endOp)
{
DEBUGLOG(5, "ZSTD_compressStream2, endOp=%u ", (unsigned)endOp);
/* check conditions */
+4
View File
@@ -518,6 +518,10 @@ struct ZSTD_CCtx_s {
U32 frameEnded;
/* The next one-shot stream call may reuse a Rust-compressed frame. */
unsigned rustSimpleCompress2Completed;
/* A caller may explicitly set maxBlockSize to zero. Keep that request
* on the C path so it remains byte-identical to the explicit default
* maxBlockSize value. */
unsigned rustSimpleCompress2MaxBlockSizeSet;
/* Stable in/out buffer verification */
ZSTD_inBuffer expectedInBuffer;