From 4952b259c4e10769f695dd4901fd606c778fcbe6 Mon Sep 17 00:00:00 2001 From: ddidderr Date: Sun, 19 Jul 2026 14:19:43 +0200 Subject: [PATCH] feat(compress): move CDict begin policy into Rust Move ZSTD_compressBegin_usingCDict_internal source-size parameter selection, parameter initialization ordering, and source-window floor into a Rust-owned ABI bridge while retaining private CCtx/CDict layouts and the final C begin callback. Preserve strict cutoff, dictionary-size multiplier, unknown-size, level-zero, and begin-error semantics. Test Plan: - cargo test --manifest-path rust/Cargo.toml --lib - cargo clippy --manifest-path rust/Cargo.toml --all-targets -- -D warnings - make -B -C programs -j1 zstd - make -C tests -j1 test-zstream ZSTREAM_TESTTIME=-T1s - focused cdict_begin unit tests --- lib/compress/zstd_compress.c | 123 ++++++-- rust/src/zstd_compress_dictionary.rs | 441 +++++++++++++++++++++++++++ 2 files changed, 535 insertions(+), 29 deletions(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 14f3fb9a2..728d7c7dc 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -1226,6 +1226,57 @@ size_t ZSTD_rust_CCtx_refPrefixAdvanced( const void* prefix, size_t prefixSize, int dictContentType, ZSTD_rust_CCtxDictionaryClear_f clearDictionaries, ZSTD_rust_CCtxAssignPrefixDict_f assignPrefixDict); +typedef void (*ZSTD_rust_compressBeginUsingCDictInitParams_f)( + void* cctxParams, const ZSTD_parameters* params, int compressionLevel); +typedef void (*ZSTD_rust_compressBeginUsingCDictAdjustWindow_f)( + void* cctxParams, U32 minWindowLog); +typedef size_t (*ZSTD_rust_compressBeginUsingCDictBegin_f)( + void* context, const void* cdict, const void* cctxParams, + U64 pledgedSrcSize); +typedef struct { + void* cctx; + const void* cdict; + void* cctxParams; + const ZSTD_compressionParameters* cdictCParams; + const size_t* cdictContentSize; + const int* cdictCompressionLevel; + const ZSTD_frameParameters* fParams; + const unsigned long long* pledgedSrcSize; + const U32* exclusionMask; + ZSTD_rust_compressBeginUsingCDictInitParams_f initParams; + ZSTD_rust_compressBeginUsingCDictAdjustWindow_f adjustWindow; + ZSTD_rust_compressBeginUsingCDictBegin_f begin; +} ZSTD_rust_compressBeginUsingCDictState; +size_t ZSTD_rust_compressBeginUsingCDict( + const ZSTD_rust_compressBeginUsingCDictState* state); +typedef char ZSTD_rust_compress_begin_using_cdict_state_layout[ + (offsetof(ZSTD_rust_compressBeginUsingCDictState, cctx) == 0 + && offsetof(ZSTD_rust_compressBeginUsingCDictState, cdict) + == sizeof(void*) + && offsetof(ZSTD_rust_compressBeginUsingCDictState, cctxParams) + == 2 * sizeof(void*) + && offsetof(ZSTD_rust_compressBeginUsingCDictState, cdictCParams) + == 3 * sizeof(void*) + && offsetof(ZSTD_rust_compressBeginUsingCDictState, cdictContentSize) + == 4 * sizeof(void*) + && offsetof(ZSTD_rust_compressBeginUsingCDictState, + cdictCompressionLevel) + == 5 * sizeof(void*) + && offsetof(ZSTD_rust_compressBeginUsingCDictState, fParams) + == 6 * sizeof(void*) + && offsetof(ZSTD_rust_compressBeginUsingCDictState, pledgedSrcSize) + == 7 * sizeof(void*) + && offsetof(ZSTD_rust_compressBeginUsingCDictState, exclusionMask) + == 8 * sizeof(void*) + && offsetof(ZSTD_rust_compressBeginUsingCDictState, initParams) + == 9 * sizeof(void*) + && offsetof(ZSTD_rust_compressBeginUsingCDictState, adjustWindow) + == 10 * sizeof(void*) + && offsetof(ZSTD_rust_compressBeginUsingCDictState, begin) + == 11 * sizeof(void*) + && sizeof(ZSTD_rust_compressBeginUsingCDictState) + == 12 * sizeof(void*)) + ? 1 : -1]; size_t ZSTD_rust_transferSequencesWBlockDelim( SeqStore_t* seqStore, ZSTD_SequencePosition* seqPos, const ZSTD_Sequence* inSeqs, size_t inSeqsSize, @@ -4902,6 +4953,34 @@ unsigned ZSTD_getDictID_fromCDict(const ZSTD_CDict* cdict) return cdict->dictID; } +static void ZSTD_rust_compressBeginUsingCDict_initParams( + void* cctxParams, const ZSTD_parameters* params, int compressionLevel) +{ + ZSTD_CCtxParams_init_internal( + (ZSTD_CCtx_params*)cctxParams, params, compressionLevel); +} + +static void ZSTD_rust_compressBeginUsingCDict_adjustWindow( + void* cctxParams, U32 minWindowLog) +{ + ZSTD_CCtx_params* const params = (ZSTD_CCtx_params*)cctxParams; + if (params->cParams.windowLog < minWindowLog) { + params->cParams.windowLog = minWindowLog; + } +} + +static size_t ZSTD_rust_compressBeginUsingCDict_begin( + void* context, const void* cdict, const void* cctxParams, + U64 pledgedSrcSize) +{ + return ZSTD_compressBegin_internal( + (ZSTD_CCtx*)context, NULL, 0, + ZSTD_dct_auto, ZSTD_dtlm_fast, + (const ZSTD_CDict*)cdict, + (const ZSTD_CCtx_params*)cctxParams, + pledgedSrcSize, ZSTDb_not_buffered); +} + /* ZSTD_compressBegin_usingCDict_internal() : * Implementation of various ZSTD_compressBegin_usingCDict* functions. */ @@ -4910,36 +4989,22 @@ static size_t ZSTD_compressBegin_usingCDict_internal( ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize) { ZSTD_CCtx_params cctxParams; + U32 const exclusionMask = ZSTD_getCParamsExclusionMask(); + ZSTD_rust_compressBeginUsingCDictState state; DEBUGLOG(4, "ZSTD_compressBegin_usingCDict_internal"); - RETURN_ERROR_IF(cdict==NULL, dictionary_wrong, "NULL pointer!"); - /* Initialize the cctxParams from the cdict */ - { - ZSTD_parameters params; - params.fParams = fParams; - params.cParams = ( pledgedSrcSize < ZSTD_USE_CDICT_PARAMS_SRCSIZE_CUTOFF - || pledgedSrcSize < cdict->dictContentSize * ZSTD_USE_CDICT_PARAMS_DICTSIZE_MULTIPLIER - || pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN - || cdict->compressionLevel == 0 ) ? - ZSTD_getCParamsFromCDict(cdict) - : ZSTD_getCParams(cdict->compressionLevel, - pledgedSrcSize, - cdict->dictContentSize); - ZSTD_CCtxParams_init_internal(&cctxParams, ¶ms, cdict->compressionLevel); - } - /* Increase window log to fit the entire dictionary and source if the - * source size is known. Limit the increase to 19, which is the - * window log for compression level 1 with the largest source size. - */ - if (pledgedSrcSize != ZSTD_CONTENTSIZE_UNKNOWN) { - U32 const limitedSrcSize = (U32)MIN(pledgedSrcSize, 1U << 19); - U32 const limitedSrcLog = limitedSrcSize > 1 ? ZSTD_highbit32(limitedSrcSize - 1) + 1 : 1; - cctxParams.cParams.windowLog = MAX(cctxParams.cParams.windowLog, limitedSrcLog); - } - return ZSTD_compressBegin_internal(cctx, - NULL, 0, ZSTD_dct_auto, ZSTD_dtlm_fast, - cdict, - &cctxParams, pledgedSrcSize, - ZSTDb_not_buffered); + state.cctx = cctx; + state.cdict = cdict; + state.cctxParams = &cctxParams; + state.cdictCParams = cdict == NULL ? NULL : &cdict->matchState.cParams; + state.cdictContentSize = cdict == NULL ? NULL : &cdict->dictContentSize; + state.cdictCompressionLevel = cdict == NULL ? NULL : &cdict->compressionLevel; + state.fParams = &fParams; + state.pledgedSrcSize = &pledgedSrcSize; + state.exclusionMask = &exclusionMask; + state.initParams = ZSTD_rust_compressBeginUsingCDict_initParams; + state.adjustWindow = ZSTD_rust_compressBeginUsingCDict_adjustWindow; + state.begin = ZSTD_rust_compressBeginUsingCDict_begin; + return ZSTD_rust_compressBeginUsingCDict(&state); } diff --git a/rust/src/zstd_compress_dictionary.rs b/rust/src/zstd_compress_dictionary.rs index b801fdd62..3acd0b665 100644 --- a/rust/src/zstd_compress_dictionary.rs +++ b/rust/src/zstd_compress_dictionary.rs @@ -15,10 +15,16 @@ use crate::entropy_common::FSE_readNCount; use crate::errors::{ERR_isError, ZstdErrorCode, ERROR}; use crate::fse_compress::FSE_buildCTable_wksp; use crate::huf_compress::HUF_readCTable; +use crate::zstd_compress_params::{ + ZSTD_compressionParameters, ZSTD_frameParameters, ZSTD_parameters, ZSTD_rust_params_getCParams, + ZSTD_CONTENTSIZE_UNKNOWN, +}; +use crate::zstd_compress_params_api::ZSTD_CCtx_params; use crate::zstd_compress_stats::{ ZSTD_compressedBlockState_t, ZSTD_rust_resetCompressedBlockState, }; use std::ffi::c_void; +use std::mem::{offset_of, size_of}; use std::os::raw::{c_int, c_short, c_uint}; use std::ptr; use std::slice; @@ -84,6 +90,148 @@ fn stage_wrong() -> usize { ERROR(ZstdErrorCode::StageWrong) } +type CompressBeginUsingCDictInitParamsFn = + unsafe extern "C" fn(*mut c_void, *const ZSTD_parameters, c_int); +type CompressBeginUsingCDictAdjustWindowFn = unsafe extern "C" fn(*mut c_void, c_uint); +type CompressBeginUsingCDictBeginFn = + unsafe extern "C" fn(*mut c_void, *const c_void, *const c_void, u64) -> usize; + +/// Explicit projection for `ZSTD_compressBegin_usingCDict_internal`. +/// +/// Rust owns CDict/source-size parameter selection, initialization ordering, +/// and the source-window floor. C retains the private parameter/context +/// layouts and the final begin operation behind callbacks. +#[repr(C)] +pub struct ZSTD_rust_compressBeginUsingCDictState { + cctx: *mut c_void, + cdict: *const c_void, + cctx_params: *mut ZSTD_CCtx_params, + cdict_cparams: *const ZSTD_compressionParameters, + cdict_content_size: *const usize, + cdict_compression_level: *const c_int, + f_params: *const ZSTD_frameParameters, + pledged_src_size: *const u64, + exclusion_mask: *const c_uint, + init_params: CompressBeginUsingCDictInitParamsFn, + adjust_window: CompressBeginUsingCDictAdjustWindowFn, + begin: CompressBeginUsingCDictBeginFn, +} + +const _: () = { + assert!(offset_of!(ZSTD_rust_compressBeginUsingCDictState, cctx) == 0); + assert!(offset_of!(ZSTD_rust_compressBeginUsingCDictState, cdict) == size_of::()); + assert!( + offset_of!(ZSTD_rust_compressBeginUsingCDictState, cctx_params) == 2 * size_of::() + ); + assert!( + offset_of!(ZSTD_rust_compressBeginUsingCDictState, cdict_cparams) == 3 * size_of::() + ); + assert!( + offset_of!(ZSTD_rust_compressBeginUsingCDictState, cdict_content_size) + == 4 * size_of::() + ); + assert!( + offset_of!( + ZSTD_rust_compressBeginUsingCDictState, + cdict_compression_level + ) == 5 * size_of::() + ); + assert!(offset_of!(ZSTD_rust_compressBeginUsingCDictState, f_params) == 6 * size_of::()); + assert!( + offset_of!(ZSTD_rust_compressBeginUsingCDictState, pledged_src_size) + == 7 * size_of::() + ); + assert!( + offset_of!(ZSTD_rust_compressBeginUsingCDictState, exclusion_mask) + == size_of::<[usize; 8]>() + ); + assert!( + offset_of!(ZSTD_rust_compressBeginUsingCDictState, init_params) == 9 * size_of::() + ); + assert!( + offset_of!(ZSTD_rust_compressBeginUsingCDictState, adjust_window) + == 10 * size_of::() + ); + assert!(offset_of!(ZSTD_rust_compressBeginUsingCDictState, begin) == 11 * size_of::()); + assert!(size_of::() == size_of::<[usize; 12]>()); +}; + +const CDICT_PARAMS_SRC_SIZE_CUTOFF: u64 = 128 * 1024; +const CDICT_PARAMS_DICT_SIZE_MULTIPLIER: u64 = 6; +const CDICT_WINDOW_SOURCE_SIZE_CAP: u64 = 1 << 19; + +/// Apply the CDict begin policy while keeping private C state behind callbacks. +#[no_mangle] +pub unsafe extern "C" fn ZSTD_rust_compressBeginUsingCDict( + state: *const ZSTD_rust_compressBeginUsingCDictState, +) -> usize { + if state.is_null() { + return ERROR(ZstdErrorCode::Generic); + } + let state = unsafe { &*state }; + if state.cdict.is_null() { + return ERROR(ZstdErrorCode::DictionaryWrong); + } + if state.cctx_params.is_null() + || state.cdict_cparams.is_null() + || state.cdict_content_size.is_null() + || state.cdict_compression_level.is_null() + || state.f_params.is_null() + || state.pledged_src_size.is_null() + || state.exclusion_mask.is_null() + { + return ERROR(ZstdErrorCode::Generic); + } + + let cdict_cparams = unsafe { *state.cdict_cparams }; + let cdict_content_size = unsafe { *state.cdict_content_size }; + let cdict_compression_level = unsafe { *state.cdict_compression_level }; + let pledged_src_size = unsafe { *state.pledged_src_size }; + let cdict_size_threshold = + (cdict_content_size as u64).wrapping_mul(CDICT_PARAMS_DICT_SIZE_MULTIPLIER); + let cparams = if pledged_src_size < CDICT_PARAMS_SRC_SIZE_CUTOFF + || pledged_src_size < cdict_size_threshold + || pledged_src_size == ZSTD_CONTENTSIZE_UNKNOWN + || cdict_compression_level == 0 + { + cdict_cparams + } else { + ZSTD_rust_params_getCParams( + cdict_compression_level, + pledged_src_size, + cdict_content_size, + unsafe { *state.exclusion_mask }, + ) + }; + let params = ZSTD_parameters { + cParams: cparams, + fParams: unsafe { *state.f_params }, + }; + + unsafe { + (state.init_params)(state.cctx_params.cast(), ¶ms, cdict_compression_level); + } + if pledged_src_size != ZSTD_CONTENTSIZE_UNKNOWN { + let limited_src_size = pledged_src_size.min(CDICT_WINDOW_SOURCE_SIZE_CAP) as u32; + let limited_src_log = if limited_src_size > 1 { + ZSTD_highbit32(limited_src_size - 1) + 1 + } else { + 1 + }; + unsafe { + (state.adjust_window)(state.cctx_params.cast(), limited_src_log); + } + } + unsafe { + (state.begin)( + state.cctx, + state.cdict, + state.cctx_params.cast_const().cast(), + pledged_src_size, + ) + } +} + /// Rust-owned policy for `ZSTD_CCtx_loadDictionary_advanced()`. #[no_mangle] pub unsafe extern "C" fn ZSTD_rust_CCtx_loadDictionaryAdvanced( @@ -743,6 +891,299 @@ mod tests { assert_eq!(probe.events, [3]); } + #[derive(Default)] + struct CdictBeginProbe { + events: Vec<&'static str>, + initialized: Option, + compression_level: c_int, + min_window_logs: Vec, + begin_result: usize, + } + + unsafe fn cdict_begin_probe(context: *mut c_void) -> &'static mut CdictBeginProbe { + unsafe { &mut *context.cast::() } + } + + unsafe extern "C" fn cdict_begin_init( + context: *mut c_void, + params: *const ZSTD_parameters, + compression_level: c_int, + ) { + let probe = unsafe { cdict_begin_probe(context) }; + probe.events.push("init"); + probe.initialized = Some(unsafe { *params }); + probe.compression_level = compression_level; + } + + unsafe extern "C" fn cdict_begin_adjust_window(context: *mut c_void, min_window_log: c_uint) { + let probe = unsafe { cdict_begin_probe(context) }; + probe.events.push("adjust"); + probe.min_window_logs.push(min_window_log); + } + + unsafe extern "C" fn cdict_begin_begin( + context: *mut c_void, + _cdict: *const c_void, + _cctx_params: *const c_void, + _pledged_src_size: u64, + ) -> usize { + let probe = unsafe { cdict_begin_probe(context) }; + probe.events.push("begin"); + probe.begin_result + } + + fn cdict_begin_test_state( + probe: &mut CdictBeginProbe, + cdict: *const c_void, + cdict_cparams: &ZSTD_compressionParameters, + cdict_content_size: &usize, + cdict_compression_level: &c_int, + f_params: &ZSTD_frameParameters, + pledged_src_size: &u64, + exclusion_mask: &c_uint, + ) -> ZSTD_rust_compressBeginUsingCDictState { + ZSTD_rust_compressBeginUsingCDictState { + cctx: (probe as *mut CdictBeginProbe).cast(), + cdict, + cctx_params: (probe as *mut CdictBeginProbe).cast(), + cdict_cparams, + cdict_content_size, + cdict_compression_level, + f_params, + pledged_src_size, + exclusion_mask, + init_params: cdict_begin_init, + adjust_window: cdict_begin_adjust_window, + begin: cdict_begin_begin, + } + } + + #[test] + fn cdict_begin_rejects_a_null_dictionary_before_reading_state() { + let state = ZSTD_rust_compressBeginUsingCDictState { + cctx: ptr::null_mut(), + cdict: ptr::null(), + cctx_params: ptr::null_mut(), + cdict_cparams: ptr::null(), + cdict_content_size: ptr::null(), + cdict_compression_level: ptr::null(), + f_params: ptr::null(), + pledged_src_size: ptr::null(), + exclusion_mask: ptr::null(), + init_params: cdict_begin_init, + adjust_window: cdict_begin_adjust_window, + begin: cdict_begin_begin, + }; + + let result = unsafe { ZSTD_rust_compressBeginUsingCDict(&state) }; + + assert_eq!(result, ERROR(ZstdErrorCode::DictionaryWrong)); + } + + #[test] + fn cdict_begin_reuses_cdict_params_below_the_source_cutoff() { + let mut probe = CdictBeginProbe::default(); + let cdict_cparams = ZSTD_compressionParameters { + windowLog: 17, + chainLog: 12, + hashLog: 13, + searchLog: 1, + minMatch: 4, + targetLength: 16, + strategy: 3, + }; + let cdict_content_size = 1usize; + let cdict_compression_level = 3; + let f_params = ZSTD_frameParameters::default(); + let pledged_src_size = CDICT_PARAMS_SRC_SIZE_CUTOFF - 1; + let exclusion_mask = 0; + let state = cdict_begin_test_state( + &mut probe, + ptr::dangling(), + &cdict_cparams, + &cdict_content_size, + &cdict_compression_level, + &f_params, + &pledged_src_size, + &exclusion_mask, + ); + + let result = unsafe { ZSTD_rust_compressBeginUsingCDict(&state) }; + + assert_eq!(result, 0); + assert_eq!(probe.events, ["init", "adjust", "begin"]); + assert_eq!(probe.initialized.unwrap().cParams, cdict_cparams); + assert_eq!(probe.compression_level, cdict_compression_level); + assert_eq!(probe.min_window_logs, [17]); + } + + #[test] + fn cdict_begin_reuses_cdict_params_for_unknown_source_without_adjustment() { + let mut probe = CdictBeginProbe::default(); + let cdict_cparams = ZSTD_compressionParameters { + windowLog: 17, + chainLog: 12, + hashLog: 13, + searchLog: 1, + minMatch: 4, + targetLength: 16, + strategy: 3, + }; + let cdict_content_size = 1usize; + let cdict_compression_level = 3; + let f_params = ZSTD_frameParameters::default(); + let pledged_src_size = ZSTD_CONTENTSIZE_UNKNOWN; + let exclusion_mask = 0; + let state = cdict_begin_test_state( + &mut probe, + ptr::dangling(), + &cdict_cparams, + &cdict_content_size, + &cdict_compression_level, + &f_params, + &pledged_src_size, + &exclusion_mask, + ); + + let result = unsafe { ZSTD_rust_compressBeginUsingCDict(&state) }; + + assert_eq!(result, 0); + assert_eq!(probe.events, ["init", "begin"]); + assert_eq!(probe.initialized.unwrap().cParams, cdict_cparams); + assert!(probe.min_window_logs.is_empty()); + } + + #[test] + fn cdict_begin_reuses_cdict_params_for_dictionary_ratio_or_zero_level() { + let cdict_cparams = ZSTD_compressionParameters { + windowLog: 10, + chainLog: 6, + hashLog: 6, + searchLog: 1, + minMatch: 3, + targetLength: 0, + strategy: 1, + }; + let cdict_content_size = 64 * 1024usize; + let f_params = ZSTD_frameParameters::default(); + let exclusion_mask = 0; + + let mut ratio_probe = CdictBeginProbe::default(); + let ratio_compression_level = 3; + let ratio_pledged_src_size = 256 * 1024; + let ratio_state = cdict_begin_test_state( + &mut ratio_probe, + ptr::dangling(), + &cdict_cparams, + &cdict_content_size, + &ratio_compression_level, + &f_params, + &ratio_pledged_src_size, + &exclusion_mask, + ); + let ratio_result = unsafe { ZSTD_rust_compressBeginUsingCDict(&ratio_state) }; + + assert_eq!(ratio_result, 0); + assert_eq!(ratio_probe.initialized.unwrap().cParams, cdict_cparams); + + let mut zero_level_probe = CdictBeginProbe::default(); + let zero_level_compression_level = 0; + let zero_level_pledged_src_size = 1 << 20; + let zero_level_state = cdict_begin_test_state( + &mut zero_level_probe, + ptr::dangling(), + &cdict_cparams, + &cdict_content_size, + &zero_level_compression_level, + &f_params, + &zero_level_pledged_src_size, + &exclusion_mask, + ); + let zero_level_result = unsafe { ZSTD_rust_compressBeginUsingCDict(&zero_level_state) }; + + assert_eq!(zero_level_result, 0); + assert_eq!(zero_level_probe.initialized.unwrap().cParams, cdict_cparams); + } + + #[test] + fn cdict_begin_selects_public_params_at_the_source_cutoff() { + let mut probe = CdictBeginProbe::default(); + let cdict_cparams = ZSTD_compressionParameters { + windowLog: 10, + chainLog: 6, + hashLog: 6, + searchLog: 1, + minMatch: 3, + targetLength: 0, + strategy: 1, + }; + let cdict_content_size = 1usize; + let cdict_compression_level = 3; + let f_params = ZSTD_frameParameters::default(); + let pledged_src_size = CDICT_PARAMS_SRC_SIZE_CUTOFF; + let exclusion_mask = 0; + let state = cdict_begin_test_state( + &mut probe, + ptr::dangling(), + &cdict_cparams, + &cdict_content_size, + &cdict_compression_level, + &f_params, + &pledged_src_size, + &exclusion_mask, + ); + let expected_cparams = ZSTD_rust_params_getCParams( + cdict_compression_level, + pledged_src_size, + cdict_content_size, + exclusion_mask, + ); + + let result = unsafe { ZSTD_rust_compressBeginUsingCDict(&state) }; + + assert_eq!(result, 0); + assert_eq!(probe.initialized.unwrap().cParams, expected_cparams); + assert_eq!(probe.events, ["init", "adjust", "begin"]); + } + + #[test] + fn cdict_begin_preserves_order_and_begin_errors_for_large_sources() { + let mut probe = CdictBeginProbe { + begin_result: ERROR(ZstdErrorCode::DstSizeTooSmall), + ..Default::default() + }; + let cdict_cparams = ZSTD_compressionParameters { + windowLog: 10, + chainLog: 6, + hashLog: 6, + searchLog: 1, + minMatch: 3, + targetLength: 0, + strategy: 1, + }; + let cdict_content_size = 1usize; + let cdict_compression_level = 3; + let f_params = ZSTD_frameParameters::default(); + let pledged_src_size = 1 << 20; + let exclusion_mask = 0; + let state = cdict_begin_test_state( + &mut probe, + ptr::dangling(), + &cdict_cparams, + &cdict_content_size, + &cdict_compression_level, + &f_params, + &pledged_src_size, + &exclusion_mask, + ); + + let result = unsafe { ZSTD_rust_compressBeginUsingCDict(&state) }; + + assert_eq!(result, probe.begin_result); + assert_eq!(probe.events, ["init", "adjust", "begin"]); + assert_eq!(probe.min_window_logs, [19]); + } + fn assert_dictionary_corrupted(result: usize) { assert!(ERR_isError(result)); assert_eq!(