feat(compress): route simple context frames through Rust

Dispatch ordinary dictionary-free ZSTD_compress2 calls through the Rust frame
compressor while retaining the original C implementation for advanced
contexts. Prepare the C workspace first so allocation downsizing and
static-context limits remain observable.

Mark successful Rust frames so a following one-shot
ZSTD_compressStream2(..., ZSTD_e_end) call uses the same output path. Other
streaming directives and advanced parameters remain on the C implementation.

Test Plan:
- RUSTC_WRAPPER= CARGO_BUILD_RUSTC_WRAPPER= cargo test --manifest-path
  rust/Cargo.toml --no-default-features --features compression
  zstd_compress::tests
- RUSTC_WRAPPER= CARGO_BUILD_RUSTC_WRAPPER= cargo clippy --manifest-path
  rust/Cargo.toml --no-default-features --features compression -- -D warnings
- cargo +nightly fmt --manifest-path rust/Cargo.toml -- --check
- make -B -C tests fuzzer
- ./tests/fuzzer -t114 -i1000 --no-big-tests -s1

The basic fuzzer run now reaches the existing Rust one-shot compression-ratio
limit at test 113; the new stateful reuse tests pass before that point.
This commit is contained in:
2026-07-12 19:16:14 +02:00
parent e66ad5f563
commit 5c448120cf
3 changed files with 197 additions and 4 deletions
+70 -1
View File
@@ -9,7 +9,10 @@
//! already migrated compression leaves. `ZSTD_compressCCtx` uses the same
//! path after a narrow C-owned context reset; the public context lifecycle
//! and streaming APIs remain C-owned because they share the
//! configuration-dependent private `ZSTD_CCtx_s` layout.
//! configuration-dependent private `ZSTD_CCtx_s` layout. `ZSTD_compress2`
//! dispatches simple, dictionary-free contexts through the same Rust frame
//! path and retains the C implementation for advanced contexts. A following
//! one-shot `ZSTD_compressStream2(..., ZSTD_e_end)` call can reuse that path.
use crate::errors::{ERR_isError, ZstdErrorCode, ERROR};
use crate::mem::MEM_writeLE24;
@@ -29,6 +32,21 @@ use std::ptr;
#[cfg(not(test))]
unsafe extern "C" {
fn ZSTD_rust_resetCCtxForSimpleCompression(cctx: *mut c_void) -> usize;
fn ZSTD_rust_prepareCCtxForSimpleCompression(
cctx: *mut c_void,
src_size: usize,
compression_level: c_int,
) -> usize;
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) -> c_int;
fn ZSTD_compress2_c(
cctx: *mut c_void,
dst: *mut c_void,
dst_capacity: usize,
src: *const c_void,
src_size: usize,
) -> usize;
}
const ZSTD_FAST: c_int = 1;
@@ -360,10 +378,61 @@ pub unsafe extern "C" fn ZSTD_compressCCtx(
if ERR_isError(reset) {
return reset;
}
let prepare =
unsafe { ZSTD_rust_prepareCCtxForSimpleCompression(cctx, src_size, compression_level) };
if ERR_isError(prepare) {
return prepare;
}
}
unsafe { compress_frame(dst, dst_capacity, src, src_size, compression_level) }
}
/// Stateful compression entry point during the context migration.
///
/// A context with only the ordinary frame settings is reset by the C shim and
/// compressed through the Rust frame path. Contexts using dictionaries,
/// checksums, target-sized blocks, sequence collection, or other advanced
/// state still use the renamed C implementation until their state is moved.
#[no_mangle]
pub unsafe extern "C" fn ZSTD_compress2(
cctx: *mut c_void,
dst: *mut c_void,
dst_capacity: usize,
src: *const c_void,
src_size: usize,
) -> usize {
if cctx.is_null() {
return ERROR(ZstdErrorCode::Generic);
}
#[cfg(test)]
{
unsafe { compress_frame(dst, dst_capacity, src, src_size, 3) }
}
#[cfg(not(test))]
{
let level = unsafe { ZSTD_rust_simpleCompress2Level(cctx.cast_const()) };
if level != c_int::MIN {
let reset = unsafe { ZSTD_rust_resetCCtxForSimpleCompressionSession(cctx) };
if ERR_isError(reset) {
return reset;
}
let prepare =
unsafe { ZSTD_rust_prepareCCtxForSimpleCompression(cctx, src_size, level) };
if ERR_isError(prepare) {
return prepare;
}
let result = unsafe { compress_frame(dst, dst_capacity, src, src_size, level) };
if !ERR_isError(result) {
unsafe { ZSTD_rust_markSimpleCompression2Complete(cctx) };
}
return result;
}
unsafe { ZSTD_compress2_c(cctx, dst, dst_capacity, src, src_size) }
}
}
#[cfg(test)]
mod tests {
use super::*;