feat(compress): move CDict query leaves into Rust

Move CDict compression-parameter and dictionary-ID snapshot reads behind a
Rust-owned projection while retaining the private C field access and the
existing non-null assertion for ZSTD_getCParamsFromCDict. Preserve the public
NULL dictionary-ID result and ABI-compatible compression-parameter return.

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 cdict_query_projection unit tests
This commit is contained in:
2026-07-19 14:26:34 +02:00
parent 993fd0acbe
commit 724c7c60fa
2 changed files with 104 additions and 3 deletions
+83
View File
@@ -232,6 +232,49 @@ pub unsafe extern "C" fn ZSTD_rust_compressBeginUsingCDict(
}
}
/// Scalar projections for the public CDict query helpers.
#[repr(C)]
pub struct ZSTD_rust_cdictQueryState {
c_params: *const ZSTD_compressionParameters,
dict_id: *const c_uint,
}
const _: () = {
assert!(offset_of!(ZSTD_rust_cdictQueryState, c_params) == 0);
assert!(offset_of!(ZSTD_rust_cdictQueryState, dict_id) == size_of::<usize>());
assert!(size_of::<ZSTD_rust_cdictQueryState>() == 2 * size_of::<usize>());
};
/// Return a copied compression-parameter snapshot from a CDict projection.
#[no_mangle]
pub unsafe extern "C" fn ZSTD_rust_getCParamsFromCDict(
state: *const ZSTD_rust_cdictQueryState,
) -> ZSTD_compressionParameters {
if state.is_null() {
return ZSTD_compressionParameters::default();
}
let state = unsafe { &*state };
if state.c_params.is_null() {
return ZSTD_compressionParameters::default();
}
unsafe { *state.c_params }
}
/// Return the dictionary ID from a CDict projection, preserving NULL -> 0.
#[no_mangle]
pub unsafe extern "C" fn ZSTD_rust_getDictIDFromCDict(
state: *const ZSTD_rust_cdictQueryState,
) -> c_uint {
if state.is_null() {
return 0;
}
let state = unsafe { &*state };
if state.dict_id.is_null() {
return 0;
}
unsafe { *state.dict_id }
}
/// Rust-owned policy for `ZSTD_CCtx_loadDictionary_advanced()`.
#[no_mangle]
pub unsafe extern "C" fn ZSTD_rust_CCtx_loadDictionaryAdvanced(
@@ -891,6 +934,46 @@ mod tests {
assert_eq!(probe.events, [3]);
}
#[test]
fn cdict_query_projection_returns_private_snapshots() {
let cparams = ZSTD_compressionParameters {
windowLog: 17,
chainLog: 12,
hashLog: 13,
searchLog: 1,
minMatch: 4,
targetLength: 16,
strategy: 3,
};
let dict_id = 0x1234_5678;
let state = ZSTD_rust_cdictQueryState {
c_params: &cparams,
dict_id: &dict_id,
};
assert_eq!(unsafe { ZSTD_rust_getCParamsFromCDict(&state) }, cparams);
assert_eq!(unsafe { ZSTD_rust_getDictIDFromCDict(&state) }, dict_id);
}
#[test]
fn cdict_query_projection_handles_missing_snapshots() {
let state = ZSTD_rust_cdictQueryState {
c_params: ptr::null(),
dict_id: ptr::null(),
};
assert_eq!(
unsafe { ZSTD_rust_getCParamsFromCDict(&state) },
ZSTD_compressionParameters::default()
);
assert_eq!(unsafe { ZSTD_rust_getDictIDFromCDict(&state) }, 0);
assert_eq!(
unsafe { ZSTD_rust_getCParamsFromCDict(ptr::null()) },
ZSTD_compressionParameters::default()
);
assert_eq!(unsafe { ZSTD_rust_getDictIDFromCDict(ptr::null()) }, 0);
}
#[derive(Default)]
struct CdictBeginProbe {
events: Vec<&'static str>,