diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 594757046..91f0b608d 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -3849,13 +3849,6 @@ size_t ZSTD_compress_usingDict(ZSTD_CCtx* cctx, /* The Rust simple API still needs the C-owned context reset, but does not * cross the private context layout. */ -int ZSTD_rust_compressCCtxStrategy(size_t srcSize, int compressionLevel) -{ - ZSTD_parameters const params = ZSTD_getParams_internal( - compressionLevel, srcSize, 0, ZSTD_cpm_noAttachDict); - return (int)params.cParams.strategy; -} - size_t ZSTD_rust_resetCCtxForSimpleCompression(void* cctx) { return ZSTD_CCtx_reset((ZSTD_CCtx*)cctx, ZSTD_reset_session_and_parameters); diff --git a/rust/src/zstd_compress.rs b/rust/src/zstd_compress.rs index 99ef1070d..8e49f6162 100644 --- a/rust/src/zstd_compress.rs +++ b/rust/src/zstd_compress.rs @@ -23,7 +23,7 @@ use crate::zstd_compress_frame::{ use crate::zstd_compress_literals::min_gain; use crate::zstd_compress_params::{ ZSTD_rust_params_adjustCParams, ZSTD_rust_params_maxNbSeq, ZSTD_rust_params_selectCParams, - ZSTD_RUST_CPM_NO_ATTACH_DICT, ZSTD_RUST_PS_DISABLE, + ZSTD_RUST_CPM_NO_ATTACH_DICT, ZSTD_RUST_PS_AUTO, ZSTD_RUST_PS_DISABLE, }; use crate::zstd_compress_sequences::SeqDef; use crate::zstd_compress_stats::{ @@ -44,7 +44,6 @@ unsafe extern "C" { src_size: usize, compression_level: c_int, ) -> usize; - fn ZSTD_rust_compressCCtxStrategy(src_size: usize, compression_level: c_int) -> c_int; fn ZSTD_rust_resetCCtxForSimpleCompressionSession(cctx: *mut c_void) -> usize; fn ZSTD_rust_markSimpleCompression2Complete(cctx: *mut c_void); fn ZSTD_rust_simpleCompress2Level(cctx: *const c_void, src_size: usize) -> c_int; @@ -142,6 +141,33 @@ fn target_c_block_size_action( } } +/// Select the strategy used by the simple compression entry points. +/// +/// This is the Rust equivalent of the strategy portion of +/// `ZSTD_getParams_internal(..., ZSTD_cpm_noAttachDict)`: use the actual +/// source size for table selection, then apply the ordinary automatic +/// parameter adjustment before dispatching to the Rust or C frame path. +#[no_mangle] +pub extern "C" fn ZSTD_rust_compressCCtxStrategy( + src_size: usize, + compression_level: c_int, +) -> c_int { + let cparams = ZSTD_rust_params_selectCParams( + compression_level, + src_size as u64, + 0, + ZSTD_RUST_CPM_NO_ATTACH_DICT, + ); + ZSTD_rust_params_adjustCParams( + cparams, + src_size as u64, + 0, + ZSTD_RUST_CPM_NO_ATTACH_DICT, + ZSTD_RUST_PS_AUTO, + ) + .strategy +} + /// Classify the target-sized block policy without crossing the C context ABI. /// /// C calls this once before the superblock attempt to classify the RLE @@ -1205,7 +1231,7 @@ pub unsafe extern "C" fn ZSTD_compress( ) -> usize { #[cfg(not(test))] { - let strategy = unsafe { ZSTD_rust_compressCCtxStrategy(src_size, compression_level) }; + let strategy = ZSTD_rust_compressCCtxStrategy(src_size, compression_level); if strategy != ZSTD_FAST && strategy != ZSTD_DFAST { let cctx = unsafe { ZSTD_createCCtx() }; if cctx.is_null() { @@ -1250,7 +1276,7 @@ pub unsafe extern "C" fn ZSTD_compressCCtx( } #[cfg(not(test))] { - let strategy = unsafe { ZSTD_rust_compressCCtxStrategy(src_size, compression_level) }; + let strategy = ZSTD_rust_compressCCtxStrategy(src_size, compression_level); if strategy != ZSTD_FAST && strategy != ZSTD_DFAST { return unsafe { ZSTD_compress_usingDict( @@ -1394,6 +1420,12 @@ mod tests { use std::io::Write; use std::process::{Command, Stdio}; + const ZSTD_GREEDY: c_int = 3; + const ZSTD_LAZY: c_int = 4; + const ZSTD_BTULTRA: c_int = 8; + const ZSTD_BTOPT: c_int = 7; + const ZSTD_BTULTRA2: c_int = 9; + fn system_round_trip(compressed: &[u8]) -> Option> { let mut child = Command::new("zstd") .args(["-q", "-d", "-c"]) @@ -1431,6 +1463,32 @@ mod tests { output } + #[test] + fn simple_strategy_follows_source_size_tiers() { + assert_eq!(ZSTD_rust_compressCCtxStrategy(0, 1), ZSTD_FAST); + assert_eq!(ZSTD_rust_compressCCtxStrategy(16 * 1024, 5), ZSTD_LAZY); + assert_eq!( + ZSTD_rust_compressCCtxStrategy(16 * 1024 + 1, 5), + ZSTD_GREEDY + ); + assert_eq!(ZSTD_rust_compressCCtxStrategy(128 * 1024, 16), ZSTD_BTULTRA); + assert_eq!(ZSTD_rust_compressCCtxStrategy(256 * 1024, 16), ZSTD_BTULTRA); + assert_eq!( + ZSTD_rust_compressCCtxStrategy(256 * 1024 + 1, 16), + ZSTD_BTOPT + ); + } + + #[test] + fn simple_strategy_preserves_default_and_fast_level_selection() { + assert_eq!(ZSTD_rust_compressCCtxStrategy(64 * 1024, 0), ZSTD_DFAST); + assert_eq!(ZSTD_rust_compressCCtxStrategy(1024 * 1024, -5), ZSTD_FAST); + assert_eq!( + ZSTD_rust_compressCCtxStrategy(1024 * 1024, 22), + ZSTD_BTULTRA2 + ); + } + #[test] fn reduce_table_applies_threshold_and_wrapping_subtraction() { let mut table = [0, 1, 2, 3, 4, 5, 6, u32::MAX, 0, 0, 0, 0, 0, 0, 0, 0];