feat(compress): move advanced CCtx parameter init to Rust
Move ZSTD_CCtxParams_init_advanced and its default-resolution policy into the Rust parameter API while retaining the C public ABI wrapper. Preserve validation, zeroing, and the existing row-match, block-splitter, LDM, and repcode defaults. Test Plan:\n- cargo clippy --manifest-path rust/Cargo.toml\n- cargo clippy --manifest-path rust/Cargo.toml --benches\n- cargo clippy --manifest-path rust/Cargo.toml --tests\n- cargo +nightly fmt --manifest-path rust/Cargo.toml --all -- --check\n- cargo test --manifest-path rust/Cargo.toml --no-default-features --features compression zstd_compress_params_api\n- make -B -C lib -j2 lib
This commit is contained in:
@@ -5,15 +5,20 @@
|
||||
|
||||
//! Rust implementation of the narrow `ZSTD_CCtx_params` object API.
|
||||
//!
|
||||
//! Advanced initialization, bounds calculation, and context policy remain in
|
||||
//! `zstd_compress.c`. This module owns the parameter object's storage
|
||||
//! lifecycle, reset/initialization, parameter set/get, and sequence-producer
|
||||
//! registration entry points.
|
||||
//! Advanced initialization, bounds calculation, and context policy are split
|
||||
//! narrowly between this module and `zstd_compress.c`. This module owns the
|
||||
//! parameter object's storage lifecycle, initialization, parameter set/get,
|
||||
//! sequence-producer registration, and advanced initialization's small
|
||||
//! default-resolution policy.
|
||||
|
||||
use crate::errors::{ZstdErrorCode, ERROR};
|
||||
#[cfg(test)]
|
||||
use crate::zstd_compress_params::ZSTD_bounds;
|
||||
use crate::zstd_compress_params::{ZSTD_compressionParameters, ZSTD_frameParameters};
|
||||
use crate::zstd_compress_params::{
|
||||
ZSTD_compressionParameters, ZSTD_frameParameters, ZSTD_parameters,
|
||||
ZSTD_rust_params_checkCParams, ZSTD_rust_params_resolveMaxBlockSize, ZSTD_RUST_PS_DISABLE,
|
||||
ZSTD_RUST_PS_ENABLE,
|
||||
};
|
||||
use std::mem::size_of;
|
||||
use std::os::raw::{c_int, c_void};
|
||||
use std::ptr;
|
||||
@@ -119,11 +124,17 @@ pub struct ZSTD_CCtx_params {
|
||||
}
|
||||
|
||||
const DEFAULT_CLEVEL: c_int = 3;
|
||||
const NO_CLEVEL: c_int = 0;
|
||||
#[cfg(test)]
|
||||
const PS_AUTO: c_int = 0;
|
||||
#[cfg(test)]
|
||||
const PS_DISABLE: c_int = 2;
|
||||
|
||||
/* Private strategy values used by the existing C policy helpers. */
|
||||
const STRATEGY_GREEDY: c_int = 3;
|
||||
const STRATEGY_LAZY2: c_int = 5;
|
||||
const STRATEGY_BTOPT: c_int = 7;
|
||||
|
||||
#[cfg(test)]
|
||||
const BLOCKSIZE_MAX: usize = 1 << 17;
|
||||
#[cfg(test)]
|
||||
@@ -301,6 +312,72 @@ unsafe fn init_impl(params: *mut ZSTD_CCtx_params, compression_level: c_int) ->
|
||||
0
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn resolve_row_match_finder(cparams: ZSTD_compressionParameters) -> c_int {
|
||||
if (STRATEGY_GREEDY..=STRATEGY_LAZY2).contains(&cparams.strategy) && cparams.windowLog > 14 {
|
||||
ZSTD_RUST_PS_ENABLE
|
||||
} else {
|
||||
ZSTD_RUST_PS_DISABLE
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn resolve_block_splitter(cparams: ZSTD_compressionParameters) -> c_int {
|
||||
if cparams.strategy >= STRATEGY_BTOPT && cparams.windowLog >= 17 {
|
||||
ZSTD_RUST_PS_ENABLE
|
||||
} else {
|
||||
ZSTD_RUST_PS_DISABLE
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn resolve_ldm(cparams: ZSTD_compressionParameters) -> c_int {
|
||||
if cparams.strategy >= STRATEGY_BTOPT && cparams.windowLog >= 27 {
|
||||
ZSTD_RUST_PS_ENABLE
|
||||
} else {
|
||||
ZSTD_RUST_PS_DISABLE
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn resolve_external_repcode_search() -> c_int {
|
||||
/* ZSTD_NO_CLEVEL is below the threshold used by the C policy helper. */
|
||||
2
|
||||
}
|
||||
|
||||
unsafe fn init_advanced_impl(params: *mut ZSTD_CCtx_params, zstd_params: ZSTD_parameters) -> usize {
|
||||
if params.is_null() {
|
||||
return ERROR(ZstdErrorCode::Generic);
|
||||
}
|
||||
|
||||
let error = ZSTD_rust_params_checkCParams(zstd_params.cParams);
|
||||
if error != 0 {
|
||||
return error;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
ptr::write_bytes(params.cast::<u8>(), 0, size_of::<ZSTD_CCtx_params>());
|
||||
(*params).cParams = zstd_params.cParams;
|
||||
(*params).fParams = zstd_params.fParams;
|
||||
(*params).compressionLevel = NO_CLEVEL;
|
||||
(*params).useRowMatchFinder = resolve_row_match_finder(zstd_params.cParams);
|
||||
(*params).postBlockSplitter = resolve_block_splitter(zstd_params.cParams);
|
||||
(*params).ldmParams.enableLdm = resolve_ldm(zstd_params.cParams);
|
||||
(*params).validateSequences = 0;
|
||||
(*params).maxBlockSize = ZSTD_rust_params_resolveMaxBlockSize((*params).maxBlockSize);
|
||||
(*params).searchForExternalRepcodes = resolve_external_repcode_search();
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn ZSTD_rust_CCtxParams_init_advanced(
|
||||
params: *mut ZSTD_CCtx_params,
|
||||
zstd_params: ZSTD_parameters,
|
||||
) -> usize {
|
||||
unsafe { init_advanced_impl(params, zstd_params) }
|
||||
}
|
||||
|
||||
unsafe fn custom_calloc(size: usize, custom_mem: ZSTD_customMem) -> *mut c_void {
|
||||
if let Some(custom_alloc) = custom_mem.customAlloc {
|
||||
let allocation = unsafe { custom_alloc(custom_mem.opaque, size) };
|
||||
@@ -929,6 +1006,113 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn advanced_init_resolves_policy_and_resets_internal_fields() {
|
||||
let cases = [
|
||||
(
|
||||
ZSTD_parameters {
|
||||
cParams: ZSTD_compressionParameters {
|
||||
windowLog: 15,
|
||||
chainLog: 15,
|
||||
hashLog: 15,
|
||||
searchLog: 5,
|
||||
minMatch: 4,
|
||||
targetLength: 16,
|
||||
strategy: STRATEGY_GREEDY,
|
||||
},
|
||||
fParams: ZSTD_frameParameters {
|
||||
contentSizeFlag: 0,
|
||||
checksumFlag: 1,
|
||||
noDictIDFlag: 1,
|
||||
},
|
||||
},
|
||||
ZSTD_RUST_PS_ENABLE,
|
||||
ZSTD_RUST_PS_DISABLE,
|
||||
ZSTD_RUST_PS_DISABLE,
|
||||
),
|
||||
(
|
||||
ZSTD_parameters {
|
||||
cParams: ZSTD_compressionParameters {
|
||||
windowLog: 27,
|
||||
chainLog: 27,
|
||||
hashLog: 25,
|
||||
searchLog: 9,
|
||||
minMatch: 3,
|
||||
targetLength: 999,
|
||||
strategy: STRATEGY_BTOPT + 2,
|
||||
},
|
||||
fParams: ZSTD_frameParameters {
|
||||
contentSizeFlag: 1,
|
||||
checksumFlag: 0,
|
||||
noDictIDFlag: 0,
|
||||
},
|
||||
},
|
||||
ZSTD_RUST_PS_DISABLE,
|
||||
ZSTD_RUST_PS_ENABLE,
|
||||
ZSTD_RUST_PS_ENABLE,
|
||||
),
|
||||
];
|
||||
|
||||
for (zstd_params, expected_row, expected_splitter, expected_ldm) in cases {
|
||||
let mut storage = MaybeUninit::<ZSTD_CCtx_params>::zeroed();
|
||||
let params = storage.as_mut_ptr();
|
||||
unsafe {
|
||||
(*params).customMem.opaque = ptr::dangling_mut::<c_void>();
|
||||
assert_eq!(ZSTD_rust_CCtxParams_init_advanced(params, zstd_params), 0);
|
||||
assert_eq!((*params).cParams, zstd_params.cParams);
|
||||
assert_eq!((*params).fParams, zstd_params.fParams);
|
||||
assert_eq!((*params).compressionLevel, NO_CLEVEL);
|
||||
assert_eq!((*params).useRowMatchFinder, expected_row);
|
||||
assert_eq!((*params).postBlockSplitter, expected_splitter);
|
||||
assert_eq!((*params).ldmParams.enableLdm, expected_ldm);
|
||||
assert_eq!((*params).validateSequences, 0);
|
||||
assert_eq!((*params).maxBlockSize, BLOCKSIZE_MAX);
|
||||
assert_eq!((*params).searchForExternalRepcodes, PS_DISABLE);
|
||||
assert!((*params).customMem.customAlloc.is_none());
|
||||
assert!((*params).customMem.customFree.is_none());
|
||||
assert!((*params).customMem.opaque.is_null());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn advanced_init_rejects_null_and_invalid_cparams_before_mutating() {
|
||||
let valid_params = ZSTD_parameters {
|
||||
cParams: ZSTD_compressionParameters {
|
||||
windowLog: 20,
|
||||
chainLog: 20,
|
||||
hashLog: 20,
|
||||
searchLog: 5,
|
||||
minMatch: 4,
|
||||
targetLength: 16,
|
||||
strategy: STRATEGY_GREEDY,
|
||||
},
|
||||
fParams: ZSTD_frameParameters::default(),
|
||||
};
|
||||
assert_eq!(
|
||||
unsafe { ZSTD_rust_CCtxParams_init_advanced(ptr::null_mut(), valid_params) },
|
||||
ERROR(ZstdErrorCode::Generic)
|
||||
);
|
||||
|
||||
let mut storage = MaybeUninit::<ZSTD_CCtx_params>::zeroed();
|
||||
let params = storage.as_mut_ptr();
|
||||
unsafe {
|
||||
(*params).format = 1;
|
||||
(*params).customMem.opaque = ptr::dangling_mut::<c_void>();
|
||||
}
|
||||
|
||||
let mut invalid_params = valid_params;
|
||||
invalid_params.cParams.minMatch = 2;
|
||||
assert_eq!(
|
||||
unsafe { ZSTD_rust_CCtxParams_init_advanced(params, invalid_params) },
|
||||
ERROR(ZstdErrorCode::ParameterOutOfBound)
|
||||
);
|
||||
unsafe {
|
||||
assert_eq!((*params).format, 1);
|
||||
assert_eq!((*params).customMem.opaque, ptr::dangling_mut::<c_void>());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn allocation_lifecycle_preserves_default_and_custom_memory_contracts() {
|
||||
unsafe extern "C" fn counting_alloc(opaque: *mut c_void, size: usize) -> *mut c_void {
|
||||
|
||||
Reference in New Issue
Block a user