feat(compress): move frame epilogue serialization to Rust

Port the scalar frame-finalization policy and byte serialization into the Rust compression leaf while keeping checksum finalization, tracing, and the compression context in C. Preserve the init-to-ongoing transition on partial failure and reset the stage only after a successful epilogue.

Test Plan:

- cargo test --manifest-path rust/Cargo.toml --no-default-features --features compression

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

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

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

- make -B -C lib -j2 lib

- make -B -C tests -j2 test-zstream (84 deterministic, 6737 and 9012 fuzzer cases)
This commit is contained in:
2026-07-18 05:49:37 +02:00
parent 52c0eb4b9b
commit 459782ad55
2 changed files with 189 additions and 34 deletions
+16 -33
View File
@@ -37,6 +37,10 @@ size_t ZSTD_rust_writeFrameHeader(void* dst, size_t dstCapacity,
int contentSizeFlag, int format,
U32 windowLog, U64 pledgedSrcSize,
U32 dictID);
size_t ZSTD_rust_writeEpilogue(void* dst, size_t dstCapacity, int* stage,
int noDictIDFlag, int checksumFlag,
int contentSizeFlag, int format, U32 windowLog,
U32 checksum);
size_t ZSTD_rust_resetCCtxForSimpleCompression(void* cctx);
size_t ZSTD_rust_prepareCCtxForSimpleCompression(void* cctx,
size_t srcSize,
@@ -3938,41 +3942,20 @@ size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel)
* @return : nb of bytes written into dst (or an error code) */
static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity)
{
BYTE* const ostart = (BYTE*)dst;
BYTE* op = ostart;
U32 const checksum = cctx->appliedParams.fParams.checksumFlag
? (U32)XXH64_digest(&cctx->xxhState)
: 0;
DEBUGLOG(4, "ZSTD_writeEpilogue");
RETURN_ERROR_IF(cctx->stage == ZSTDcs_created, stage_wrong, "init missing");
/* special case : empty frame */
if (cctx->stage == ZSTDcs_init) {
size_t fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, &cctx->appliedParams, 0, 0);
FORWARD_IF_ERROR(fhSize, "ZSTD_writeFrameHeader failed");
dstCapacity -= fhSize;
op += fhSize;
cctx->stage = ZSTDcs_ongoing;
}
if (cctx->stage != ZSTDcs_ending) {
/* write one last empty block, make it the "last" block */
U32 const cBlockHeader24 = 1 /* last block */ + (((U32)bt_raw)<<1) + 0;
ZSTD_STATIC_ASSERT(ZSTD_BLOCKHEADERSIZE == 3);
RETURN_ERROR_IF(dstCapacity<3, dstSize_tooSmall, "no room for epilogue");
MEM_writeLE24(op, cBlockHeader24);
op += ZSTD_blockHeaderSize;
dstCapacity -= ZSTD_blockHeaderSize;
}
if (cctx->appliedParams.fParams.checksumFlag) {
U32 const checksum = (U32) XXH64_digest(&cctx->xxhState);
RETURN_ERROR_IF(dstCapacity<4, dstSize_tooSmall, "no room for checksum");
if (cctx->appliedParams.fParams.checksumFlag)
DEBUGLOG(4, "ZSTD_writeEpilogue: write checksum : %08X", (unsigned)checksum);
MEM_writeLE32(op, checksum);
op += 4;
}
cctx->stage = ZSTDcs_created; /* return to "created but no init" status */
return (size_t)(op-ostart);
return ZSTD_rust_writeEpilogue(
dst, dstCapacity, (int*)&cctx->stage,
cctx->appliedParams.fParams.noDictIDFlag,
cctx->appliedParams.fParams.checksumFlag,
cctx->appliedParams.fParams.contentSizeFlag,
(int)cctx->appliedParams.format,
cctx->appliedParams.cParams.windowLog,
checksum);
}
void ZSTD_CCtx_trace(ZSTD_CCtx* cctx, size_t extraCSize)