diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 68d568d0c..3436462b6 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -2015,6 +2015,9 @@ int ZSTD_rust_cctx_params_job_size_min(void); int ZSTD_rust_cctx_params_job_size_max(void); ZSTD_CCtx_params* ZSTD_rust_createCCtxParams(ZSTD_customMem customMem); size_t ZSTD_rust_freeCCtxParams(ZSTD_CCtx_params* params); +void ZSTD_rust_CCtxParams_init_internal( + ZSTD_CCtx_params* cctxParams, const ZSTD_parameters* params, + int compressionLevel); size_t ZSTD_rust_CCtxParams_init_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params); void ZSTD_rust_CCtxParams_setZstdParams(ZSTD_CCtx_params* cctxParams, @@ -3661,19 +3664,7 @@ ZSTD_CCtxParams_init_internal(ZSTD_CCtx_params* cctxParams, int compressionLevel) { assert(!ZSTD_checkCParams(params->cParams)); - ZSTD_memset(cctxParams, 0, sizeof(*cctxParams)); - cctxParams->cParams = params->cParams; - cctxParams->fParams = params->fParams; - /* Should not matter, as all cParams are presumed properly defined. - * But, set it for tracing anyway. - */ - cctxParams->compressionLevel = compressionLevel; - cctxParams->useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(cctxParams->useRowMatchFinder, ¶ms->cParams); - cctxParams->postBlockSplitter = ZSTD_resolveBlockSplitterMode(cctxParams->postBlockSplitter, ¶ms->cParams); - cctxParams->ldmParams.enableLdm = ZSTD_resolveEnableLdm(cctxParams->ldmParams.enableLdm, ¶ms->cParams); - cctxParams->validateSequences = ZSTD_resolveExternalSequenceValidation(cctxParams->validateSequences); - cctxParams->maxBlockSize = ZSTD_resolveMaxBlockSize(cctxParams->maxBlockSize); - cctxParams->searchForExternalRepcodes = ZSTD_resolveExternalRepcodeSearch(cctxParams->searchForExternalRepcodes, compressionLevel); + ZSTD_rust_CCtxParams_init_internal(cctxParams, params, compressionLevel); DEBUGLOG(4, "ZSTD_CCtxParams_init_internal: useRowMatchFinder=%d, useBlockSplitter=%d ldm=%d", cctxParams->useRowMatchFinder, cctxParams->postBlockSplitter, cctxParams->ldmParams.enableLdm); } diff --git a/rust/src/zstd_compress_params_api.rs b/rust/src/zstd_compress_params_api.rs index 886f0c471..6cba51b58 100644 --- a/rust/src/zstd_compress_params_api.rs +++ b/rust/src/zstd_compress_params_api.rs @@ -17,9 +17,10 @@ use crate::zstd_compress_params::{ ZSTD_rust_params_checkCParams, ZSTD_rust_params_dedicatedDictSearchIsSupported, ZSTD_rust_params_dedicatedDictSearch_getCParams, ZSTD_rust_params_getBounds, ZSTD_rust_params_getCParamsFromCCtxParams, ZSTD_rust_params_getCParamsInternal, - ZSTD_rust_params_overrideCParams, ZSTD_rust_params_resolveMaxBlockSize, + ZSTD_rust_params_overrideCParams, ZSTD_rust_params_resolveExternalRepcodeSearch, + ZSTD_rust_params_resolveExternalSequenceValidation, ZSTD_rust_params_resolveMaxBlockSize, ZSTD_rust_params_resolveRowMatchFinderMode, ZSTD_CONTENTSIZE_UNKNOWN, - ZSTD_RUST_CPM_CREATE_CDICT, ZSTD_RUST_PS_DISABLE, ZSTD_RUST_PS_ENABLE, + ZSTD_RUST_CPM_CREATE_CDICT, ZSTD_RUST_PS_AUTO, ZSTD_RUST_PS_DISABLE, ZSTD_RUST_PS_ENABLE, }; use std::mem::size_of; use std::os::raw::{c_int, c_void}; @@ -426,6 +427,41 @@ unsafe fn init_impl(params: *mut ZSTD_CCtx_params, compression_level: c_int) -> 0 } +unsafe fn init_internal_impl( + cctx_params: *mut ZSTD_CCtx_params, + zstd_params: *const ZSTD_parameters, + compression_level: c_int, +) { + unsafe { + ptr::write_bytes(cctx_params.cast::(), 0, size_of::()); + (*cctx_params).cParams = (*zstd_params).cParams; + (*cctx_params).fParams = (*zstd_params).fParams; + /* Keep the level for tracing even when params came from a zstd-params object. */ + (*cctx_params).compressionLevel = compression_level; + (*cctx_params).useRowMatchFinder = resolve_row_match_finder((*zstd_params).cParams); + (*cctx_params).postBlockSplitter = resolve_block_splitter((*zstd_params).cParams); + (*cctx_params).ldmParams.enableLdm = resolve_ldm((*zstd_params).cParams); + (*cctx_params).validateSequences = + ZSTD_rust_params_resolveExternalSequenceValidation(ZSTD_RUST_PS_AUTO); + (*cctx_params).maxBlockSize = ZSTD_rust_params_resolveMaxBlockSize(0); + (*cctx_params).searchForExternalRepcodes = + ZSTD_rust_params_resolveExternalRepcodeSearch(ZSTD_RUST_PS_AUTO, compression_level); + } +} + +/// Initializes the internal parameter object from validated zstd parameters. +/// +/// The C adapter retains validation assertions and diagnostic logging; this +/// function owns only the narrow reset, copy, and default-resolution policy. +#[no_mangle] +pub unsafe extern "C" fn ZSTD_rust_CCtxParams_init_internal( + cctx_params: *mut ZSTD_CCtx_params, + zstd_params: *const ZSTD_parameters, + compression_level: c_int, +) { + unsafe { init_internal_impl(cctx_params, zstd_params, compression_level) } +} + #[inline] fn resolve_row_match_finder(cparams: ZSTD_compressionParameters) -> c_int { if (STRATEGY_GREEDY..=STRATEGY_LAZY2).contains(&cparams.strategy) && cparams.windowLog > 14 { @@ -1483,6 +1519,51 @@ mod tests { } } + #[test] + fn init_internal_resets_and_resolves_policy_without_changing_inputs() { + let zstd_params = ZSTD_parameters { + cParams: ZSTD_compressionParameters { + windowLog: 27, + chainLog: 27, + hashLog: 25, + searchLog: 9, + minMatch: 4, + targetLength: 32, + strategy: STRATEGY_BTOPT, + }, + fParams: ZSTD_frameParameters { + contentSizeFlag: 1, + checksumFlag: 1, + noDictIDFlag: 0, + }, + }; + + for (compression_level, expected_repcode_search) in + [(9, ZSTD_RUST_PS_DISABLE), (10, ZSTD_RUST_PS_ENABLE)] + { + let mut storage = MaybeUninit::::zeroed(); + let params = storage.as_mut_ptr(); + unsafe { + (*params).format = 1; + (*params).customMem.opaque = ptr::dangling_mut::(); + + ZSTD_rust_CCtxParams_init_internal(params, &zstd_params, compression_level); + + assert_eq!((*params).cParams, zstd_params.cParams); + assert_eq!((*params).fParams, zstd_params.fParams); + assert_eq!((*params).compressionLevel, compression_level); + assert_eq!((*params).useRowMatchFinder, ZSTD_RUST_PS_DISABLE); + assert_eq!((*params).postBlockSplitter, ZSTD_RUST_PS_ENABLE); + assert_eq!((*params).ldmParams.enableLdm, ZSTD_RUST_PS_ENABLE); + assert_eq!((*params).validateSequences, 0); + assert_eq!((*params).maxBlockSize, BLOCKSIZE_MAX); + assert_eq!((*params).searchForExternalRepcodes, expected_repcode_search); + assert_eq!((*params).format, 0); + assert!((*params).customMem.opaque.is_null()); + } + } + } + #[test] fn advanced_init_resolves_policy_and_resets_internal_fields() { let cases = [