From db8c58ac97a7f082473160f4deccb73a3a78320b Mon Sep 17 00:00:00 2001 From: ddidderr Date: Sun, 19 Jul 2026 18:16:44 +0200 Subject: [PATCH] feat(compress): move CCtx reset storage policy into Rust Move the post-match-state CCtx storage reservation and publication policy into Rust while keeping the private C workspace and context layouts behind narrow callbacks. The Rust leaf now preserves the sequence, LDM, external-sequence, literal, buffered-input/output, bucket, and entropy-code allocation order, including zeroing and reset callbacks. C remains responsible for workspace resize/layout, private field publication, allocator callbacks, and the LDM window reset details. ABI layout assertions and fake-callback tests cover ordinary, LDM/external-producer, and allocation-failure paths. Test Plan: - ulimit -v 41943040 && CARGO_BUILD_JOBS=1 cargo fmt --manifest-path rust/Cargo.toml - ulimit -v 41943040 && CARGO_BUILD_JOBS=1 cargo test --manifest-path rust/Cargo.toml cctx_storage --lib (3 passed) - ulimit -v 41943040 && CARGO_BUILD_JOBS=1 cargo test --manifest-path rust/Cargo.toml --lib (683 passed) - ulimit -v 41943040 && CARGO_BUILD_JOBS=1 cargo clippy --manifest-path rust/Cargo.toml --all-targets -- -D warnings - ulimit -v 41943040 && make -B -C programs -j1 zstd (passed; existing fileio const-cast warnings) - ulimit -v 41943040 && make -C tests -j1 test-zstream ZSTREAM_TESTTIME=-T1s (84 tests and both short fuzz rounds passed; existing zstreamtest warning) --- lib/compress/zstd_compress.c | 348 ++++++++++++++++--- rust/README.md | 5 +- rust/src/zstd_compress.rs | 634 +++++++++++++++++++++++++++++++++++ 3 files changed, 930 insertions(+), 57 deletions(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 759dd3e52..91580b6c2 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -1274,6 +1274,121 @@ typedef char ZSTD_rust_cctx_reset_plan_layout[ && offsetof(ZSTD_rustCCtxResetPlan, needsIndexReset) == 8 * sizeof(size_t) && sizeof(ZSTD_rustCCtxResetPlan) == 9 * sizeof(size_t)) ? 1 : -1]; +typedef void (*ZSTD_rust_resetCCtxStorageSetPointer_f)( + void* context, int pointerKind, void* pointer); +typedef void (*ZSTD_rust_resetCCtxStorageSetSize_f)( + void* context, int sizeKind, size_t value); +typedef void (*ZSTD_rust_resetCCtxStorageSetInt_f)( + void* context, int intKind, int value); +typedef void* (*ZSTD_rust_resetCCtxStorageReserve_f)( + void* context, int reserveKind, size_t size); +typedef int (*ZSTD_rust_resetCCtxStorageReserveFailed_f)(void* context); +typedef void (*ZSTD_rust_resetCCtxStorageZero_f)( + void* context, void* pointer, size_t size); +typedef void (*ZSTD_rust_resetCCtxStorageCallback_f)(void* context); +typedef struct { + void* callbackContext; + int ldmEnable; + int hasExtSeqProd; + U32 hashLog; + U32 bucketSizeLog; + size_t blockSize; + size_t maxNbSeq; + size_t maxNbLdmSeq; + size_t maxNbExternalSeq; + size_t buffInSize; + size_t buffOutSize; + size_t seqDefSize; + size_t ldmEntrySize; + size_t rawSeqSize; + size_t externalSequenceSize; + size_t byteSize; + size_t wildcopyOverlength; + int bufferedPolicy; + ZSTD_rust_resetCCtxStorageSetPointer_f setPointer; + ZSTD_rust_resetCCtxStorageSetSize_f setSize; + ZSTD_rust_resetCCtxStorageSetInt_f setInt; + ZSTD_rust_resetCCtxStorageReserve_f reserve; + ZSTD_rust_resetCCtxStorageReserveFailed_f reserveFailed; + ZSTD_rust_resetCCtxStorageZero_f zero; + ZSTD_rust_resetCCtxStorageCallback_f windowInit; + ZSTD_rust_resetCCtxStorageCallback_f resetExternalSequences; +} ZSTD_rust_resetCCtxStorageState; +typedef char ZSTD_rust_reset_cctx_storage_state_layout[ + (offsetof(ZSTD_rust_resetCCtxStorageState, callbackContext) == 0 + && offsetof(ZSTD_rust_resetCCtxStorageState, ldmEnable) == sizeof(void*) + && offsetof(ZSTD_rust_resetCCtxStorageState, hasExtSeqProd) + == sizeof(void*) + sizeof(int) + && offsetof(ZSTD_rust_resetCCtxStorageState, hashLog) + > offsetof(ZSTD_rust_resetCCtxStorageState, hasExtSeqProd) + && offsetof(ZSTD_rust_resetCCtxStorageState, bucketSizeLog) + == offsetof(ZSTD_rust_resetCCtxStorageState, hashLog) + sizeof(U32) + && offsetof(ZSTD_rust_resetCCtxStorageState, blockSize) + > offsetof(ZSTD_rust_resetCCtxStorageState, bucketSizeLog) + && offsetof(ZSTD_rust_resetCCtxStorageState, maxNbSeq) + == offsetof(ZSTD_rust_resetCCtxStorageState, blockSize) + sizeof(size_t) + && offsetof(ZSTD_rust_resetCCtxStorageState, maxNbLdmSeq) + == offsetof(ZSTD_rust_resetCCtxStorageState, maxNbSeq) + sizeof(size_t) + && offsetof(ZSTD_rust_resetCCtxStorageState, maxNbExternalSeq) + == offsetof(ZSTD_rust_resetCCtxStorageState, maxNbLdmSeq) + sizeof(size_t) + && offsetof(ZSTD_rust_resetCCtxStorageState, buffInSize) + == offsetof(ZSTD_rust_resetCCtxStorageState, maxNbExternalSeq) + sizeof(size_t) + && offsetof(ZSTD_rust_resetCCtxStorageState, buffOutSize) + == offsetof(ZSTD_rust_resetCCtxStorageState, buffInSize) + sizeof(size_t) + && offsetof(ZSTD_rust_resetCCtxStorageState, seqDefSize) + == offsetof(ZSTD_rust_resetCCtxStorageState, buffOutSize) + sizeof(size_t) + && offsetof(ZSTD_rust_resetCCtxStorageState, ldmEntrySize) + == offsetof(ZSTD_rust_resetCCtxStorageState, seqDefSize) + sizeof(size_t) + && offsetof(ZSTD_rust_resetCCtxStorageState, rawSeqSize) + == offsetof(ZSTD_rust_resetCCtxStorageState, ldmEntrySize) + sizeof(size_t) + && offsetof(ZSTD_rust_resetCCtxStorageState, externalSequenceSize) + == offsetof(ZSTD_rust_resetCCtxStorageState, rawSeqSize) + sizeof(size_t) + && offsetof(ZSTD_rust_resetCCtxStorageState, byteSize) + == offsetof(ZSTD_rust_resetCCtxStorageState, externalSequenceSize) + sizeof(size_t) + && offsetof(ZSTD_rust_resetCCtxStorageState, wildcopyOverlength) + == offsetof(ZSTD_rust_resetCCtxStorageState, byteSize) + sizeof(size_t) + && offsetof(ZSTD_rust_resetCCtxStorageState, bufferedPolicy) + > offsetof(ZSTD_rust_resetCCtxStorageState, wildcopyOverlength) + && offsetof(ZSTD_rust_resetCCtxStorageState, setSize) + == offsetof(ZSTD_rust_resetCCtxStorageState, setPointer) + sizeof(void*) + && offsetof(ZSTD_rust_resetCCtxStorageState, setInt) + == offsetof(ZSTD_rust_resetCCtxStorageState, setSize) + sizeof(void*) + && offsetof(ZSTD_rust_resetCCtxStorageState, reserve) + == offsetof(ZSTD_rust_resetCCtxStorageState, setInt) + sizeof(void*) + && sizeof(ZSTD_rust_resetCCtxStorageState) + == offsetof(ZSTD_rust_resetCCtxStorageState, resetExternalSequences) + + sizeof(void*)) + ? 1 : -1]; +enum { + ZSTD_RUST_RESET_CCTX_RESERVE_ALIGNED64 = 0, + ZSTD_RUST_RESET_CCTX_RESERVE_BUFFER = 1 +}; +enum { + ZSTD_RUST_RESET_CCTX_POINTER_SEQ_START = 0, + ZSTD_RUST_RESET_CCTX_POINTER_LDM_HASH = 1, + ZSTD_RUST_RESET_CCTX_POINTER_LDM_SEQUENCES = 2, + ZSTD_RUST_RESET_CCTX_POINTER_EXTERNAL_SEQUENCES = 3, + ZSTD_RUST_RESET_CCTX_POINTER_LITERALS = 4, + ZSTD_RUST_RESET_CCTX_POINTER_INPUT_BUFFER = 5, + ZSTD_RUST_RESET_CCTX_POINTER_OUTPUT_BUFFER = 6, + ZSTD_RUST_RESET_CCTX_POINTER_LL_CODE = 7, + ZSTD_RUST_RESET_CCTX_POINTER_ML_CODE = 8, + ZSTD_RUST_RESET_CCTX_POINTER_OF_CODE = 9, + ZSTD_RUST_RESET_CCTX_POINTER_LDM_BUCKETS = 10 +}; +enum { + ZSTD_RUST_RESET_CCTX_SIZE_MAX_NB_SEQ = 0, + ZSTD_RUST_RESET_CCTX_SIZE_MAX_NB_LIT = 1, + ZSTD_RUST_RESET_CCTX_SIZE_MAX_NB_LDM_SEQ = 2, + ZSTD_RUST_RESET_CCTX_SIZE_EXTERNAL_SEQ_CAPACITY = 3, + ZSTD_RUST_RESET_CCTX_SIZE_INPUT_BUFFER = 4, + ZSTD_RUST_RESET_CCTX_SIZE_OUTPUT_BUFFER = 5 +}; +enum { + ZSTD_RUST_RESET_CCTX_INT_BUFFERED_POLICY = 0, + ZSTD_RUST_RESET_CCTX_INT_INITIALIZED = 1 +}; +size_t ZSTD_rust_resetCCtxStorage(const ZSTD_rust_resetCCtxStorageState* state); size_t ZSTD_rust_estimateCCtxWorkspaceSize( ZSTD_compressionParameters cParams, int ldmEnable, U32 ldmHashLog, U32 ldmBucketSizeLog, @@ -3650,6 +3765,152 @@ static int ZSTD_dictTooBig(size_t const loadedDictSize) return ZSTD_rust_dictTooBig(loadedDictSize); } +typedef struct { + ZSTD_CCtx* cctx; + ZSTD_cwksp* ws; +} ZSTD_rust_resetCCtxStorageContext; + +static void ZSTD_rust_resetCCtxStorage_setPointer( + void* opaque, int pointerKind, void* pointer) +{ + ZSTD_rust_resetCCtxStorageContext* const context = + (ZSTD_rust_resetCCtxStorageContext*)opaque; + ZSTD_CCtx* const cctx = context->cctx; + switch (pointerKind) { + case ZSTD_RUST_RESET_CCTX_POINTER_SEQ_START: + cctx->seqStore.sequencesStart = (SeqDef*)pointer; + break; + case ZSTD_RUST_RESET_CCTX_POINTER_LDM_HASH: + cctx->ldmState.hashTable = (ldmEntry_t*)pointer; + break; + case ZSTD_RUST_RESET_CCTX_POINTER_LDM_SEQUENCES: + cctx->ldmSequences = (rawSeq*)pointer; + break; + case ZSTD_RUST_RESET_CCTX_POINTER_EXTERNAL_SEQUENCES: + cctx->extSeqBuf = (ZSTD_Sequence*)pointer; + break; + case ZSTD_RUST_RESET_CCTX_POINTER_LITERALS: + cctx->seqStore.litStart = (BYTE*)pointer; + break; + case ZSTD_RUST_RESET_CCTX_POINTER_INPUT_BUFFER: + cctx->inBuff = (char*)pointer; + break; + case ZSTD_RUST_RESET_CCTX_POINTER_OUTPUT_BUFFER: + cctx->outBuff = (char*)pointer; + break; + case ZSTD_RUST_RESET_CCTX_POINTER_LL_CODE: + cctx->seqStore.llCode = (BYTE*)pointer; + break; + case ZSTD_RUST_RESET_CCTX_POINTER_ML_CODE: + cctx->seqStore.mlCode = (BYTE*)pointer; + break; + case ZSTD_RUST_RESET_CCTX_POINTER_OF_CODE: + cctx->seqStore.ofCode = (BYTE*)pointer; + break; + case ZSTD_RUST_RESET_CCTX_POINTER_LDM_BUCKETS: + cctx->ldmState.bucketOffsets = (BYTE*)pointer; + break; + default: + assert(0); + break; + } +} + +static void ZSTD_rust_resetCCtxStorage_setSize( + void* opaque, int sizeKind, size_t value) +{ + ZSTD_rust_resetCCtxStorageContext* const context = + (ZSTD_rust_resetCCtxStorageContext*)opaque; + ZSTD_CCtx* const cctx = context->cctx; + switch (sizeKind) { + case ZSTD_RUST_RESET_CCTX_SIZE_MAX_NB_SEQ: + cctx->seqStore.maxNbSeq = value; + break; + case ZSTD_RUST_RESET_CCTX_SIZE_MAX_NB_LIT: + cctx->seqStore.maxNbLit = value; + break; + case ZSTD_RUST_RESET_CCTX_SIZE_MAX_NB_LDM_SEQ: + cctx->maxNbLdmSequences = value; + break; + case ZSTD_RUST_RESET_CCTX_SIZE_EXTERNAL_SEQ_CAPACITY: + cctx->extSeqBufCapacity = value; + break; + case ZSTD_RUST_RESET_CCTX_SIZE_INPUT_BUFFER: + cctx->inBuffSize = value; + break; + case ZSTD_RUST_RESET_CCTX_SIZE_OUTPUT_BUFFER: + cctx->outBuffSize = value; + break; + default: + assert(0); + break; + } +} + +static void ZSTD_rust_resetCCtxStorage_setInt( + void* opaque, int intKind, int value) +{ + ZSTD_rust_resetCCtxStorageContext* const context = + (ZSTD_rust_resetCCtxStorageContext*)opaque; + ZSTD_CCtx* const cctx = context->cctx; + switch (intKind) { + case ZSTD_RUST_RESET_CCTX_INT_BUFFERED_POLICY: + cctx->bufferedPolicy = (ZSTD_buffered_policy_e)value; + break; + case ZSTD_RUST_RESET_CCTX_INT_INITIALIZED: + cctx->initialized = value; + break; + default: + assert(0); + break; + } +} + +static void* ZSTD_rust_resetCCtxStorage_reserve( + void* opaque, int reserveKind, size_t size) +{ + ZSTD_rust_resetCCtxStorageContext* const context = + (ZSTD_rust_resetCCtxStorageContext*)opaque; + switch (reserveKind) { + case ZSTD_RUST_RESET_CCTX_RESERVE_ALIGNED64: + return ZSTD_cwksp_reserve_aligned64(context->ws, size); + case ZSTD_RUST_RESET_CCTX_RESERVE_BUFFER: + return ZSTD_cwksp_reserve_buffer(context->ws, size); + default: + assert(0); + return NULL; + } +} + +static int ZSTD_rust_resetCCtxStorage_reserveFailed(void* opaque) +{ + ZSTD_rust_resetCCtxStorageContext* const context = + (ZSTD_rust_resetCCtxStorageContext*)opaque; + return ZSTD_cwksp_reserve_failed(context->ws); +} + +static void ZSTD_rust_resetCCtxStorage_zero( + void* opaque, void* pointer, size_t size) +{ + (void)opaque; + ZSTD_memset(pointer, 0, size); +} + +static void ZSTD_rust_resetCCtxStorage_windowInit(void* opaque) +{ + ZSTD_rust_resetCCtxStorageContext* const context = + (ZSTD_rust_resetCCtxStorageContext*)opaque; + ZSTD_window_init(&context->cctx->ldmState.window); + context->cctx->ldmState.loadedDictEnd = 0; +} + +static void ZSTD_rust_resetCCtxStorage_resetExternalSequences(void* opaque) +{ + ZSTD_rust_resetCCtxStorageContext* const context = + (ZSTD_rust_resetCCtxStorageContext*)opaque; + ZSTD_referenceExternalSequences(context->cctx, NULL, 0); +} + /*! ZSTD_resetCCtx_internal() : * @param loadedDictSize The size of the dictionary to be loaded * into the context, if any. If no dictionary is used, or the @@ -3708,6 +3969,8 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, size_t maxNbLdmSeq; size_t neededSpace; ZSTD_indexResetPolicy_e needsIndexReset; + ZSTD_rust_resetCCtxStorageContext storageContext; + ZSTD_rust_resetCCtxStorageState storageState; resetState.cParams = params->cParams; resetState.ldmEnable = (int)params->ldmParams.enableLdm; resetState.ldmHashLog = params->ldmParams.hashLog; @@ -3737,6 +4000,35 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, maxNbLdmSeq = resetPlan.maxNbLdmSeq; neededSpace = resetPlan.neededSpace; needsIndexReset = (ZSTD_indexResetPolicy_e)resetPlan.needsIndexReset; + storageContext.cctx = zc; + storageContext.ws = ws; + storageState.callbackContext = &storageContext; + storageState.ldmEnable = (int)params->ldmParams.enableLdm; + storageState.hasExtSeqProd = ZSTD_hasExtSeqProd(params); + storageState.hashLog = params->ldmParams.hashLog; + storageState.bucketSizeLog = params->ldmParams.bucketSizeLog; + storageState.blockSize = blockSize; + storageState.maxNbSeq = maxNbSeq; + storageState.maxNbLdmSeq = maxNbLdmSeq; + storageState.maxNbExternalSeq = resetPlan.maxNbExternalSeq; + storageState.buffInSize = buffInSize; + storageState.buffOutSize = buffOutSize; + storageState.seqDefSize = sizeof(SeqDef); + storageState.ldmEntrySize = sizeof(ldmEntry_t); + storageState.rawSeqSize = sizeof(rawSeq); + storageState.externalSequenceSize = sizeof(ZSTD_Sequence); + storageState.byteSize = sizeof(BYTE); + storageState.wildcopyOverlength = WILDCOPY_OVERLENGTH; + storageState.bufferedPolicy = (int)zbuff; + storageState.setPointer = ZSTD_rust_resetCCtxStorage_setPointer; + storageState.setSize = ZSTD_rust_resetCCtxStorage_setSize; + storageState.setInt = ZSTD_rust_resetCCtxStorage_setInt; + storageState.reserve = ZSTD_rust_resetCCtxStorage_reserve; + storageState.reserveFailed = ZSTD_rust_resetCCtxStorage_reserveFailed; + storageState.zero = ZSTD_rust_resetCCtxStorage_zero; + storageState.windowInit = ZSTD_rust_resetCCtxStorage_windowInit; + storageState.resetExternalSequences = + ZSTD_rust_resetCCtxStorage_resetExternalSequences; if (!zc->staticSize) ZSTD_cwksp_bump_oversized_duration(ws, 0); @@ -3803,65 +4095,11 @@ static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, needsIndexReset, ZSTD_resetTarget_CCtx), ""); - zc->seqStore.sequencesStart = (SeqDef*)ZSTD_cwksp_reserve_aligned64(ws, maxNbSeq * sizeof(SeqDef)); - - /* ldm hash table */ - if (params->ldmParams.enableLdm == ZSTD_ps_enable) { - /* TODO: avoid memset? */ - size_t const ldmHSize = ((size_t)1) << params->ldmParams.hashLog; - zc->ldmState.hashTable = (ldmEntry_t*)ZSTD_cwksp_reserve_aligned64(ws, ldmHSize * sizeof(ldmEntry_t)); - ZSTD_memset(zc->ldmState.hashTable, 0, ldmHSize * sizeof(ldmEntry_t)); - zc->ldmSequences = (rawSeq*)ZSTD_cwksp_reserve_aligned64(ws, maxNbLdmSeq * sizeof(rawSeq)); - zc->maxNbLdmSequences = maxNbLdmSeq; - - ZSTD_window_init(&zc->ldmState.window); - zc->ldmState.loadedDictEnd = 0; - } - - /* reserve space for block-level external sequences */ - if (ZSTD_hasExtSeqProd(params)) { - size_t const maxNbExternalSeq = resetPlan.maxNbExternalSeq; - zc->extSeqBufCapacity = maxNbExternalSeq; - zc->extSeqBuf = - (ZSTD_Sequence*)ZSTD_cwksp_reserve_aligned64(ws, maxNbExternalSeq * sizeof(ZSTD_Sequence)); - } - - /* buffers */ - - /* ZSTD_wildcopy() is used to copy into the literals buffer, - * so we have to oversize the buffer by WILDCOPY_OVERLENGTH bytes. - */ - zc->seqStore.litStart = ZSTD_cwksp_reserve_buffer(ws, blockSize + WILDCOPY_OVERLENGTH); - zc->seqStore.maxNbLit = blockSize; - - zc->bufferedPolicy = zbuff; - zc->inBuffSize = buffInSize; - zc->inBuff = (char*)ZSTD_cwksp_reserve_buffer(ws, buffInSize); - zc->outBuffSize = buffOutSize; - zc->outBuff = (char*)ZSTD_cwksp_reserve_buffer(ws, buffOutSize); - - /* ldm bucketOffsets table */ - if (params->ldmParams.enableLdm == ZSTD_ps_enable) { - /* TODO: avoid memset? */ - size_t const numBuckets = - ((size_t)1) << (params->ldmParams.hashLog - - params->ldmParams.bucketSizeLog); - zc->ldmState.bucketOffsets = ZSTD_cwksp_reserve_buffer(ws, numBuckets); - ZSTD_memset(zc->ldmState.bucketOffsets, 0, numBuckets); - } - - /* sequences storage */ - ZSTD_referenceExternalSequences(zc, NULL, 0); - zc->seqStore.maxNbSeq = maxNbSeq; - zc->seqStore.llCode = ZSTD_cwksp_reserve_buffer(ws, maxNbSeq * sizeof(BYTE)); - zc->seqStore.mlCode = ZSTD_cwksp_reserve_buffer(ws, maxNbSeq * sizeof(BYTE)); - zc->seqStore.ofCode = ZSTD_cwksp_reserve_buffer(ws, maxNbSeq * sizeof(BYTE)); + FORWARD_IF_ERROR(ZSTD_rust_resetCCtxStorage(&storageState), ""); DEBUGLOG(3, "wksp: finished allocating, %zd bytes remain available", ZSTD_cwksp_available_space(ws)); assert(ZSTD_cwksp_estimated_space_within_bounds(ws, neededSpace)); - zc->initialized = 1; - return 0; } } diff --git a/rust/README.md b/rust/README.md index 46cb01e57..b2e0273ed 100644 --- a/rust/README.md +++ b/rust/README.md @@ -166,8 +166,9 @@ CDict advanced private workspace construction, private static-CCtx and static-CDict workspace construction and dictionary-content allocation/loading, and advanced-CDict dictionary-content loading remain in C. Rust now owns advanced-CDict custom-memory validation, workspace-size query/allocation, -allocation/create/init cleanup ordering, the CCtx workspace-size formula, and -the scalar CCtx-reset plan and match-state reset policy/order; C retains +allocation/create/init cleanup ordering, the CCtx workspace-size formula, the +scalar CCtx-reset plan, post-match-state storage reservation order, and +match-state reset policy/order; C retains private layout-size inputs, workspace resize/layout, private field publication, and allocator callbacks. Private CCtx reset/matchfinder/workspace operations and codec/adaptive-policy diff --git a/rust/src/zstd_compress.rs b/rust/src/zstd_compress.rs index 56c4eb86d..ba3c85ca8 100644 --- a/rust/src/zstd_compress.rs +++ b/rust/src/zstd_compress.rs @@ -6020,6 +6020,363 @@ pub unsafe extern "C" fn ZSTD_rust_planCCtxReset(state: *const ZSTD_rustCCtxRese 0 } +type ResetCCtxStorageSetPointer = unsafe extern "C" fn(*mut c_void, c_int, *mut c_void); +type ResetCCtxStorageSetSize = unsafe extern "C" fn(*mut c_void, c_int, usize); +type ResetCCtxStorageSetInt = unsafe extern "C" fn(*mut c_void, c_int, c_int); +type ResetCCtxStorageReserve = unsafe extern "C" fn(*mut c_void, c_int, usize) -> *mut c_void; +type ResetCCtxStorageReserveFailed = unsafe extern "C" fn(*mut c_void) -> c_int; +type ResetCCtxStorageZero = unsafe extern "C" fn(*mut c_void, *mut c_void, usize); +type ResetCCtxStorageCallback = unsafe extern "C" fn(*mut c_void); + +const RESET_CCTX_RESERVE_ALIGNED64: c_int = 0; +const RESET_CCTX_RESERVE_BUFFER: c_int = 1; + +const RESET_CCTX_POINTER_SEQ_START: c_int = 0; +const RESET_CCTX_POINTER_LDM_HASH: c_int = 1; +const RESET_CCTX_POINTER_LDM_SEQUENCES: c_int = 2; +const RESET_CCTX_POINTER_EXTERNAL_SEQUENCES: c_int = 3; +const RESET_CCTX_POINTER_LITERALS: c_int = 4; +const RESET_CCTX_POINTER_INPUT_BUFFER: c_int = 5; +const RESET_CCTX_POINTER_OUTPUT_BUFFER: c_int = 6; +const RESET_CCTX_POINTER_LL_CODE: c_int = 7; +const RESET_CCTX_POINTER_ML_CODE: c_int = 8; +const RESET_CCTX_POINTER_OF_CODE: c_int = 9; +const RESET_CCTX_POINTER_LDM_BUCKETS: c_int = 10; + +const RESET_CCTX_SIZE_MAX_NB_SEQ: c_int = 0; +const RESET_CCTX_SIZE_MAX_NB_LIT: c_int = 1; +const RESET_CCTX_SIZE_MAX_NB_LDM_SEQ: c_int = 2; +const RESET_CCTX_SIZE_EXTERNAL_SEQ_CAPACITY: c_int = 3; +const RESET_CCTX_SIZE_INPUT_BUFFER: c_int = 4; +const RESET_CCTX_SIZE_OUTPUT_BUFFER: c_int = 5; + +const RESET_CCTX_INT_BUFFERED_POLICY: c_int = 0; +const RESET_CCTX_INT_INITIALIZED: c_int = 1; + +/// C-owned workspace/layout projection for the post-match-state reset tail. +/// +/// Rust owns the reservation order and size policy. C retains the private +/// `ZSTD_CCtx`/`ldmState_t` layouts and implements the workspace callbacks. +#[repr(C)] +pub struct ZSTD_rust_resetCCtxStorageState { + pub callbackContext: *mut c_void, + pub ldmEnable: c_int, + pub hasExtSeqProd: c_int, + pub hashLog: c_uint, + pub bucketSizeLog: c_uint, + pub blockSize: usize, + pub maxNbSeq: usize, + pub maxNbLdmSeq: usize, + pub maxNbExternalSeq: usize, + pub buffInSize: usize, + pub buffOutSize: usize, + pub seqDefSize: usize, + pub ldmEntrySize: usize, + pub rawSeqSize: usize, + pub externalSequenceSize: usize, + pub byteSize: usize, + pub wildcopyOverlength: usize, + pub bufferedPolicy: c_int, + pub setPointer: Option, + pub setSize: Option, + pub setInt: Option, + pub reserve: Option, + pub reserveFailed: Option, + pub zero: Option, + pub windowInit: Option, + pub resetExternalSequences: Option, +} + +const _: () = { + assert!(size_of::() == size_of::()); + assert!(size_of::() == size_of::()); + assert!(size_of::() == size_of::()); + assert!(size_of::() == size_of::()); + assert!(size_of::() == size_of::()); + assert!(size_of::() == size_of::()); + assert!(size_of::() == size_of::()); + assert!(offset_of!(ZSTD_rust_resetCCtxStorageState, callbackContext) == 0); + assert!(offset_of!(ZSTD_rust_resetCCtxStorageState, ldmEnable) == size_of::()); + assert!( + offset_of!(ZSTD_rust_resetCCtxStorageState, hasExtSeqProd) + == size_of::() + size_of::() + ); + assert!( + offset_of!(ZSTD_rust_resetCCtxStorageState, hashLog) + > offset_of!(ZSTD_rust_resetCCtxStorageState, hasExtSeqProd) + ); + assert!( + offset_of!(ZSTD_rust_resetCCtxStorageState, bucketSizeLog) + == offset_of!(ZSTD_rust_resetCCtxStorageState, hashLog) + size_of::() + ); + assert!( + offset_of!(ZSTD_rust_resetCCtxStorageState, blockSize) + > offset_of!(ZSTD_rust_resetCCtxStorageState, bucketSizeLog) + ); + assert!( + offset_of!(ZSTD_rust_resetCCtxStorageState, maxNbSeq) + == offset_of!(ZSTD_rust_resetCCtxStorageState, blockSize) + size_of::() + ); + assert!( + offset_of!(ZSTD_rust_resetCCtxStorageState, maxNbLdmSeq) + == offset_of!(ZSTD_rust_resetCCtxStorageState, maxNbSeq) + size_of::() + ); + assert!( + offset_of!(ZSTD_rust_resetCCtxStorageState, maxNbExternalSeq) + == offset_of!(ZSTD_rust_resetCCtxStorageState, maxNbLdmSeq) + size_of::() + ); + assert!( + offset_of!(ZSTD_rust_resetCCtxStorageState, buffInSize) + == offset_of!(ZSTD_rust_resetCCtxStorageState, maxNbExternalSeq) + size_of::() + ); + assert!( + offset_of!(ZSTD_rust_resetCCtxStorageState, buffOutSize) + == offset_of!(ZSTD_rust_resetCCtxStorageState, buffInSize) + size_of::() + ); + assert!( + offset_of!(ZSTD_rust_resetCCtxStorageState, seqDefSize) + == offset_of!(ZSTD_rust_resetCCtxStorageState, buffOutSize) + size_of::() + ); + assert!( + offset_of!(ZSTD_rust_resetCCtxStorageState, ldmEntrySize) + == offset_of!(ZSTD_rust_resetCCtxStorageState, seqDefSize) + size_of::() + ); + assert!( + offset_of!(ZSTD_rust_resetCCtxStorageState, rawSeqSize) + == offset_of!(ZSTD_rust_resetCCtxStorageState, ldmEntrySize) + size_of::() + ); + assert!( + offset_of!(ZSTD_rust_resetCCtxStorageState, externalSequenceSize) + == offset_of!(ZSTD_rust_resetCCtxStorageState, rawSeqSize) + size_of::() + ); + assert!( + offset_of!(ZSTD_rust_resetCCtxStorageState, byteSize) + == offset_of!(ZSTD_rust_resetCCtxStorageState, externalSequenceSize) + + size_of::() + ); + assert!( + offset_of!(ZSTD_rust_resetCCtxStorageState, wildcopyOverlength) + == offset_of!(ZSTD_rust_resetCCtxStorageState, byteSize) + size_of::() + ); + assert!( + offset_of!(ZSTD_rust_resetCCtxStorageState, bufferedPolicy) + > offset_of!(ZSTD_rust_resetCCtxStorageState, wildcopyOverlength) + ); + assert!( + offset_of!(ZSTD_rust_resetCCtxStorageState, setSize) + == offset_of!(ZSTD_rust_resetCCtxStorageState, setPointer) + size_of::() + ); + assert!( + offset_of!(ZSTD_rust_resetCCtxStorageState, setInt) + == offset_of!(ZSTD_rust_resetCCtxStorageState, setSize) + size_of::() + ); + assert!( + offset_of!(ZSTD_rust_resetCCtxStorageState, reserve) + == offset_of!(ZSTD_rust_resetCCtxStorageState, setInt) + size_of::() + ); + assert!( + size_of::() + == offset_of!(ZSTD_rust_resetCCtxStorageState, resetExternalSequences) + + size_of::() + ); +}; + +/// Reserve and publish the private CCtx storage that follows match-state reset. +#[no_mangle] +pub unsafe extern "C" fn ZSTD_rust_resetCCtxStorage( + state: *const ZSTD_rust_resetCCtxStorageState, +) -> usize { + if state.is_null() { + return ERROR(ZstdErrorCode::Generic); + } + let state = unsafe { &*state }; + if state.callbackContext.is_null() { + return ERROR(ZstdErrorCode::Generic); + } + let Some(set_pointer) = state.setPointer else { + return ERROR(ZstdErrorCode::Generic); + }; + let Some(set_size) = state.setSize else { + return ERROR(ZstdErrorCode::Generic); + }; + let Some(set_int) = state.setInt else { + return ERROR(ZstdErrorCode::Generic); + }; + let Some(reserve_callback) = state.reserve else { + return ERROR(ZstdErrorCode::Generic); + }; + let Some(reserve_failed) = state.reserveFailed else { + return ERROR(ZstdErrorCode::Generic); + }; + let Some(zero) = state.zero else { + return ERROR(ZstdErrorCode::Generic); + }; + let Some(window_init) = state.windowInit else { + return ERROR(ZstdErrorCode::Generic); + }; + let Some(reset_external_sequences) = state.resetExternalSequences else { + return ERROR(ZstdErrorCode::Generic); + }; + + let reserve = |kind: c_int, size: usize| -> Result<*mut c_void, usize> { + let pointer = unsafe { reserve_callback(state.callbackContext, kind, size) }; + if unsafe { reserve_failed(state.callbackContext) } != 0 { + Err(ERROR(ZstdErrorCode::MemoryAllocation)) + } else { + Ok(pointer) + } + }; + let publish_pointer = |kind: c_int, pointer: *mut c_void| unsafe { + set_pointer(state.callbackContext, kind, pointer) + }; + let publish_size = + |kind: c_int, value: usize| unsafe { set_size(state.callbackContext, kind, value) }; + + let sequence_start = match reserve( + RESET_CCTX_RESERVE_ALIGNED64, + state.maxNbSeq.wrapping_mul(state.seqDefSize), + ) { + Ok(pointer) => pointer, + Err(error) => return error, + }; + publish_pointer(RESET_CCTX_POINTER_SEQ_START, sequence_start); + + if state.ldmEnable == ZSTD_RUST_PS_ENABLE { + if state.bucketSizeLog > state.hashLog { + return ERROR(ZstdErrorCode::Generic); + } + let Some(hash_size) = 1usize.checked_shl(state.hashLog) else { + return ERROR(ZstdErrorCode::Generic); + }; + let hash_table = match reserve( + RESET_CCTX_RESERVE_ALIGNED64, + hash_size.wrapping_mul(state.ldmEntrySize), + ) { + Ok(pointer) => pointer, + Err(error) => return error, + }; + publish_pointer(RESET_CCTX_POINTER_LDM_HASH, hash_table); + unsafe { + zero( + state.callbackContext, + hash_table, + hash_size.wrapping_mul(state.ldmEntrySize), + ) + }; + + let ldm_sequences = match reserve( + RESET_CCTX_RESERVE_ALIGNED64, + state.maxNbLdmSeq.wrapping_mul(state.rawSeqSize), + ) { + Ok(pointer) => pointer, + Err(error) => return error, + }; + publish_pointer(RESET_CCTX_POINTER_LDM_SEQUENCES, ldm_sequences); + publish_size(RESET_CCTX_SIZE_MAX_NB_LDM_SEQ, state.maxNbLdmSeq); + unsafe { window_init(state.callbackContext) }; + } + + if state.hasExtSeqProd != 0 { + let external_sequences = match reserve( + RESET_CCTX_RESERVE_ALIGNED64, + state + .maxNbExternalSeq + .wrapping_mul(state.externalSequenceSize), + ) { + Ok(pointer) => pointer, + Err(error) => return error, + }; + publish_pointer(RESET_CCTX_POINTER_EXTERNAL_SEQUENCES, external_sequences); + publish_size( + RESET_CCTX_SIZE_EXTERNAL_SEQ_CAPACITY, + state.maxNbExternalSeq, + ); + } + + let literals = match reserve( + RESET_CCTX_RESERVE_BUFFER, + state.blockSize.wrapping_add(state.wildcopyOverlength), + ) { + Ok(pointer) => pointer, + Err(error) => return error, + }; + publish_pointer(RESET_CCTX_POINTER_LITERALS, literals); + publish_size(RESET_CCTX_SIZE_MAX_NB_LIT, state.blockSize); + unsafe { + set_int( + state.callbackContext, + RESET_CCTX_INT_BUFFERED_POLICY, + state.bufferedPolicy, + ) + }; + + let input_buffer = match reserve(RESET_CCTX_RESERVE_BUFFER, state.buffInSize) { + Ok(pointer) => pointer, + Err(error) => return error, + }; + publish_pointer(RESET_CCTX_POINTER_INPUT_BUFFER, input_buffer); + publish_size(RESET_CCTX_SIZE_INPUT_BUFFER, state.buffInSize); + + let output_buffer = match reserve(RESET_CCTX_RESERVE_BUFFER, state.buffOutSize) { + Ok(pointer) => pointer, + Err(error) => return error, + }; + publish_pointer(RESET_CCTX_POINTER_OUTPUT_BUFFER, output_buffer); + publish_size(RESET_CCTX_SIZE_OUTPUT_BUFFER, state.buffOutSize); + + if state.ldmEnable == ZSTD_RUST_PS_ENABLE { + let bucket_count = match 1usize.checked_shl(state.hashLog - state.bucketSizeLog) { + Some(count) => count, + None => return ERROR(ZstdErrorCode::Generic), + }; + let bucket_offsets = match reserve( + RESET_CCTX_RESERVE_BUFFER, + bucket_count.wrapping_mul(state.byteSize), + ) { + Ok(pointer) => pointer, + Err(error) => return error, + }; + publish_pointer(RESET_CCTX_POINTER_LDM_BUCKETS, bucket_offsets); + unsafe { + zero( + state.callbackContext, + bucket_offsets, + bucket_count.wrapping_mul(state.byteSize), + ) + }; + } + + unsafe { reset_external_sequences(state.callbackContext) }; + publish_size(RESET_CCTX_SIZE_MAX_NB_SEQ, state.maxNbSeq); + + let ll_code = match reserve( + RESET_CCTX_RESERVE_BUFFER, + state.maxNbSeq.wrapping_mul(state.byteSize), + ) { + Ok(pointer) => pointer, + Err(error) => return error, + }; + publish_pointer(RESET_CCTX_POINTER_LL_CODE, ll_code); + let ml_code = match reserve( + RESET_CCTX_RESERVE_BUFFER, + state.maxNbSeq.wrapping_mul(state.byteSize), + ) { + Ok(pointer) => pointer, + Err(error) => return error, + }; + publish_pointer(RESET_CCTX_POINTER_ML_CODE, ml_code); + let of_code = match reserve( + RESET_CCTX_RESERVE_BUFFER, + state.maxNbSeq.wrapping_mul(state.byteSize), + ) { + Ok(pointer) => pointer, + Err(error) => return error, + }; + publish_pointer(RESET_CCTX_POINTER_OF_CODE, of_code); + unsafe { set_int(state.callbackContext, RESET_CCTX_INT_INITIALIZED, 1) }; + 0 +} + #[inline] fn max_estimate_cctx_size( estimate0: usize, @@ -13975,6 +14332,283 @@ mod tests { ); } + #[derive(Debug, PartialEq)] + enum ResetCCtxStorageTestEvent { + Reserve(c_int, usize), + Pointer(c_int), + Size(c_int, usize), + Int(c_int, c_int), + Zero(usize), + WindowInit, + ResetExternalSequences, + } + + #[derive(Default)] + struct ResetCCtxStorageTestContext { + events: Vec, + reserve_count: usize, + reserve_failure: bool, + } + + unsafe fn reset_cctx_storage_test_context( + context: *mut c_void, + ) -> &'static mut ResetCCtxStorageTestContext { + unsafe { &mut *context.cast::() } + } + + unsafe extern "C" fn reset_cctx_storage_test_set_pointer( + context: *mut c_void, + kind: c_int, + _pointer: *mut c_void, + ) { + let context = unsafe { reset_cctx_storage_test_context(context) }; + context + .events + .push(ResetCCtxStorageTestEvent::Pointer(kind)); + } + + unsafe extern "C" fn reset_cctx_storage_test_set_size( + context: *mut c_void, + kind: c_int, + value: usize, + ) { + let context = unsafe { reset_cctx_storage_test_context(context) }; + context + .events + .push(ResetCCtxStorageTestEvent::Size(kind, value)); + } + + unsafe extern "C" fn reset_cctx_storage_test_set_int( + context: *mut c_void, + kind: c_int, + value: c_int, + ) { + let context = unsafe { reset_cctx_storage_test_context(context) }; + context + .events + .push(ResetCCtxStorageTestEvent::Int(kind, value)); + } + + unsafe extern "C" fn reset_cctx_storage_test_reserve( + context: *mut c_void, + kind: c_int, + size: usize, + ) -> *mut c_void { + let context = unsafe { reset_cctx_storage_test_context(context) }; + context + .events + .push(ResetCCtxStorageTestEvent::Reserve(kind, size)); + let pointer = (0x1000usize + context.reserve_count * 0x1000) as *mut c_void; + context.reserve_count += 1; + pointer + } + + unsafe extern "C" fn reset_cctx_storage_test_reserve_failed(context: *mut c_void) -> c_int { + let context = unsafe { reset_cctx_storage_test_context(context) }; + c_int::from(context.reserve_failure) + } + + unsafe extern "C" fn reset_cctx_storage_test_zero( + context: *mut c_void, + _pointer: *mut c_void, + size: usize, + ) { + let context = unsafe { reset_cctx_storage_test_context(context) }; + context.events.push(ResetCCtxStorageTestEvent::Zero(size)); + } + + unsafe extern "C" fn reset_cctx_storage_test_window_init(context: *mut c_void) { + let context = unsafe { reset_cctx_storage_test_context(context) }; + context.events.push(ResetCCtxStorageTestEvent::WindowInit); + } + + unsafe extern "C" fn reset_cctx_storage_test_reset_external_sequences(context: *mut c_void) { + let context = unsafe { reset_cctx_storage_test_context(context) }; + context + .events + .push(ResetCCtxStorageTestEvent::ResetExternalSequences); + } + + fn reset_cctx_storage_test_state( + context: &mut ResetCCtxStorageTestContext, + ldm_enable: c_int, + has_ext_seq_prod: c_int, + block_size: usize, + max_nb_seq: usize, + max_nb_ldm_seq: usize, + max_nb_external_seq: usize, + buff_in_size: usize, + buff_out_size: usize, + ) -> ZSTD_rust_resetCCtxStorageState { + ZSTD_rust_resetCCtxStorageState { + callbackContext: (context as *mut ResetCCtxStorageTestContext).cast(), + ldmEnable: ldm_enable, + hasExtSeqProd: has_ext_seq_prod, + hashLog: 4, + bucketSizeLog: 2, + blockSize: block_size, + maxNbSeq: max_nb_seq, + maxNbLdmSeq: max_nb_ldm_seq, + maxNbExternalSeq: max_nb_external_seq, + buffInSize: buff_in_size, + buffOutSize: buff_out_size, + seqDefSize: size_of::(), + ldmEntrySize: 8, + rawSeqSize: 12, + externalSequenceSize: size_of::(), + byteSize: 1, + wildcopyOverlength: 8, + bufferedPolicy: ZSTD_BM_BUFFERED, + setPointer: Some(reset_cctx_storage_test_set_pointer), + setSize: Some(reset_cctx_storage_test_set_size), + setInt: Some(reset_cctx_storage_test_set_int), + reserve: Some(reset_cctx_storage_test_reserve), + reserveFailed: Some(reset_cctx_storage_test_reserve_failed), + zero: Some(reset_cctx_storage_test_zero), + windowInit: Some(reset_cctx_storage_test_window_init), + resetExternalSequences: Some(reset_cctx_storage_test_reset_external_sequences), + } + } + + #[test] + fn cctx_storage_preserves_ordinary_reservation_and_publication_order() { + let mut context = ResetCCtxStorageTestContext::default(); + let state = reset_cctx_storage_test_state( + &mut context, + ZSTD_RUST_PS_DISABLE, + 0, + 128, + 4, + 0, + 0, + 0, + 0, + ); + + assert_eq!(unsafe { ZSTD_rust_resetCCtxStorage(&state) }, 0); + assert_eq!( + context.events, + [ + ResetCCtxStorageTestEvent::Reserve( + RESET_CCTX_RESERVE_ALIGNED64, + 4 * size_of::() + ), + ResetCCtxStorageTestEvent::Pointer(RESET_CCTX_POINTER_SEQ_START), + ResetCCtxStorageTestEvent::Reserve(RESET_CCTX_RESERVE_BUFFER, 136), + ResetCCtxStorageTestEvent::Pointer(RESET_CCTX_POINTER_LITERALS), + ResetCCtxStorageTestEvent::Size(RESET_CCTX_SIZE_MAX_NB_LIT, 128), + ResetCCtxStorageTestEvent::Int(RESET_CCTX_INT_BUFFERED_POLICY, ZSTD_BM_BUFFERED), + ResetCCtxStorageTestEvent::Reserve(RESET_CCTX_RESERVE_BUFFER, 0), + ResetCCtxStorageTestEvent::Pointer(RESET_CCTX_POINTER_INPUT_BUFFER), + ResetCCtxStorageTestEvent::Size(RESET_CCTX_SIZE_INPUT_BUFFER, 0), + ResetCCtxStorageTestEvent::Reserve(RESET_CCTX_RESERVE_BUFFER, 0), + ResetCCtxStorageTestEvent::Pointer(RESET_CCTX_POINTER_OUTPUT_BUFFER), + ResetCCtxStorageTestEvent::Size(RESET_CCTX_SIZE_OUTPUT_BUFFER, 0), + ResetCCtxStorageTestEvent::ResetExternalSequences, + ResetCCtxStorageTestEvent::Size(RESET_CCTX_SIZE_MAX_NB_SEQ, 4), + ResetCCtxStorageTestEvent::Reserve(RESET_CCTX_RESERVE_BUFFER, 4), + ResetCCtxStorageTestEvent::Pointer(RESET_CCTX_POINTER_LL_CODE), + ResetCCtxStorageTestEvent::Reserve(RESET_CCTX_RESERVE_BUFFER, 4), + ResetCCtxStorageTestEvent::Pointer(RESET_CCTX_POINTER_ML_CODE), + ResetCCtxStorageTestEvent::Reserve(RESET_CCTX_RESERVE_BUFFER, 4), + ResetCCtxStorageTestEvent::Pointer(RESET_CCTX_POINTER_OF_CODE), + ResetCCtxStorageTestEvent::Int(RESET_CCTX_INT_INITIALIZED, 1), + ] + ); + } + + #[test] + fn cctx_storage_preserves_ldm_and_external_sequence_order() { + let mut context = ResetCCtxStorageTestContext::default(); + let state = reset_cctx_storage_test_state( + &mut context, + ZSTD_RUST_PS_ENABLE, + 1, + 128, + 4, + 2, + 3, + 17, + 19, + ); + let external_size = 3 * size_of::(); + + assert_eq!(unsafe { ZSTD_rust_resetCCtxStorage(&state) }, 0); + assert_eq!( + context.events, + [ + ResetCCtxStorageTestEvent::Reserve( + RESET_CCTX_RESERVE_ALIGNED64, + 4 * size_of::() + ), + ResetCCtxStorageTestEvent::Pointer(RESET_CCTX_POINTER_SEQ_START), + ResetCCtxStorageTestEvent::Reserve(RESET_CCTX_RESERVE_ALIGNED64, 16 * 8), + ResetCCtxStorageTestEvent::Pointer(RESET_CCTX_POINTER_LDM_HASH), + ResetCCtxStorageTestEvent::Zero(16 * 8), + ResetCCtxStorageTestEvent::Reserve(RESET_CCTX_RESERVE_ALIGNED64, 2 * 12), + ResetCCtxStorageTestEvent::Pointer(RESET_CCTX_POINTER_LDM_SEQUENCES), + ResetCCtxStorageTestEvent::Size(RESET_CCTX_SIZE_MAX_NB_LDM_SEQ, 2), + ResetCCtxStorageTestEvent::WindowInit, + ResetCCtxStorageTestEvent::Reserve(RESET_CCTX_RESERVE_ALIGNED64, external_size), + ResetCCtxStorageTestEvent::Pointer(RESET_CCTX_POINTER_EXTERNAL_SEQUENCES), + ResetCCtxStorageTestEvent::Size(RESET_CCTX_SIZE_EXTERNAL_SEQ_CAPACITY, 3), + ResetCCtxStorageTestEvent::Reserve(RESET_CCTX_RESERVE_BUFFER, 136), + ResetCCtxStorageTestEvent::Pointer(RESET_CCTX_POINTER_LITERALS), + ResetCCtxStorageTestEvent::Size(RESET_CCTX_SIZE_MAX_NB_LIT, 128), + ResetCCtxStorageTestEvent::Int(RESET_CCTX_INT_BUFFERED_POLICY, ZSTD_BM_BUFFERED), + ResetCCtxStorageTestEvent::Reserve(RESET_CCTX_RESERVE_BUFFER, 17), + ResetCCtxStorageTestEvent::Pointer(RESET_CCTX_POINTER_INPUT_BUFFER), + ResetCCtxStorageTestEvent::Size(RESET_CCTX_SIZE_INPUT_BUFFER, 17), + ResetCCtxStorageTestEvent::Reserve(RESET_CCTX_RESERVE_BUFFER, 19), + ResetCCtxStorageTestEvent::Pointer(RESET_CCTX_POINTER_OUTPUT_BUFFER), + ResetCCtxStorageTestEvent::Size(RESET_CCTX_SIZE_OUTPUT_BUFFER, 19), + ResetCCtxStorageTestEvent::Reserve(RESET_CCTX_RESERVE_BUFFER, 4), + ResetCCtxStorageTestEvent::Pointer(RESET_CCTX_POINTER_LDM_BUCKETS), + ResetCCtxStorageTestEvent::Zero(4), + ResetCCtxStorageTestEvent::ResetExternalSequences, + ResetCCtxStorageTestEvent::Size(RESET_CCTX_SIZE_MAX_NB_SEQ, 4), + ResetCCtxStorageTestEvent::Reserve(RESET_CCTX_RESERVE_BUFFER, 4), + ResetCCtxStorageTestEvent::Pointer(RESET_CCTX_POINTER_LL_CODE), + ResetCCtxStorageTestEvent::Reserve(RESET_CCTX_RESERVE_BUFFER, 4), + ResetCCtxStorageTestEvent::Pointer(RESET_CCTX_POINTER_ML_CODE), + ResetCCtxStorageTestEvent::Reserve(RESET_CCTX_RESERVE_BUFFER, 4), + ResetCCtxStorageTestEvent::Pointer(RESET_CCTX_POINTER_OF_CODE), + ResetCCtxStorageTestEvent::Int(RESET_CCTX_INT_INITIALIZED, 1), + ] + ); + } + + #[test] + fn cctx_storage_propagates_reservation_failure_before_publication() { + let mut context = ResetCCtxStorageTestContext { + reserve_failure: true, + ..ResetCCtxStorageTestContext::default() + }; + let state = reset_cctx_storage_test_state( + &mut context, + ZSTD_RUST_PS_DISABLE, + 0, + 128, + 4, + 0, + 0, + 0, + 0, + ); + + assert_eq!( + unsafe { ZSTD_rust_resetCCtxStorage(&state) }, + ERROR(ZstdErrorCode::MemoryAllocation) + ); + assert_eq!( + context.events, + [ResetCCtxStorageTestEvent::Reserve( + RESET_CCTX_RESERVE_ALIGNED64, + 4 * size_of::() + )] + ); + } + #[test] fn estimate_cctx_workspace_size_keeps_static_and_buffer_components_separate() { let sizing = cctx_workspace_test_sizing();