feat(compress): move stored parameter policy into Rust
Move ZSTD_CCtx_setParametersUsingCCtxParams stage, dictionary, and copy policy into a Rust-owned ABI bridge while retaining C-owned parameter object storage. Preserve stage-before-dictionary validation, error codes, and no-mutation behavior on rejected calls. Test Plan: - cargo test --manifest-path rust/Cargo.toml --lib - cargo clippy --manifest-path rust/Cargo.toml --all-targets -- -D warnings - make -B -C programs -j1 zstd - make -C tests -j1 test-zstream ZSTREAM_TESTTIME=-T1s - focused set_parameters_using_cctx_params unit tests
This commit is contained in:
@@ -247,6 +247,25 @@ typedef char ZSTD_rust_set_params_state_layout[
|
|||||||
&& offsetof(ZSTD_rust_setParamsState, setCParams) == 3 * sizeof(void*)
|
&& offsetof(ZSTD_rust_setParamsState, setCParams) == 3 * sizeof(void*)
|
||||||
&& sizeof(ZSTD_rust_setParamsState) == 4 * sizeof(void*))
|
&& sizeof(ZSTD_rust_setParamsState) == 4 * sizeof(void*))
|
||||||
? 1 : -1];
|
? 1 : -1];
|
||||||
|
typedef struct {
|
||||||
|
ZSTD_CCtx_params* requestedParams;
|
||||||
|
const ZSTD_CCtx_params* sourceParams;
|
||||||
|
int streamStage;
|
||||||
|
const void* cdict;
|
||||||
|
} ZSTD_rust_setParametersUsingCCtxParamsState;
|
||||||
|
size_t ZSTD_rust_setParametersUsingCCtxParams(
|
||||||
|
const ZSTD_rust_setParametersUsingCCtxParamsState* state);
|
||||||
|
typedef char ZSTD_rust_set_parameters_using_cctx_params_state_layout[
|
||||||
|
(offsetof(ZSTD_rust_setParametersUsingCCtxParamsState, requestedParams) == 0
|
||||||
|
&& offsetof(ZSTD_rust_setParametersUsingCCtxParamsState, sourceParams)
|
||||||
|
== sizeof(void*)
|
||||||
|
&& offsetof(ZSTD_rust_setParametersUsingCCtxParamsState, streamStage)
|
||||||
|
== 2 * sizeof(void*)
|
||||||
|
&& offsetof(ZSTD_rust_setParametersUsingCCtxParamsState, cdict)
|
||||||
|
== 3 * sizeof(void*)
|
||||||
|
&& sizeof(ZSTD_rust_setParametersUsingCCtxParamsState)
|
||||||
|
== 4 * sizeof(void*))
|
||||||
|
? 1 : -1];
|
||||||
typedef void (*ZSTD_rust_resetCCtxClearAllDicts_f)(void* context);
|
typedef void (*ZSTD_rust_resetCCtxClearAllDicts_f)(void* context);
|
||||||
typedef size_t (*ZSTD_rust_resetCCtxResetParams_f)(void* context);
|
typedef size_t (*ZSTD_rust_resetCCtxResetParams_f)(void* context);
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -1942,14 +1961,11 @@ size_t ZSTD_CCtx_setParametersUsingCCtxParams(
|
|||||||
ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params)
|
ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params)
|
||||||
{
|
{
|
||||||
DEBUGLOG(4, "ZSTD_CCtx_setParametersUsingCCtxParams");
|
DEBUGLOG(4, "ZSTD_CCtx_setParametersUsingCCtxParams");
|
||||||
RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong,
|
{ ZSTD_rust_setParametersUsingCCtxParamsState const state = {
|
||||||
"The context is in the wrong stage!");
|
&cctx->requestedParams, params, (int)cctx->streamStage, cctx->cdict
|
||||||
RETURN_ERROR_IF(cctx->cdict, stage_wrong,
|
};
|
||||||
"Can't override parameters with cdict attached (some must "
|
return ZSTD_rust_setParametersUsingCCtxParams(&state);
|
||||||
"be inherited from the cdict).");
|
}
|
||||||
|
|
||||||
cctx->requestedParams = *params;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t ZSTD_rust_setCParams_checkCParams(
|
static size_t ZSTD_rust_setCParams_checkCParams(
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ use crate::zstd_compress_params::{
|
|||||||
ZSTD_rust_params_adjustCParams, ZSTD_rust_params_maxNbSeq, ZSTD_rust_params_selectCParams,
|
ZSTD_rust_params_adjustCParams, ZSTD_rust_params_maxNbSeq, ZSTD_rust_params_selectCParams,
|
||||||
ZSTD_RUST_CPM_NO_ATTACH_DICT, ZSTD_RUST_PS_AUTO, ZSTD_RUST_PS_DISABLE,
|
ZSTD_RUST_CPM_NO_ATTACH_DICT, ZSTD_RUST_PS_AUTO, ZSTD_RUST_PS_DISABLE,
|
||||||
};
|
};
|
||||||
|
use crate::zstd_compress_params_api::ZSTD_CCtx_params;
|
||||||
use crate::zstd_compress_sequences::SeqDef;
|
use crate::zstd_compress_sequences::SeqDef;
|
||||||
use crate::zstd_compress_stats::{
|
use crate::zstd_compress_stats::{
|
||||||
update_rep, SeqCollector, SeqStore_t, ZSTD_Sequence, ZSTD_SequencePosition,
|
update_rep, SeqCollector, SeqStore_t, ZSTD_Sequence, ZSTD_SequencePosition,
|
||||||
@@ -817,6 +818,60 @@ pub unsafe extern "C" fn ZSTD_rust_compress2(
|
|||||||
unsafe { compress2_body_with(&*state, dst, dst_capacity, src, src_size) }
|
unsafe { compress2_body_with(&*state, dst, dst_capacity, src, src_size) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Explicit projection for `ZSTD_CCtx_setParametersUsingCCtxParams`.
|
||||||
|
///
|
||||||
|
/// Rust owns the stage and dictionary policy while the C-owned parameter
|
||||||
|
/// objects cross the ABI as pointers to the shared layout mirror.
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct ZSTD_rust_setParametersUsingCCtxParamsState {
|
||||||
|
requested_params: *mut ZSTD_CCtx_params,
|
||||||
|
source_params: *const ZSTD_CCtx_params,
|
||||||
|
stream_stage: c_int,
|
||||||
|
cdict: *const c_void,
|
||||||
|
}
|
||||||
|
|
||||||
|
const _: () = {
|
||||||
|
assert!(
|
||||||
|
offset_of!(
|
||||||
|
ZSTD_rust_setParametersUsingCCtxParamsState,
|
||||||
|
requested_params
|
||||||
|
) == 0
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
offset_of!(ZSTD_rust_setParametersUsingCCtxParamsState, source_params)
|
||||||
|
== size_of::<usize>()
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
offset_of!(ZSTD_rust_setParametersUsingCCtxParamsState, stream_stage)
|
||||||
|
== 2 * size_of::<usize>()
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
offset_of!(ZSTD_rust_setParametersUsingCCtxParamsState, cdict) == 3 * size_of::<usize>()
|
||||||
|
);
|
||||||
|
assert!(size_of::<ZSTD_rust_setParametersUsingCCtxParamsState>() == 4 * size_of::<usize>());
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Apply stored parameters through the C-owned context projection.
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn ZSTD_rust_setParametersUsingCCtxParams(
|
||||||
|
state: *const ZSTD_rust_setParametersUsingCCtxParamsState,
|
||||||
|
) -> usize {
|
||||||
|
if state.is_null() {
|
||||||
|
return ERROR(ZstdErrorCode::Generic);
|
||||||
|
}
|
||||||
|
let state = unsafe { &*state };
|
||||||
|
if state.stream_stage != ZSTD_CSTREAM_STAGE_INIT {
|
||||||
|
return ERROR(ZstdErrorCode::StageWrong);
|
||||||
|
}
|
||||||
|
if !state.cdict.is_null() {
|
||||||
|
return ERROR(ZstdErrorCode::StageWrong);
|
||||||
|
}
|
||||||
|
unsafe {
|
||||||
|
*state.requested_params = *state.source_params;
|
||||||
|
}
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
type ResetCCtxClearAllDictsFn = unsafe extern "C" fn(*mut c_void);
|
type ResetCCtxClearAllDictsFn = unsafe extern "C" fn(*mut c_void);
|
||||||
type ResetCCtxResetParamsFn = unsafe extern "C" fn(*mut c_void) -> usize;
|
type ResetCCtxResetParamsFn = unsafe extern "C" fn(*mut c_void) -> usize;
|
||||||
|
|
||||||
@@ -5745,6 +5800,9 @@ pub unsafe extern "C" fn ZSTD_compressStream2(
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::errors::ERR_getErrorCode;
|
use crate::errors::ERR_getErrorCode;
|
||||||
|
use crate::zstd_compress_params_api::{
|
||||||
|
ZSTD_CCtxParams_getParameter, ZSTD_CCtxParams_setParameter,
|
||||||
|
};
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::process::{Command, Stdio};
|
use std::process::{Command, Stdio};
|
||||||
|
|
||||||
@@ -10019,6 +10077,109 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_parameters_using_cctx_params_test_value(params: &ZSTD_CCtx_params) -> c_int {
|
||||||
|
let mut value = -1;
|
||||||
|
let result = unsafe { ZSTD_CCtxParams_getParameter(params, 10, &mut value) };
|
||||||
|
assert_eq!(result, 0);
|
||||||
|
value
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_parameters_using_cctx_params_test_state(
|
||||||
|
requested_params: &mut ZSTD_CCtx_params,
|
||||||
|
source_params: &ZSTD_CCtx_params,
|
||||||
|
stream_stage: c_int,
|
||||||
|
cdict: *const c_void,
|
||||||
|
) -> ZSTD_rust_setParametersUsingCCtxParamsState {
|
||||||
|
ZSTD_rust_setParametersUsingCCtxParamsState {
|
||||||
|
requested_params,
|
||||||
|
source_params,
|
||||||
|
stream_stage,
|
||||||
|
cdict,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn set_parameters_using_cctx_params_copies_source_after_policy_checks() {
|
||||||
|
let mut source_params = unsafe { MaybeUninit::<ZSTD_CCtx_params>::zeroed().assume_init() };
|
||||||
|
let mut requested_params =
|
||||||
|
unsafe { MaybeUninit::<ZSTD_CCtx_params>::zeroed().assume_init() };
|
||||||
|
assert_eq!(
|
||||||
|
unsafe { ZSTD_CCtxParams_setParameter(&mut source_params, 10, 1) },
|
||||||
|
1
|
||||||
|
);
|
||||||
|
let state = set_parameters_using_cctx_params_test_state(
|
||||||
|
&mut requested_params,
|
||||||
|
&source_params,
|
||||||
|
ZSTD_CSTREAM_STAGE_INIT,
|
||||||
|
ptr::null(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let result = unsafe { ZSTD_rust_setParametersUsingCCtxParams(&state) };
|
||||||
|
|
||||||
|
assert_eq!(result, 0);
|
||||||
|
assert_eq!(
|
||||||
|
set_parameters_using_cctx_params_test_value(&requested_params),
|
||||||
|
1
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn set_parameters_using_cctx_params_rejects_non_init_stage_without_copying() {
|
||||||
|
let mut source_params = unsafe { MaybeUninit::<ZSTD_CCtx_params>::zeroed().assume_init() };
|
||||||
|
let mut requested_params =
|
||||||
|
unsafe { MaybeUninit::<ZSTD_CCtx_params>::zeroed().assume_init() };
|
||||||
|
assert_eq!(
|
||||||
|
unsafe { ZSTD_CCtxParams_setParameter(&mut source_params, 10, 1) },
|
||||||
|
1
|
||||||
|
);
|
||||||
|
let state = set_parameters_using_cctx_params_test_state(
|
||||||
|
&mut requested_params,
|
||||||
|
&source_params,
|
||||||
|
ZSTD_CSTREAM_STAGE_LOAD,
|
||||||
|
ptr::null(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let result = unsafe { ZSTD_rust_setParametersUsingCCtxParams(&state) };
|
||||||
|
|
||||||
|
assert_eq!(result, ERROR(ZstdErrorCode::StageWrong));
|
||||||
|
assert_eq!(
|
||||||
|
set_parameters_using_cctx_params_test_value(&requested_params),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn set_parameters_using_cctx_params_rejects_cdict_without_copying() {
|
||||||
|
let mut source_params = unsafe { MaybeUninit::<ZSTD_CCtx_params>::zeroed().assume_init() };
|
||||||
|
let mut requested_params =
|
||||||
|
unsafe { MaybeUninit::<ZSTD_CCtx_params>::zeroed().assume_init() };
|
||||||
|
assert_eq!(
|
||||||
|
unsafe { ZSTD_CCtxParams_setParameter(&mut source_params, 10, 1) },
|
||||||
|
1
|
||||||
|
);
|
||||||
|
let state = set_parameters_using_cctx_params_test_state(
|
||||||
|
&mut requested_params,
|
||||||
|
&source_params,
|
||||||
|
ZSTD_CSTREAM_STAGE_INIT,
|
||||||
|
ptr::dangling(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let result = unsafe { ZSTD_rust_setParametersUsingCCtxParams(&state) };
|
||||||
|
|
||||||
|
assert_eq!(result, ERROR(ZstdErrorCode::StageWrong));
|
||||||
|
assert_eq!(
|
||||||
|
set_parameters_using_cctx_params_test_value(&requested_params),
|
||||||
|
0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn set_parameters_using_cctx_params_rejects_null_state() {
|
||||||
|
let result = unsafe { ZSTD_rust_setParametersUsingCCtxParams(ptr::null()) };
|
||||||
|
|
||||||
|
assert_eq!(result, ERROR(ZstdErrorCode::Generic));
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct SetCParamsTestContext {
|
struct SetCParamsTestContext {
|
||||||
events: Vec<&'static str>,
|
events: Vec<&'static str>,
|
||||||
|
|||||||
Reference in New Issue
Block a user