feat(compress): move target block policy to Rust

Port the target-sized block action policy behind a scalar Rust ABI while keeping sequence inspection, superblock compression, block-state confirmation, diagnostics, and raw/RLE emission in C. Preserve the strict three-byte header boundary, destination-too-small fallback, and first-block RLE guard with focused tests.

Test Plan:

- cargo test --manifest-path rust/Cargo.toml --no-default-features --features compression zstd_compress::tests::target_block

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

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

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

- cargo +nightly fmt --manifest-path rust/Cargo.toml --all

- make -B -C lib -j2 lib
This commit is contained in:
2026-07-18 06:37:07 +02:00
parent b19ca569f7
commit 21f8e8958c
2 changed files with 209 additions and 18 deletions
+36 -18
View File
@@ -66,6 +66,16 @@ void ZSTD_rust_reduceTable(U32* table, U32 size, U32 reducerValue,
U64 ZSTD_rust_advanceHashSalt(U64 hashSalt, U64 hashSaltEntropy);
int ZSTD_rust_indexTooCloseToMax(size_t nextSrcBaseOffset);
int ZSTD_rust_dictTooBig(size_t loadedDictSize);
enum {
ZSTD_RUST_TARGET_CBLOCK_ACTION_RAW = 0,
ZSTD_RUST_TARGET_CBLOCK_ACTION_RLE = 1,
ZSTD_RUST_TARGET_CBLOCK_ACTION_COMPRESSED = 2,
ZSTD_RUST_TARGET_CBLOCK_ACTION_ERROR = 3
};
int ZSTD_rust_targetCBlockSizeAction(int bss, int isFirstBlock,
int maybeRLE, int isRLE,
size_t cSize, size_t srcSize,
int strategy);
/* Context-free compression-parameter selection and sizing leaves live in
* Rust (rust/src/zstd_compress_params.rs). This file retains
@@ -3124,18 +3134,25 @@ static size_t ZSTD_compressBlock_targetCBlockSize_body(ZSTD_CCtx* zc,
const void* src, size_t srcSize,
const size_t bss, U32 lastBlock)
{
int const isCompress = bss == ZSTDbss_compress;
int maybeRLE = 0;
int isRLE = 0;
int action;
DEBUGLOG(6, "Attempting ZSTD_compressSuperBlock()");
if (bss == ZSTDbss_compress) {
if (/* We don't want to emit our first block as a RLE even if it qualifies because
* doing so will cause the decoder (cli only) to throw a "should consume all input error."
* This is only an issue for zstd <= v1.4.3
*/
!zc->isFirstBlock &&
ZSTD_maybeRLE(&zc->seqStore) &&
ZSTD_isRLE((BYTE const*)src, srcSize))
{
return ZSTD_rust_rleCompressBlock(dst, dstCapacity, *(BYTE const*)src, srcSize, lastBlock);
}
if (isCompress) {
maybeRLE = ZSTD_maybeRLE(&zc->seqStore);
isRLE = ZSTD_isRLE((BYTE const*)src, srcSize);
}
action = ZSTD_rust_targetCBlockSizeAction(
(int)bss, (int)zc->isFirstBlock, maybeRLE, isRLE,
0, srcSize, (int)zc->appliedParams.cParams.strategy);
if (action == ZSTD_RUST_TARGET_CBLOCK_ACTION_RLE) {
return ZSTD_rust_rleCompressBlock(dst, dstCapacity, *(BYTE const*)src, srcSize, lastBlock);
}
if (isCompress) {
/* Attempt superblock compression.
*
* Note that compressed size of ZSTD_compressSuperBlock() is not bound by the
@@ -3156,14 +3173,15 @@ static size_t ZSTD_compressBlock_targetCBlockSize_body(ZSTD_CCtx* zc,
*/
{ size_t const cSize =
ZSTD_compressSuperBlock(zc, dst, dstCapacity, src, srcSize, lastBlock);
if (cSize != ERROR(dstSize_tooSmall)) {
size_t const maxCSize =
srcSize - ZSTD_minGain(srcSize, zc->appliedParams.cParams.strategy);
action = ZSTD_rust_targetCBlockSizeAction(
(int)bss, (int)zc->isFirstBlock, 0, 0,
cSize, srcSize, (int)zc->appliedParams.cParams.strategy);
if (action == ZSTD_RUST_TARGET_CBLOCK_ACTION_ERROR) {
FORWARD_IF_ERROR(cSize, "ZSTD_compressSuperBlock failed");
if (cSize != 0 && cSize < maxCSize + ZSTD_blockHeaderSize) {
ZSTD_blockState_confirmRepcodesAndEntropyTables(&zc->blockState);
return cSize;
}
}
if (action == ZSTD_RUST_TARGET_CBLOCK_ACTION_COMPRESSED) {
ZSTD_blockState_confirmRepcodesAndEntropyTables(&zc->blockState);
return cSize;
}
}
} /* if (bss == ZSTDbss_compress)*/