feat(compress): move sequence API orchestration into Rust
Move the high-level orchestration of ZSTD_compressSequences() and ZSTD_compressSequencesAndLiterals() into Rust. Rust now owns the validation precedence, CCtx initialization handoff, frame-header and checksum ordering, block-loop dispatch, and output accounting for both public sequence APIs. Keep the private CCtx, sequence-store, block-state, checksum, and conversion layouts in C. C supplies scalar block projections and callbacks for private initialization, frame-header emission, checksum operations, and sequence-state preparation, preserving the ABI boundary and the existing codec leaves. Test Plan: - focused sequence API policy tests: 4 passed - cargo test --manifest-path rust/Cargo.toml --all-targets -- --test-threads=1: 533 passed - cargo test --manifest-path rust/cli/Cargo.toml --all-targets -- --test-threads=1: 169 passed - legacy compression/decompression/dictionary-builder feature matrix: 588 passed - six library/CLI clippy gates with -D warnings - capped serial native library/program rebuilds, 41 CLI tests, Rust library smoke, and full test-zstd round trips - capped serial stress gates: 278 fuzzer cases, 84+129+143 zstream cases, and 1,601 decode-corpus cases - every heavyweight command used CARGO_BUILD_JOBS=1 or make -j1 and ulimit -v 41943040; no worker/native process remained afterward Commit is intentionally unsigned because GPG pinentry hangs in this non-interactive environment.
This commit is contained in:
+218
-162
@@ -1021,6 +1021,72 @@ typedef char ZSTD_rust_sequence_literals_state_layout[
|
|||||||
== 6 * sizeof(void*) + 4 * sizeof(int) + 3 * sizeof(void*))
|
== 6 * sizeof(void*) + 4 * sizeof(int) + 3 * sizeof(void*))
|
||||||
? 1 : -1];
|
? 1 : -1];
|
||||||
|
|
||||||
|
/* The public sequence APIs keep their CCtx initialization, frame header, and
|
||||||
|
* checksum state in C, but Rust owns the ordering and output accounting. The
|
||||||
|
* two block-loop projections above are populated by the initialization
|
||||||
|
* callback after the private CCtx has been initialized. */
|
||||||
|
typedef struct ZSTD_rust_sequenceApiState_s ZSTD_rust_sequenceApiState;
|
||||||
|
typedef size_t (*ZSTD_rust_sequenceApiInit_f)(
|
||||||
|
void* context, size_t pledgedSrcSize,
|
||||||
|
ZSTD_rust_sequenceApiState* state);
|
||||||
|
typedef size_t (*ZSTD_rust_sequenceApiWriteFrameHeader_f)(
|
||||||
|
void* context, void* dst, size_t dstCapacity, size_t pledgedSrcSize);
|
||||||
|
typedef void (*ZSTD_rust_sequenceApiUpdateChecksum_f)(
|
||||||
|
void* context, const void* src, size_t srcSize);
|
||||||
|
typedef U32 (*ZSTD_rust_sequenceApiDigestChecksum_f)(void* context);
|
||||||
|
typedef void (*ZSTD_rust_sequenceApiWriteChecksum_f)(
|
||||||
|
void* context, void* dst, U32 checksum);
|
||||||
|
|
||||||
|
struct ZSTD_rust_sequenceApiState_s {
|
||||||
|
void* callbackContext;
|
||||||
|
ZSTD_rust_sequenceCompressionState* sequenceState;
|
||||||
|
ZSTD_rust_sequenceLiteralsState* sequenceLiteralsState;
|
||||||
|
ZSTD_rust_sequenceApiInit_f init;
|
||||||
|
ZSTD_rust_sequenceApiWriteFrameHeader_f writeFrameHeader;
|
||||||
|
ZSTD_rust_sequenceApiUpdateChecksum_f updateChecksum;
|
||||||
|
ZSTD_rust_sequenceApiDigestChecksum_f digestChecksum;
|
||||||
|
ZSTD_rust_sequenceApiWriteChecksum_f writeChecksum;
|
||||||
|
int checksumFlag;
|
||||||
|
int blockDelimiters;
|
||||||
|
int validateSequences;
|
||||||
|
};
|
||||||
|
size_t ZSTD_rust_compressSequences(
|
||||||
|
ZSTD_rust_sequenceApiState* state,
|
||||||
|
void* dst, size_t dstCapacity,
|
||||||
|
const ZSTD_Sequence* inSeqs, size_t inSeqsSize,
|
||||||
|
const void* src, size_t srcSize);
|
||||||
|
size_t ZSTD_rust_compressSequencesAndLiterals(
|
||||||
|
ZSTD_rust_sequenceApiState* state,
|
||||||
|
void* dst, size_t dstCapacity,
|
||||||
|
const ZSTD_Sequence* inSeqs, size_t inSeqsSize,
|
||||||
|
const void* literals, size_t litSize, size_t litCapacity,
|
||||||
|
size_t decompressedSize);
|
||||||
|
typedef char ZSTD_rust_sequence_api_state_layout[
|
||||||
|
(offsetof(ZSTD_rust_sequenceApiState, callbackContext) == 0
|
||||||
|
&& offsetof(ZSTD_rust_sequenceApiState, sequenceState)
|
||||||
|
== sizeof(void*)
|
||||||
|
&& offsetof(ZSTD_rust_sequenceApiState, sequenceLiteralsState)
|
||||||
|
== 2 * sizeof(void*)
|
||||||
|
&& offsetof(ZSTD_rust_sequenceApiState, init)
|
||||||
|
== 3 * sizeof(void*)
|
||||||
|
&& offsetof(ZSTD_rust_sequenceApiState, writeFrameHeader)
|
||||||
|
== 4 * sizeof(void*)
|
||||||
|
&& offsetof(ZSTD_rust_sequenceApiState, updateChecksum)
|
||||||
|
== 5 * sizeof(void*)
|
||||||
|
&& offsetof(ZSTD_rust_sequenceApiState, digestChecksum)
|
||||||
|
== 6 * sizeof(void*)
|
||||||
|
&& offsetof(ZSTD_rust_sequenceApiState, writeChecksum)
|
||||||
|
== 7 * sizeof(void*)
|
||||||
|
&& offsetof(ZSTD_rust_sequenceApiState, checksumFlag)
|
||||||
|
== 8 * sizeof(void*)
|
||||||
|
&& offsetof(ZSTD_rust_sequenceApiState, blockDelimiters)
|
||||||
|
== 8 * sizeof(void*) + sizeof(int)
|
||||||
|
&& offsetof(ZSTD_rust_sequenceApiState, validateSequences)
|
||||||
|
== 8 * sizeof(void*) + 2 * sizeof(int)
|
||||||
|
&& sizeof(ZSTD_rust_sequenceApiState)
|
||||||
|
== (sizeof(void*) == 8 ? 80 : 44))
|
||||||
|
? 1 : -1];
|
||||||
|
|
||||||
typedef char ZSTD_rust_stats_seqdef_layout[(sizeof(SeqDef) == 8) ? 1 : -1];
|
typedef char ZSTD_rust_stats_seqdef_layout[(sizeof(SeqDef) == 8) ? 1 : -1];
|
||||||
typedef char ZSTD_rust_stats_block_summary_layout[
|
typedef char ZSTD_rust_stats_block_summary_layout[
|
||||||
(sizeof(BlockSummary) == 3 * sizeof(size_t)) ? 1 : -1];
|
(sizeof(BlockSummary) == 3 * sizeof(size_t)) ? 1 : -1];
|
||||||
@@ -5387,100 +5453,6 @@ ZSTD_transferSequences_wBlockDelim(ZSTD_CCtx* cctx,
|
|||||||
ZSTD_hasExtSeqProd(&cctx->appliedParams));
|
ZSTD_hasExtSeqProd(&cctx->appliedParams));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Compress all provided sequences, block-by-block.
|
|
||||||
*
|
|
||||||
* Returns the cumulative size of all compressed blocks (including their headers),
|
|
||||||
* otherwise a ZSTD error.
|
|
||||||
*/
|
|
||||||
static size_t
|
|
||||||
ZSTD_compressSequences_internal(ZSTD_CCtx* cctx,
|
|
||||||
void* dst, size_t dstCapacity,
|
|
||||||
const ZSTD_Sequence* inSeqs, size_t inSeqsSize,
|
|
||||||
const void* src, size_t srcSize)
|
|
||||||
{
|
|
||||||
U32 dictSize;
|
|
||||||
ZSTD_rust_sequenceCompressionState state;
|
|
||||||
|
|
||||||
if (cctx->cdict) {
|
|
||||||
dictSize = (U32)cctx->cdict->dictContentSize;
|
|
||||||
} else if (cctx->prefixDict.dict) {
|
|
||||||
dictSize = (U32)cctx->prefixDict.dictSize;
|
|
||||||
} else {
|
|
||||||
dictSize = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
state.seqStore = &cctx->seqStore;
|
|
||||||
state.prevCBlock = &cctx->blockState.prevCBlock;
|
|
||||||
state.nextCBlock = &cctx->blockState.nextCBlock;
|
|
||||||
state.tmpWorkspace = cctx->tmpWorkspace;
|
|
||||||
state.tmpWkspSize = cctx->tmpWkspSize;
|
|
||||||
state.blockSizeMax = cctx->blockSizeMax;
|
|
||||||
state.bmi2 = cctx->bmi2;
|
|
||||||
state.blockDelimiters = (int)cctx->appliedParams.blockDelimiters;
|
|
||||||
state.strategy = (int)cctx->appliedParams.cParams.strategy;
|
|
||||||
state.disableLiteralCompression = ZSTD_literalsCompressionIsDisabled(&cctx->appliedParams);
|
|
||||||
state.searchForExternalRepcodes = (int)cctx->appliedParams.searchForExternalRepcodes;
|
|
||||||
state.validateSequences = cctx->appliedParams.validateSequences;
|
|
||||||
state.minMatch = cctx->appliedParams.cParams.minMatch;
|
|
||||||
state.windowLog = cctx->appliedParams.cParams.windowLog;
|
|
||||||
state.dictSize = dictSize;
|
|
||||||
state.useSequenceProducer = ZSTD_hasExtSeqProd(&cctx->appliedParams);
|
|
||||||
state.isFirstBlock = &cctx->isFirstBlock;
|
|
||||||
|
|
||||||
DEBUGLOG(4, "ZSTD_compressSequences_internal srcSize: %zu, inSeqsSize: %zu", srcSize, inSeqsSize);
|
|
||||||
return ZSTD_rust_compressSequencesInternal(&state, dst, dstCapacity,
|
|
||||||
inSeqs, inSeqsSize, src, srcSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t ZSTD_compressSequences(ZSTD_CCtx* cctx,
|
|
||||||
void* dst, size_t dstCapacity,
|
|
||||||
const ZSTD_Sequence* inSeqs, size_t inSeqsSize,
|
|
||||||
const void* src, size_t srcSize)
|
|
||||||
{
|
|
||||||
BYTE* op = (BYTE*)dst;
|
|
||||||
size_t cSize = 0;
|
|
||||||
|
|
||||||
/* Transparent initialization stage, same as compressStream2() */
|
|
||||||
DEBUGLOG(4, "ZSTD_compressSequences (nbSeqs=%zu,dstCapacity=%zu)", inSeqsSize, dstCapacity);
|
|
||||||
assert(cctx != NULL);
|
|
||||||
FORWARD_IF_ERROR(ZSTD_CCtx_init_compressStream2(cctx, ZSTD_e_end, srcSize), "CCtx initialization failed");
|
|
||||||
|
|
||||||
/* Begin writing output, starting with frame header */
|
|
||||||
{ size_t const frameHeaderSize = ZSTD_writeFrameHeader(op, dstCapacity,
|
|
||||||
&cctx->appliedParams, srcSize, cctx->dictID);
|
|
||||||
op += frameHeaderSize;
|
|
||||||
assert(frameHeaderSize <= dstCapacity);
|
|
||||||
dstCapacity -= frameHeaderSize;
|
|
||||||
cSize += frameHeaderSize;
|
|
||||||
}
|
|
||||||
if (cctx->appliedParams.fParams.checksumFlag && srcSize) {
|
|
||||||
XXH64_update(&cctx->xxhState, src, srcSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Now generate compressed blocks */
|
|
||||||
{ size_t const cBlocksSize = ZSTD_compressSequences_internal(cctx,
|
|
||||||
op, dstCapacity,
|
|
||||||
inSeqs, inSeqsSize,
|
|
||||||
src, srcSize);
|
|
||||||
FORWARD_IF_ERROR(cBlocksSize, "Compressing blocks failed!");
|
|
||||||
cSize += cBlocksSize;
|
|
||||||
assert(cBlocksSize <= dstCapacity);
|
|
||||||
dstCapacity -= cBlocksSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Complete with frame checksum, if needed */
|
|
||||||
if (cctx->appliedParams.fParams.checksumFlag) {
|
|
||||||
U32 const checksum = (U32) XXH64_digest(&cctx->xxhState);
|
|
||||||
RETURN_ERROR_IF(dstCapacity<4, dstSize_tooSmall, "no room for checksum");
|
|
||||||
DEBUGLOG(4, "Write checksum : %08X", (unsigned)checksum);
|
|
||||||
MEM_writeLE32((char*)dst + cSize, checksum);
|
|
||||||
cSize += 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUGLOG(4, "Final compressed size: %zu", cSize);
|
|
||||||
return cSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The public symbol remains C-facing for fullbench and the sequence API, but
|
/* The public symbol remains C-facing for fullbench and the sequence API, but
|
||||||
* the sequence-store conversion itself is Rust-owned. */
|
* the sequence-store conversion itself is Rust-owned. */
|
||||||
size_t ZSTD_convertBlockSequences(ZSTD_CCtx* cctx,
|
size_t ZSTD_convertBlockSequences(ZSTD_CCtx* cctx,
|
||||||
@@ -5505,41 +5477,151 @@ static size_t ZSTD_convertBlockSequencesForRust(
|
|||||||
repcodeResolution);
|
repcodeResolution);
|
||||||
}
|
}
|
||||||
|
|
||||||
BlockSummary ZSTD_get1BlockSummary(const ZSTD_Sequence* seqs, size_t nbSeqs)
|
static void ZSTD_rust_sequenceApi_prepareStates(
|
||||||
|
ZSTD_CCtx* cctx,
|
||||||
|
ZSTD_rust_sequenceCompressionState* sequenceState,
|
||||||
|
ZSTD_rust_sequenceLiteralsState* sequenceLiteralsState)
|
||||||
{
|
{
|
||||||
return ZSTD_rust_get1BlockSummary(seqs, nbSeqs);
|
U32 dictSize;
|
||||||
}
|
|
||||||
|
|
||||||
|
if (cctx->cdict) {
|
||||||
|
dictSize = (U32)cctx->cdict->dictContentSize;
|
||||||
|
} else if (cctx->prefixDict.dict) {
|
||||||
|
dictSize = (U32)cctx->prefixDict.dictSize;
|
||||||
|
} else {
|
||||||
|
dictSize = 0;
|
||||||
|
}
|
||||||
|
|
||||||
static size_t
|
sequenceState->seqStore = &cctx->seqStore;
|
||||||
ZSTD_compressSequencesAndLiterals_internal(ZSTD_CCtx* cctx,
|
sequenceState->prevCBlock = &cctx->blockState.prevCBlock;
|
||||||
void* dst, size_t dstCapacity,
|
sequenceState->nextCBlock = &cctx->blockState.nextCBlock;
|
||||||
const ZSTD_Sequence* inSeqs, size_t nbSequences,
|
sequenceState->tmpWorkspace = cctx->tmpWorkspace;
|
||||||
const void* literals, size_t litSize, size_t srcSize)
|
sequenceState->tmpWkspSize = cctx->tmpWkspSize;
|
||||||
{
|
sequenceState->blockSizeMax = cctx->blockSizeMax;
|
||||||
ZSTD_rust_sequenceLiteralsState state;
|
sequenceState->bmi2 = cctx->bmi2;
|
||||||
int const repcodeResolution =
|
sequenceState->blockDelimiters = (int)cctx->appliedParams.blockDelimiters;
|
||||||
(cctx->appliedParams.searchForExternalRepcodes == ZSTD_ps_enable);
|
sequenceState->strategy = (int)cctx->appliedParams.cParams.strategy;
|
||||||
|
sequenceState->disableLiteralCompression =
|
||||||
|
ZSTD_literalsCompressionIsDisabled(&cctx->appliedParams);
|
||||||
|
sequenceState->searchForExternalRepcodes =
|
||||||
|
(int)cctx->appliedParams.searchForExternalRepcodes;
|
||||||
|
sequenceState->validateSequences = cctx->appliedParams.validateSequences;
|
||||||
|
sequenceState->minMatch = cctx->appliedParams.cParams.minMatch;
|
||||||
|
sequenceState->windowLog = cctx->appliedParams.cParams.windowLog;
|
||||||
|
sequenceState->dictSize = dictSize;
|
||||||
|
sequenceState->useSequenceProducer = ZSTD_hasExtSeqProd(&cctx->appliedParams);
|
||||||
|
sequenceState->isFirstBlock = &cctx->isFirstBlock;
|
||||||
|
|
||||||
assert(cctx->appliedParams.searchForExternalRepcodes != ZSTD_ps_auto);
|
assert(cctx->appliedParams.searchForExternalRepcodes != ZSTD_ps_auto);
|
||||||
state.seqStore = &cctx->seqStore;
|
sequenceLiteralsState->seqStore = &cctx->seqStore;
|
||||||
state.prevCBlock = &cctx->blockState.prevCBlock;
|
sequenceLiteralsState->prevCBlock = &cctx->blockState.prevCBlock;
|
||||||
state.nextCBlock = &cctx->blockState.nextCBlock;
|
sequenceLiteralsState->nextCBlock = &cctx->blockState.nextCBlock;
|
||||||
state.tmpWorkspace = cctx->tmpWorkspace;
|
sequenceLiteralsState->tmpWorkspace = cctx->tmpWorkspace;
|
||||||
state.tmpWkspSize = cctx->tmpWkspSize;
|
sequenceLiteralsState->tmpWkspSize = cctx->tmpWkspSize;
|
||||||
state.blockSizeMax = cctx->blockSizeMax;
|
sequenceLiteralsState->blockSizeMax = cctx->blockSizeMax;
|
||||||
state.bmi2 = cctx->bmi2;
|
sequenceLiteralsState->bmi2 = cctx->bmi2;
|
||||||
state.strategy = (int)cctx->appliedParams.cParams.strategy;
|
sequenceLiteralsState->strategy = (int)cctx->appliedParams.cParams.strategy;
|
||||||
state.disableLiteralCompression =
|
sequenceLiteralsState->disableLiteralCompression =
|
||||||
ZSTD_literalsCompressionIsDisabled(&cctx->appliedParams);
|
ZSTD_literalsCompressionIsDisabled(&cctx->appliedParams);
|
||||||
state.repcodeResolution = repcodeResolution;
|
sequenceLiteralsState->repcodeResolution =
|
||||||
state.isFirstBlock = &cctx->isFirstBlock;
|
(cctx->appliedParams.searchForExternalRepcodes == ZSTD_ps_enable);
|
||||||
state.callbackContext = cctx;
|
sequenceLiteralsState->isFirstBlock = &cctx->isFirstBlock;
|
||||||
state.convertBlockSequences = ZSTD_convertBlockSequencesForRust;
|
sequenceLiteralsState->callbackContext = cctx;
|
||||||
|
sequenceLiteralsState->convertBlockSequences =
|
||||||
|
ZSTD_convertBlockSequencesForRust;
|
||||||
|
}
|
||||||
|
|
||||||
return ZSTD_rust_compressSequencesAndLiteralsInternal(
|
static size_t ZSTD_rust_sequenceApi_init(
|
||||||
&state, dst, dstCapacity, inSeqs, nbSequences, literals, litSize,
|
void* context, size_t pledgedSrcSize,
|
||||||
srcSize);
|
ZSTD_rust_sequenceApiState* state)
|
||||||
|
{
|
||||||
|
ZSTD_CCtx* const cctx = (ZSTD_CCtx*)context;
|
||||||
|
size_t initResult;
|
||||||
|
|
||||||
|
if (cctx == NULL || state == NULL
|
||||||
|
|| state->sequenceState == NULL
|
||||||
|
|| state->sequenceLiteralsState == NULL) {
|
||||||
|
return ERROR(GENERIC);
|
||||||
|
}
|
||||||
|
|
||||||
|
initResult = ZSTD_CCtx_init_compressStream2(
|
||||||
|
cctx, ZSTD_e_end, pledgedSrcSize);
|
||||||
|
if (ERR_isError(initResult)) {
|
||||||
|
return initResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZSTD_rust_sequenceApi_prepareStates(
|
||||||
|
cctx, state->sequenceState, state->sequenceLiteralsState);
|
||||||
|
state->checksumFlag = cctx->appliedParams.fParams.checksumFlag;
|
||||||
|
state->blockDelimiters = (int)cctx->appliedParams.blockDelimiters;
|
||||||
|
state->validateSequences = cctx->appliedParams.validateSequences;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t ZSTD_rust_sequenceApi_writeFrameHeader(
|
||||||
|
void* context, void* dst, size_t dstCapacity, size_t pledgedSrcSize)
|
||||||
|
{
|
||||||
|
ZSTD_CCtx const* const cctx = (ZSTD_CCtx const*)context;
|
||||||
|
return ZSTD_writeFrameHeader(dst, dstCapacity, &cctx->appliedParams,
|
||||||
|
pledgedSrcSize, cctx->dictID);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ZSTD_rust_sequenceApi_updateChecksum(
|
||||||
|
void* context, const void* src, size_t srcSize)
|
||||||
|
{
|
||||||
|
ZSTD_CCtx* const cctx = (ZSTD_CCtx*)context;
|
||||||
|
(void)XXH64_update(&cctx->xxhState, src, srcSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
static U32 ZSTD_rust_sequenceApi_digestChecksum(void* context)
|
||||||
|
{
|
||||||
|
ZSTD_CCtx const* const cctx = (ZSTD_CCtx const*)context;
|
||||||
|
return (U32)XXH64_digest(&cctx->xxhState);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ZSTD_rust_sequenceApi_writeChecksum(
|
||||||
|
void* context, void* dst, U32 checksum)
|
||||||
|
{
|
||||||
|
(void)context;
|
||||||
|
DEBUGLOG(4, "Write checksum : %08X", (unsigned)checksum);
|
||||||
|
MEM_writeLE32((char*)dst, checksum);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ZSTD_rust_sequenceApi_initState(
|
||||||
|
ZSTD_rust_sequenceApiState* state,
|
||||||
|
ZSTD_CCtx* cctx,
|
||||||
|
ZSTD_rust_sequenceCompressionState* sequenceState,
|
||||||
|
ZSTD_rust_sequenceLiteralsState* sequenceLiteralsState)
|
||||||
|
{
|
||||||
|
state->callbackContext = cctx;
|
||||||
|
state->sequenceState = sequenceState;
|
||||||
|
state->sequenceLiteralsState = sequenceLiteralsState;
|
||||||
|
state->init = ZSTD_rust_sequenceApi_init;
|
||||||
|
state->writeFrameHeader = ZSTD_rust_sequenceApi_writeFrameHeader;
|
||||||
|
state->updateChecksum = ZSTD_rust_sequenceApi_updateChecksum;
|
||||||
|
state->digestChecksum = ZSTD_rust_sequenceApi_digestChecksum;
|
||||||
|
state->writeChecksum = ZSTD_rust_sequenceApi_writeChecksum;
|
||||||
|
state->checksumFlag = 0;
|
||||||
|
state->blockDelimiters = 0;
|
||||||
|
state->validateSequences = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ZSTD_compressSequences(ZSTD_CCtx* cctx,
|
||||||
|
void* dst, size_t dstCapacity,
|
||||||
|
const ZSTD_Sequence* inSeqs, size_t inSeqsSize,
|
||||||
|
const void* src, size_t srcSize)
|
||||||
|
{
|
||||||
|
ZSTD_rust_sequenceCompressionState sequenceState;
|
||||||
|
ZSTD_rust_sequenceLiteralsState sequenceLiteralsState;
|
||||||
|
ZSTD_rust_sequenceApiState state;
|
||||||
|
|
||||||
|
DEBUGLOG(4, "ZSTD_compressSequences (nbSeqs=%zu,dstCapacity=%zu)",
|
||||||
|
inSeqsSize, dstCapacity);
|
||||||
|
assert(cctx != NULL);
|
||||||
|
ZSTD_rust_sequenceApi_initState(
|
||||||
|
&state, cctx, &sequenceState, &sequenceLiteralsState);
|
||||||
|
return ZSTD_rust_compressSequences(
|
||||||
|
&state, dst, dstCapacity, inSeqs, inSeqsSize, src, srcSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
@@ -5549,49 +5631,23 @@ ZSTD_compressSequencesAndLiterals(ZSTD_CCtx* cctx,
|
|||||||
const void* literals, size_t litSize, size_t litCapacity,
|
const void* literals, size_t litSize, size_t litCapacity,
|
||||||
size_t decompressedSize)
|
size_t decompressedSize)
|
||||||
{
|
{
|
||||||
BYTE* op = (BYTE*)dst;
|
ZSTD_rust_sequenceCompressionState sequenceState;
|
||||||
size_t cSize = 0;
|
ZSTD_rust_sequenceLiteralsState sequenceLiteralsState;
|
||||||
|
ZSTD_rust_sequenceApiState state;
|
||||||
|
|
||||||
/* Transparent initialization stage, same as compressStream2() */
|
DEBUGLOG(4, "ZSTD_compressSequencesAndLiterals (dstCapacity=%zu)",
|
||||||
DEBUGLOG(4, "ZSTD_compressSequencesAndLiterals (dstCapacity=%zu)", dstCapacity);
|
dstCapacity);
|
||||||
assert(cctx != NULL);
|
assert(cctx != NULL);
|
||||||
if (litCapacity < litSize) {
|
ZSTD_rust_sequenceApi_initState(
|
||||||
RETURN_ERROR(workSpace_tooSmall, "literals buffer is not large enough: must be at least 8 bytes larger than litSize (risk of read out-of-bound)");
|
&state, cctx, &sequenceState, &sequenceLiteralsState);
|
||||||
}
|
return ZSTD_rust_compressSequencesAndLiterals(
|
||||||
FORWARD_IF_ERROR(ZSTD_CCtx_init_compressStream2(cctx, ZSTD_e_end, decompressedSize), "CCtx initialization failed");
|
&state, dst, dstCapacity, inSeqs, inSeqsSize, literals, litSize,
|
||||||
|
litCapacity, decompressedSize);
|
||||||
|
}
|
||||||
|
|
||||||
if (cctx->appliedParams.blockDelimiters == ZSTD_sf_noBlockDelimiters) {
|
BlockSummary ZSTD_get1BlockSummary(const ZSTD_Sequence* seqs, size_t nbSeqs)
|
||||||
RETURN_ERROR(frameParameter_unsupported, "This mode is only compatible with explicit delimiters");
|
{
|
||||||
}
|
return ZSTD_rust_get1BlockSummary(seqs, nbSeqs);
|
||||||
if (cctx->appliedParams.validateSequences) {
|
|
||||||
RETURN_ERROR(parameter_unsupported, "This mode is not compatible with Sequence validation");
|
|
||||||
}
|
|
||||||
if (cctx->appliedParams.fParams.checksumFlag) {
|
|
||||||
RETURN_ERROR(frameParameter_unsupported, "this mode is not compatible with frame checksum");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Begin writing output, starting with frame header */
|
|
||||||
{ size_t const frameHeaderSize = ZSTD_writeFrameHeader(op, dstCapacity,
|
|
||||||
&cctx->appliedParams, decompressedSize, cctx->dictID);
|
|
||||||
op += frameHeaderSize;
|
|
||||||
assert(frameHeaderSize <= dstCapacity);
|
|
||||||
dstCapacity -= frameHeaderSize;
|
|
||||||
cSize += frameHeaderSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Now generate compressed blocks */
|
|
||||||
{ size_t const cBlocksSize = ZSTD_compressSequencesAndLiterals_internal(cctx,
|
|
||||||
op, dstCapacity,
|
|
||||||
inSeqs, inSeqsSize,
|
|
||||||
literals, litSize, decompressedSize);
|
|
||||||
FORWARD_IF_ERROR(cBlocksSize, "Compressing blocks failed!");
|
|
||||||
cSize += cBlocksSize;
|
|
||||||
assert(cBlocksSize <= dstCapacity);
|
|
||||||
dstCapacity -= cBlocksSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUGLOG(4, "Final compressed size: %zu", cSize);
|
|
||||||
return cSize;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*====== Finalize ======*/
|
/*====== Finalize ======*/
|
||||||
|
|||||||
+408
-7
@@ -1443,6 +1443,107 @@ const _: () = {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type SequenceApiInitFn =
|
||||||
|
unsafe extern "C" fn(*mut c_void, usize, *mut ZSTD_rust_sequenceApiState) -> usize;
|
||||||
|
type SequenceApiWriteFrameHeaderFn =
|
||||||
|
unsafe extern "C" fn(*mut c_void, *mut c_void, usize, usize) -> usize;
|
||||||
|
type SequenceApiUpdateChecksumFn = unsafe extern "C" fn(*mut c_void, *const c_void, usize);
|
||||||
|
type SequenceApiDigestChecksumFn = unsafe extern "C" fn(*mut c_void) -> c_uint;
|
||||||
|
type SequenceApiWriteChecksumFn = unsafe extern "C" fn(*mut c_void, *mut c_void, c_uint);
|
||||||
|
|
||||||
|
/// Explicit projection for the public sequence-compression API orchestration.
|
||||||
|
///
|
||||||
|
/// Rust owns validation ordering, frame-header/checksum sequencing, and
|
||||||
|
/// output accounting. C retains the private CCtx, sequence-store, block,
|
||||||
|
/// and checksum layouts through the two block-state projections and callbacks.
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct ZSTD_rust_sequenceApiState {
|
||||||
|
callback_context: *mut c_void,
|
||||||
|
sequence_state: *mut ZSTD_rust_sequenceCompressionState,
|
||||||
|
sequence_literals_state: *mut ZSTD_rust_sequenceLiteralsState,
|
||||||
|
init: SequenceApiInitFn,
|
||||||
|
write_frame_header: SequenceApiWriteFrameHeaderFn,
|
||||||
|
update_checksum: SequenceApiUpdateChecksumFn,
|
||||||
|
digest_checksum: SequenceApiDigestChecksumFn,
|
||||||
|
write_checksum: SequenceApiWriteChecksumFn,
|
||||||
|
checksum_flag: c_int,
|
||||||
|
block_delimiters: c_int,
|
||||||
|
validate_sequences: c_int,
|
||||||
|
}
|
||||||
|
|
||||||
|
const _: () = {
|
||||||
|
assert!(offset_of!(ZSTD_rust_sequenceApiState, callback_context) == 0);
|
||||||
|
assert!(offset_of!(ZSTD_rust_sequenceApiState, sequence_state) == size_of::<usize>());
|
||||||
|
assert!(
|
||||||
|
offset_of!(ZSTD_rust_sequenceApiState, sequence_literals_state) == 2 * size_of::<usize>()
|
||||||
|
);
|
||||||
|
assert!(offset_of!(ZSTD_rust_sequenceApiState, init) == 3 * size_of::<usize>());
|
||||||
|
assert!(offset_of!(ZSTD_rust_sequenceApiState, write_frame_header) == 4 * size_of::<usize>());
|
||||||
|
assert!(offset_of!(ZSTD_rust_sequenceApiState, update_checksum) == 5 * size_of::<usize>());
|
||||||
|
assert!(offset_of!(ZSTD_rust_sequenceApiState, digest_checksum) == 6 * size_of::<usize>());
|
||||||
|
assert!(offset_of!(ZSTD_rust_sequenceApiState, write_checksum) == 7 * size_of::<usize>());
|
||||||
|
assert!(offset_of!(ZSTD_rust_sequenceApiState, checksum_flag) == size_of::<[usize; 8]>());
|
||||||
|
assert!(
|
||||||
|
offset_of!(ZSTD_rust_sequenceApiState, block_delimiters)
|
||||||
|
== size_of::<[usize; 8]>() + size_of::<c_int>()
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
offset_of!(ZSTD_rust_sequenceApiState, validate_sequences)
|
||||||
|
== size_of::<[usize; 8]>() + 2 * size_of::<c_int>()
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
size_of::<ZSTD_rust_sequenceApiState>() == if size_of::<usize>() == 8 { 80 } else { 44 }
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
|
struct SequenceApiPlan {
|
||||||
|
update_input_checksum: bool,
|
||||||
|
append_frame_checksum: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Apply the public sequence API's post-initialization validation policy.
|
||||||
|
///
|
||||||
|
/// The order is intentional and matches the C entry point: the literals
|
||||||
|
/// variant rejects no-delimiter mode first, then sequence validation, then a
|
||||||
|
/// frame checksum. The ordinary variant permits all three independently.
|
||||||
|
fn sequence_api_plan(
|
||||||
|
with_literals: bool,
|
||||||
|
block_delimiters: c_int,
|
||||||
|
validate_sequences: c_int,
|
||||||
|
checksum_flag: c_int,
|
||||||
|
) -> Result<SequenceApiPlan, usize> {
|
||||||
|
if with_literals {
|
||||||
|
if block_delimiters == ZSTD_SF_NO_BLOCK_DELIMITERS {
|
||||||
|
return Err(ERROR(ZstdErrorCode::FrameParameterUnsupported));
|
||||||
|
}
|
||||||
|
if validate_sequences != 0 {
|
||||||
|
return Err(ERROR(ZstdErrorCode::ParameterUnsupported));
|
||||||
|
}
|
||||||
|
if checksum_flag != 0 {
|
||||||
|
return Err(ERROR(ZstdErrorCode::FrameParameterUnsupported));
|
||||||
|
}
|
||||||
|
return Ok(SequenceApiPlan {
|
||||||
|
update_input_checksum: false,
|
||||||
|
append_frame_checksum: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(SequenceApiPlan {
|
||||||
|
update_input_checksum: checksum_flag != 0,
|
||||||
|
append_frame_checksum: checksum_flag != 0,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn sequence_api_validate_literal_capacity(lit_size: usize, lit_capacity: usize) -> usize {
|
||||||
|
if lit_capacity < lit_size {
|
||||||
|
ERROR(ZstdErrorCode::WorkSpaceTooSmall)
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Explicit projection of the state used by `ZSTD_compressSeqStore_singleBlock`.
|
/// Explicit projection of the state used by `ZSTD_compressSeqStore_singleBlock`.
|
||||||
///
|
///
|
||||||
/// Sequence-store construction and split discovery remain in C. Only the
|
/// Sequence-store construction and split discovery remain in C. Only the
|
||||||
@@ -3685,10 +3786,10 @@ unsafe fn write_empty_sequence_block(dst: *mut u8, dst_capacity: usize) -> usize
|
|||||||
/// Rust implementation of the per-block loop from
|
/// Rust implementation of the per-block loop from
|
||||||
/// `ZSTD_compressSequences_internal()`.
|
/// `ZSTD_compressSequences_internal()`.
|
||||||
///
|
///
|
||||||
/// Context initialization, frame-header/checksum handling, and public API
|
/// Public initialization, frame-header/checksum ordering, and validation are
|
||||||
/// validation remain in C. The projected state keeps the ABI explicit while
|
/// driven by the Rust API orchestrator below. The projected state keeps the
|
||||||
/// allowing the loop to reuse the existing Rust sequence-transfer, entropy,
|
/// ABI explicit while allowing this loop to reuse the existing Rust
|
||||||
/// and block-serialization leaves.
|
/// sequence-transfer, entropy, and block-serialization leaves.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn ZSTD_rust_compressSequencesInternal(
|
pub unsafe extern "C" fn ZSTD_rust_compressSequencesInternal(
|
||||||
state: *const ZSTD_rust_sequenceCompressionState,
|
state: *const ZSTD_rust_sequenceCompressionState,
|
||||||
@@ -3926,9 +4027,10 @@ unsafe fn write_empty_sequence_literals_block(dst: *mut u8, dst_capacity: usize)
|
|||||||
/// Rust implementation of the block loop from
|
/// Rust implementation of the block loop from
|
||||||
/// ZSTD_compressSequencesAndLiterals_internal.
|
/// ZSTD_compressSequencesAndLiterals_internal.
|
||||||
///
|
///
|
||||||
/// The C wrapper retains public-API initialization and the CCtx-dependent
|
/// The C wrapper retains the private CCtx-dependent state and sequence
|
||||||
/// sequence conversion callback. Rust owns the external literal cursor,
|
/// conversion callback. Rust owns the public validation/ordering layer, the
|
||||||
/// per-block entropy pass, compressed-block framing, and completion checks.
|
/// external literal cursor, per-block entropy pass, compressed-block framing,
|
||||||
|
/// and completion checks.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn ZSTD_rust_compressSequencesAndLiteralsInternal(
|
pub unsafe extern "C" fn ZSTD_rust_compressSequencesAndLiteralsInternal(
|
||||||
state: *const ZSTD_rust_sequenceLiteralsState,
|
state: *const ZSTD_rust_sequenceLiteralsState,
|
||||||
@@ -4086,6 +4188,251 @@ pub unsafe extern "C" fn ZSTD_rust_compressSequencesAndLiteralsInternal(
|
|||||||
c_size
|
c_size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe fn sequence_api_prepare(
|
||||||
|
state: &mut ZSTD_rust_sequenceApiState,
|
||||||
|
pledged_src_size: usize,
|
||||||
|
with_literals: bool,
|
||||||
|
lit_size: usize,
|
||||||
|
lit_capacity: usize,
|
||||||
|
) -> Result<SequenceApiPlan, usize> {
|
||||||
|
if with_literals {
|
||||||
|
let capacity_result = sequence_api_validate_literal_capacity(lit_size, lit_capacity);
|
||||||
|
if ERR_isError(capacity_result) {
|
||||||
|
return Err(capacity_result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if state.callback_context.is_null()
|
||||||
|
|| state.sequence_state.is_null()
|
||||||
|
|| state.sequence_literals_state.is_null()
|
||||||
|
|| state.init as usize == 0
|
||||||
|
|| state.write_frame_header as usize == 0
|
||||||
|
|| state.update_checksum as usize == 0
|
||||||
|
|| state.digest_checksum as usize == 0
|
||||||
|
|| state.write_checksum as usize == 0
|
||||||
|
{
|
||||||
|
return Err(ERROR(ZstdErrorCode::Generic));
|
||||||
|
}
|
||||||
|
|
||||||
|
let init_result = unsafe {
|
||||||
|
(state.init)(
|
||||||
|
state.callback_context,
|
||||||
|
pledged_src_size,
|
||||||
|
state as *mut ZSTD_rust_sequenceApiState,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
if ERR_isError(init_result) {
|
||||||
|
return Err(init_result);
|
||||||
|
}
|
||||||
|
|
||||||
|
sequence_api_plan(
|
||||||
|
with_literals,
|
||||||
|
state.block_delimiters,
|
||||||
|
state.validate_sequences,
|
||||||
|
state.checksum_flag,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn sequence_api_write_frame_header(
|
||||||
|
state: &ZSTD_rust_sequenceApiState,
|
||||||
|
op: &mut *mut u8,
|
||||||
|
dst_capacity: &mut usize,
|
||||||
|
c_size: &mut usize,
|
||||||
|
pledged_src_size: usize,
|
||||||
|
) -> usize {
|
||||||
|
let frame_header_size = unsafe {
|
||||||
|
(state.write_frame_header)(
|
||||||
|
state.callback_context,
|
||||||
|
(*op).cast(),
|
||||||
|
*dst_capacity,
|
||||||
|
pledged_src_size,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
if ERR_isError(frame_header_size) {
|
||||||
|
return frame_header_size;
|
||||||
|
}
|
||||||
|
if frame_header_size > *dst_capacity {
|
||||||
|
return ERROR(ZstdErrorCode::DstSizeTooSmall);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
*op = (*op).add(frame_header_size);
|
||||||
|
}
|
||||||
|
*dst_capacity -= frame_header_size;
|
||||||
|
*c_size = c_size.wrapping_add(frame_header_size);
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn sequence_api_append_frame_checksum(
|
||||||
|
state: &ZSTD_rust_sequenceApiState,
|
||||||
|
plan: SequenceApiPlan,
|
||||||
|
op: *mut u8,
|
||||||
|
dst_capacity: usize,
|
||||||
|
c_size: &mut usize,
|
||||||
|
) -> usize {
|
||||||
|
if !plan.append_frame_checksum {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Keep the original ordering: digest the checksum before checking the
|
||||||
|
* remaining destination capacity. */
|
||||||
|
let checksum = unsafe { (state.digest_checksum)(state.callback_context) };
|
||||||
|
if dst_capacity < 4 {
|
||||||
|
return ERROR(ZstdErrorCode::DstSizeTooSmall);
|
||||||
|
}
|
||||||
|
unsafe {
|
||||||
|
(state.write_checksum)(state.callback_context, op.cast(), checksum);
|
||||||
|
}
|
||||||
|
*c_size = c_size.wrapping_add(4);
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Rust-owned orchestration for `ZSTD_compressSequences`.
|
||||||
|
///
|
||||||
|
/// The C wrapper provides the post-initialization block-state projection and
|
||||||
|
/// callbacks for the private CCtx/header/checksum operations. Rust preserves
|
||||||
|
/// the public ordering: initialize, write the frame header, update the input
|
||||||
|
/// checksum, emit blocks, then append the frame checksum.
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn ZSTD_rust_compressSequences(
|
||||||
|
state: *mut ZSTD_rust_sequenceApiState,
|
||||||
|
dst: *mut c_void,
|
||||||
|
dst_capacity: usize,
|
||||||
|
in_seqs: *const ZSTD_Sequence,
|
||||||
|
in_seqs_size: usize,
|
||||||
|
src: *const c_void,
|
||||||
|
src_size: usize,
|
||||||
|
) -> usize {
|
||||||
|
if state.is_null() {
|
||||||
|
return ERROR(ZstdErrorCode::Generic);
|
||||||
|
}
|
||||||
|
let state = unsafe { &mut *state };
|
||||||
|
let plan = match unsafe { sequence_api_prepare(state, src_size, false, 0, 0) } {
|
||||||
|
Ok(plan) => plan,
|
||||||
|
Err(result) => return result,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut op = dst.cast::<u8>();
|
||||||
|
let mut dst_capacity = dst_capacity;
|
||||||
|
let mut c_size = 0usize;
|
||||||
|
let header_result = unsafe {
|
||||||
|
sequence_api_write_frame_header(state, &mut op, &mut dst_capacity, &mut c_size, src_size)
|
||||||
|
};
|
||||||
|
if ERR_isError(header_result) {
|
||||||
|
return header_result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if plan.update_input_checksum && src_size != 0 {
|
||||||
|
unsafe { (state.update_checksum)(state.callback_context, src, src_size) };
|
||||||
|
}
|
||||||
|
|
||||||
|
let block_size = unsafe {
|
||||||
|
ZSTD_rust_compressSequencesInternal(
|
||||||
|
&*state.sequence_state,
|
||||||
|
op.cast(),
|
||||||
|
dst_capacity,
|
||||||
|
in_seqs,
|
||||||
|
in_seqs_size,
|
||||||
|
src,
|
||||||
|
src_size,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
if ERR_isError(block_size) {
|
||||||
|
return block_size;
|
||||||
|
}
|
||||||
|
if block_size > dst_capacity {
|
||||||
|
return ERROR(ZstdErrorCode::DstSizeTooSmall);
|
||||||
|
}
|
||||||
|
unsafe {
|
||||||
|
op = op.add(block_size);
|
||||||
|
}
|
||||||
|
dst_capacity -= block_size;
|
||||||
|
c_size = c_size.wrapping_add(block_size);
|
||||||
|
|
||||||
|
let checksum_result =
|
||||||
|
unsafe { sequence_api_append_frame_checksum(state, plan, op, dst_capacity, &mut c_size) };
|
||||||
|
if ERR_isError(checksum_result) {
|
||||||
|
return checksum_result;
|
||||||
|
}
|
||||||
|
|
||||||
|
c_size
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Rust-owned orchestration for `ZSTD_compressSequencesAndLiterals`.
|
||||||
|
///
|
||||||
|
/// The literal-capacity check intentionally precedes CCtx initialization, and
|
||||||
|
/// the post-initialization incompatibility checks retain their original
|
||||||
|
/// precedence. The existing Rust block loop remains responsible for literal
|
||||||
|
/// accounting, sequence conversion, and block codec operations.
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn ZSTD_rust_compressSequencesAndLiterals(
|
||||||
|
state: *mut ZSTD_rust_sequenceApiState,
|
||||||
|
dst: *mut c_void,
|
||||||
|
dst_capacity: usize,
|
||||||
|
in_seqs: *const ZSTD_Sequence,
|
||||||
|
in_seqs_size: usize,
|
||||||
|
literals: *const c_void,
|
||||||
|
lit_size: usize,
|
||||||
|
lit_capacity: usize,
|
||||||
|
decompressed_size: usize,
|
||||||
|
) -> usize {
|
||||||
|
if state.is_null() {
|
||||||
|
return ERROR(ZstdErrorCode::Generic);
|
||||||
|
}
|
||||||
|
let state = unsafe { &mut *state };
|
||||||
|
let plan = match unsafe {
|
||||||
|
sequence_api_prepare(state, decompressed_size, true, lit_size, lit_capacity)
|
||||||
|
} {
|
||||||
|
Ok(plan) => plan,
|
||||||
|
Err(result) => return result,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut op = dst.cast::<u8>();
|
||||||
|
let mut dst_capacity = dst_capacity;
|
||||||
|
let mut c_size = 0usize;
|
||||||
|
let header_result = unsafe {
|
||||||
|
sequence_api_write_frame_header(
|
||||||
|
state,
|
||||||
|
&mut op,
|
||||||
|
&mut dst_capacity,
|
||||||
|
&mut c_size,
|
||||||
|
decompressed_size,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
if ERR_isError(header_result) {
|
||||||
|
return header_result;
|
||||||
|
}
|
||||||
|
|
||||||
|
let block_size = unsafe {
|
||||||
|
ZSTD_rust_compressSequencesAndLiteralsInternal(
|
||||||
|
&*state.sequence_literals_state,
|
||||||
|
op.cast(),
|
||||||
|
dst_capacity,
|
||||||
|
in_seqs,
|
||||||
|
in_seqs_size,
|
||||||
|
literals,
|
||||||
|
lit_size,
|
||||||
|
decompressed_size,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
if ERR_isError(block_size) {
|
||||||
|
return block_size;
|
||||||
|
}
|
||||||
|
if block_size > dst_capacity {
|
||||||
|
return ERROR(ZstdErrorCode::DstSizeTooSmall);
|
||||||
|
}
|
||||||
|
dst_capacity -= block_size;
|
||||||
|
c_size = c_size.wrapping_add(block_size);
|
||||||
|
|
||||||
|
let checksum_result =
|
||||||
|
unsafe { sequence_api_append_frame_checksum(state, plan, op, dst_capacity, &mut c_size) };
|
||||||
|
if ERR_isError(checksum_result) {
|
||||||
|
return checksum_result;
|
||||||
|
}
|
||||||
|
|
||||||
|
c_size
|
||||||
|
}
|
||||||
|
|
||||||
unsafe fn compress_frame(
|
unsafe fn compress_frame(
|
||||||
dst: *mut c_void,
|
dst: *mut c_void,
|
||||||
dst_capacity: usize,
|
dst_capacity: usize,
|
||||||
@@ -4546,6 +4893,7 @@ pub unsafe extern "C" fn ZSTD_compressStream2(
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::errors::ERR_getErrorCode;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::process::{Command, Stdio};
|
use std::process::{Command, Stdio};
|
||||||
|
|
||||||
@@ -6992,6 +7340,59 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sequence_api_plan_places_input_and_frame_checksums_around_blocks() {
|
||||||
|
assert_eq!(
|
||||||
|
sequence_api_plan(false, ZSTD_SF_NO_BLOCK_DELIMITERS, 1, 1),
|
||||||
|
Ok(SequenceApiPlan {
|
||||||
|
update_input_checksum: true,
|
||||||
|
append_frame_checksum: true,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sequence_api_plan_disables_checksums_for_literals_variant() {
|
||||||
|
assert_eq!(
|
||||||
|
sequence_api_plan(true, ZSTD_SF_EXPLICIT_BLOCK_DELIMITERS, 0, 0),
|
||||||
|
Ok(SequenceApiPlan {
|
||||||
|
update_input_checksum: false,
|
||||||
|
append_frame_checksum: false,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sequence_api_plan_preserves_literals_validation_precedence() {
|
||||||
|
assert_eq!(
|
||||||
|
ERR_getErrorCode(
|
||||||
|
sequence_api_plan(true, ZSTD_SF_NO_BLOCK_DELIMITERS, 1, 1).unwrap_err()
|
||||||
|
),
|
||||||
|
ZstdErrorCode::FrameParameterUnsupported as i32
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
ERR_getErrorCode(
|
||||||
|
sequence_api_plan(true, ZSTD_SF_EXPLICIT_BLOCK_DELIMITERS, 1, 1).unwrap_err()
|
||||||
|
),
|
||||||
|
ZstdErrorCode::ParameterUnsupported as i32
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
ERR_getErrorCode(
|
||||||
|
sequence_api_plan(true, ZSTD_SF_EXPLICIT_BLOCK_DELIMITERS, 0, 1).unwrap_err()
|
||||||
|
),
|
||||||
|
ZstdErrorCode::FrameParameterUnsupported as i32
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sequence_api_literal_capacity_check_precedes_initialization() {
|
||||||
|
assert_eq!(
|
||||||
|
sequence_api_validate_literal_capacity(9, 8),
|
||||||
|
ERROR(ZstdErrorCode::WorkSpaceTooSmall)
|
||||||
|
);
|
||||||
|
assert_eq!(sequence_api_validate_literal_capacity(8, 9), 0);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn sequence_copier_selector_returns_no_delimiters_mode() {
|
fn sequence_copier_selector_returns_no_delimiters_mode() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|||||||
Reference in New Issue
Block a user