feat(compress): move parameter bundle orchestration into Rust

Move ZSTD_CCtx_setParams's check, frame-parameter, and compression-parameter
orchestration into the Rust projection. C retains callbacks for the existing
context-bound operations while Rust preserves the check -> frame -> compression
order and first-error propagation.

Test Plan:
- ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo test --manifest-path rust/Cargo.toml set_params -- --test-threads=1
- ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo clippy --manifest-path rust/Cargo.toml --all-targets -- -D warnings
- ulimit -v 41943040; make -B -C programs -j1 zstd
- git diff --cached --check
This commit is contained in:
2026-07-19 13:09:08 +02:00
parent b4e37ad09f
commit 878e18a966
2 changed files with 228 additions and 7 deletions
+46 -7
View File
@@ -226,6 +226,27 @@ typedef char ZSTD_rust_set_fparams_state_layout[
&& offsetof(ZSTD_rust_setFParamsState, setParameter) == sizeof(void*)
&& sizeof(ZSTD_rust_setFParamsState) == 2 * sizeof(void*))
? 1 : -1];
typedef size_t (*ZSTD_rust_setParamsCheckCParams_f)(
void* context, ZSTD_compressionParameters cParams);
typedef size_t (*ZSTD_rust_setParamsSetFParams_f)(
void* context, ZSTD_frameParameters fParams);
typedef size_t (*ZSTD_rust_setParamsSetCParams_f)(
void* context, ZSTD_compressionParameters cParams);
typedef struct {
void* callbackContext;
ZSTD_rust_setParamsCheckCParams_f checkCParams;
ZSTD_rust_setParamsSetFParams_f setFParams;
ZSTD_rust_setParamsSetCParams_f setCParams;
} ZSTD_rust_setParamsState;
size_t ZSTD_rust_setParams(const ZSTD_rust_setParamsState* state,
ZSTD_parameters params);
typedef char ZSTD_rust_set_params_state_layout[
(offsetof(ZSTD_rust_setParamsState, callbackContext) == 0
&& offsetof(ZSTD_rust_setParamsState, checkCParams) == sizeof(void*)
&& offsetof(ZSTD_rust_setParamsState, setFParams) == 2 * sizeof(void*)
&& offsetof(ZSTD_rust_setParamsState, setCParams) == 3 * sizeof(void*)
&& sizeof(ZSTD_rust_setParamsState) == 4 * sizeof(void*))
? 1 : -1];
ZSTD_frameProgression ZSTD_rust_frameProgression(U64 consumedSrcSize,
size_t buffered,
U64 producedCSize);
@@ -1922,6 +1943,25 @@ static size_t ZSTD_rust_setFParams_setParameter(
return ZSTD_CCtx_setParameter((ZSTD_CCtx*)context, (ZSTD_cParameter)param, value);
}
static size_t ZSTD_rust_setParams_checkCParams(
void* context, ZSTD_compressionParameters cParams)
{
(void)context;
return ZSTD_checkCParams(cParams);
}
static size_t ZSTD_rust_setParams_setFParams(
void* context, ZSTD_frameParameters fParams)
{
return ZSTD_CCtx_setFParams((ZSTD_CCtx*)context, fParams);
}
static size_t ZSTD_rust_setParams_setCParams(
void* context, ZSTD_compressionParameters cParams)
{
return ZSTD_CCtx_setCParams((ZSTD_CCtx*)context, cParams);
}
size_t ZSTD_CCtx_setCParams(ZSTD_CCtx* cctx, ZSTD_compressionParameters cparams)
{
ZSTD_rust_setCParamsState state;
@@ -1945,14 +1985,13 @@ size_t ZSTD_CCtx_setFParams(ZSTD_CCtx* cctx, ZSTD_frameParameters fparams)
size_t ZSTD_CCtx_setParams(ZSTD_CCtx* cctx, ZSTD_parameters params)
{
ZSTD_rust_setParamsState state;
DEBUGLOG(4, "ZSTD_CCtx_setParams");
/* First check cParams, because we want to update all or none. */
FORWARD_IF_ERROR(ZSTD_checkCParams(params.cParams), "");
/* Next set fParams, because this could fail if the cctx isn't in init stage. */
FORWARD_IF_ERROR(ZSTD_CCtx_setFParams(cctx, params.fParams), "");
/* Finally set cParams, which should succeed. */
FORWARD_IF_ERROR(ZSTD_CCtx_setCParams(cctx, params.cParams), "");
return 0;
state.callbackContext = cctx;
state.checkCParams = ZSTD_rust_setParams_checkCParams;
state.setFParams = ZSTD_rust_setParams_setFParams;
state.setCParams = ZSTD_rust_setParams_setCParams;
return ZSTD_rust_setParams(&state, params);
}
size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long long pledgedSrcSize)
+182
View File
@@ -1311,6 +1311,55 @@ pub unsafe extern "C" fn ZSTD_rust_setFParams(
0
}
type SetParamsCheckCParamsFn =
unsafe extern "C" fn(*mut c_void, ZSTD_compressionParameters) -> usize;
type SetParamsSetFParamsFn = unsafe extern "C" fn(*mut c_void, ZSTD_frameParameters) -> usize;
type SetParamsSetCParamsFn = unsafe extern "C" fn(*mut c_void, ZSTD_compressionParameters) -> usize;
/// Explicit projection for `ZSTD_CCtx_setParams`.
#[repr(C)]
pub struct ZSTD_rust_setParamsState {
callback_context: *mut c_void,
check_c_params: SetParamsCheckCParamsFn,
set_f_params: SetParamsSetFParamsFn,
set_c_params: SetParamsSetCParamsFn,
}
const _: () = {
assert!(offset_of!(ZSTD_rust_setParamsState, callback_context) == 0);
assert!(offset_of!(ZSTD_rust_setParamsState, check_c_params) == size_of::<usize>());
assert!(offset_of!(ZSTD_rust_setParamsState, set_f_params) == 2 * size_of::<usize>());
assert!(offset_of!(ZSTD_rust_setParamsState, set_c_params) == 3 * size_of::<usize>());
assert!(size_of::<ZSTD_rust_setParamsState>() == 4 * size_of::<usize>());
};
#[no_mangle]
pub unsafe extern "C" fn ZSTD_rust_setParams(
state: *const ZSTD_rust_setParamsState,
params: ZSTD_parameters,
) -> usize {
if state.is_null() {
return ERROR(ZstdErrorCode::Generic);
}
let state = unsafe { &*state };
let result = unsafe { (state.check_c_params)(state.callback_context, params.cParams) };
if ERR_isError(result) {
return result;
}
let result = unsafe { (state.set_f_params)(state.callback_context, params.fParams) };
if ERR_isError(result) {
return result;
}
let result = unsafe { (state.set_c_params)(state.callback_context, params.cParams) };
if ERR_isError(result) {
return result;
}
0
}
type CompressStreamBlockFn =
unsafe extern "C" fn(*mut c_void, *mut c_void, usize, *const c_void, usize) -> usize;
type CompressStreamResetFn = unsafe extern "C" fn(*mut c_void) -> usize;
@@ -9943,6 +9992,139 @@ mod tests {
);
}
#[derive(Default)]
struct SetParamsTestContext {
events: Vec<&'static str>,
received_cparams: Option<ZSTD_compressionParameters>,
received_fparams: Option<ZSTD_frameParameters>,
check_result: usize,
f_params_result: usize,
c_params_result: usize,
}
unsafe fn set_params_test_context(context: *mut c_void) -> &'static mut SetParamsTestContext {
unsafe { &mut *context.cast::<SetParamsTestContext>() }
}
unsafe extern "C" fn set_params_test_check(
context: *mut c_void,
cparams: ZSTD_compressionParameters,
) -> usize {
let context = unsafe { set_params_test_context(context) };
context.events.push("check");
context.received_cparams = Some(cparams);
context.check_result
}
unsafe extern "C" fn set_params_test_set_f_params(
context: *mut c_void,
fparams: ZSTD_frameParameters,
) -> usize {
let context = unsafe { set_params_test_context(context) };
context.events.push("f-params");
context.received_fparams = Some(fparams);
context.f_params_result
}
unsafe extern "C" fn set_params_test_set_c_params(
context: *mut c_void,
cparams: ZSTD_compressionParameters,
) -> usize {
let context = unsafe { set_params_test_context(context) };
context.events.push("c-params");
context.received_cparams = Some(cparams);
context.c_params_result
}
fn set_params_test_state(context: &mut SetParamsTestContext) -> ZSTD_rust_setParamsState {
ZSTD_rust_setParamsState {
callback_context: (context as *mut SetParamsTestContext).cast(),
check_c_params: set_params_test_check,
set_f_params: set_params_test_set_f_params,
set_c_params: set_params_test_set_c_params,
}
}
fn set_params_test_params() -> ZSTD_parameters {
ZSTD_parameters {
cParams: ZSTD_compressionParameters {
windowLog: 20,
chainLog: 19,
hashLog: 18,
searchLog: 5,
minMatch: 4,
targetLength: 32,
strategy: 3,
},
fParams: ZSTD_frameParameters {
contentSizeFlag: 1,
checksumFlag: 0,
noDictIDFlag: 1,
},
}
}
#[test]
fn set_params_preserves_check_frame_then_compression_order() {
let params = set_params_test_params();
let mut context = SetParamsTestContext::default();
let state = set_params_test_state(&mut context);
let result = unsafe { ZSTD_rust_setParams(&state, params) };
assert_eq!(result, 0);
assert_eq!(context.events, ["check", "f-params", "c-params"]);
assert_eq!(context.received_cparams, Some(params.cParams));
assert_eq!(context.received_fparams, Some(params.fParams));
}
#[test]
fn set_params_stops_before_frame_and_compression_after_check_error() {
let params = set_params_test_params();
let mut context = SetParamsTestContext {
check_result: ERROR(ZstdErrorCode::ParameterOutOfBound),
..SetParamsTestContext::default()
};
let state = set_params_test_state(&mut context);
let result = unsafe { ZSTD_rust_setParams(&state, params) };
assert_eq!(result, ERROR(ZstdErrorCode::ParameterOutOfBound));
assert_eq!(context.events, ["check"]);
assert!(context.received_fparams.is_none());
}
#[test]
fn set_params_stops_before_compression_after_frame_error() {
let params = set_params_test_params();
let mut context = SetParamsTestContext {
f_params_result: ERROR(ZstdErrorCode::StageWrong),
..SetParamsTestContext::default()
};
let state = set_params_test_state(&mut context);
let result = unsafe { ZSTD_rust_setParams(&state, params) };
assert_eq!(result, ERROR(ZstdErrorCode::StageWrong));
assert_eq!(context.events, ["check", "f-params"]);
assert!(context.received_cparams.is_some());
}
#[test]
fn set_params_propagates_compression_error_after_prior_stages() {
let params = set_params_test_params();
let mut context = SetParamsTestContext {
c_params_result: ERROR(ZstdErrorCode::StageWrong),
..SetParamsTestContext::default()
};
let state = set_params_test_state(&mut context);
let result = unsafe { ZSTD_rust_setParams(&state, params) };
assert_eq!(result, ERROR(ZstdErrorCode::StageWrong));
assert_eq!(context.events, ["check", "f-params", "c-params"]);
}
#[test]
fn pledged_src_size_writes_the_init_stage_value_plus_one() {
let mut pledged_src_size_plus_one = 0;