feat(decompress): invoke trace hooks from Rust

Keep weak-symbol discovery and private dctx/ddict extraction in the C adapter,
but project the exact trace callback types into Rust and invoke them from the
Rust trace lifecycle. Preserve the nullable-hook behavior, trace context
width, dictionary-cold timing, record field layout, size conversions, and the
no-trace build path. Add focused Rust policy tests for callback, record, and
null-projection behavior.

Test Plan:
- ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo check --manifest-path rust/Cargo.toml --tests
- ulimit -v 41943040; make -j1
- ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo clippy --manifest-path rust/cli/Cargo.toml --all-targets -- -D warnings
- ulimit -v 41943040; make -j1 -C tests test
This commit is contained in:
2026-07-21 19:58:11 +02:00
parent 8597c9c4aa
commit 09abf02049
2 changed files with 55 additions and 28 deletions
+46 -8
View File
@@ -358,8 +358,8 @@ const _: () = {
assert!(align_of::<ZSTD_rustDctxView>() == align_of::<usize>());
};
type ZSTD_rustTraceBeginFn = unsafe extern "C" fn(*const c_void) -> u64;
type ZSTD_rustTraceEndFn = unsafe extern "C" fn(u64, *const c_void);
type ZSTD_rustTraceBeginFn = unsafe extern "C" fn(*const ZSTD_DCtx) -> u64;
type ZSTD_rustTraceEndFn = unsafe extern "C" fn(u64, *const ZSTD_rustTrace);
#[repr(C)]
#[derive(Clone, Copy)]
@@ -367,7 +367,7 @@ struct ZSTD_rustDctxTraceView {
trace_ctx: *mut u64,
begin: Option<ZSTD_rustTraceBeginFn>,
end: Option<ZSTD_rustTraceEndFn>,
dctx: *const c_void,
dctx: *const ZSTD_DCtx,
ddict: *const c_void,
dictionary_is_cold: c_int,
}
@@ -386,6 +386,44 @@ struct ZSTD_rustTrace {
dctx: *const c_void,
}
const _: () = {
assert!(offset_of!(ZSTD_rustTrace, version) == 0);
assert!(offset_of!(ZSTD_rustTrace, streaming) == size_of::<c_uint>());
assert!(offset_of!(ZSTD_rustTrace, dictionary_id) == size_of::<c_uint>() + size_of::<c_int>());
assert!(
offset_of!(ZSTD_rustTrace, dictionary_is_cold)
== 2 * size_of::<c_uint>() + size_of::<c_int>()
);
assert!(
offset_of!(ZSTD_rustTrace, dictionary_size)
== 2 * size_of::<c_uint>() + 2 * size_of::<c_int>()
);
assert!(
offset_of!(ZSTD_rustTrace, uncompressed_size)
== offset_of!(ZSTD_rustTrace, dictionary_size) + size_of::<usize>()
);
assert!(
offset_of!(ZSTD_rustTrace, compressed_size)
== offset_of!(ZSTD_rustTrace, dictionary_size) + 2 * size_of::<usize>()
);
assert!(
offset_of!(ZSTD_rustTrace, params)
== offset_of!(ZSTD_rustTrace, dictionary_size) + 3 * size_of::<usize>()
);
assert!(
offset_of!(ZSTD_rustTrace, cctx)
== offset_of!(ZSTD_rustTrace, dictionary_size) + 4 * size_of::<usize>()
);
assert!(
offset_of!(ZSTD_rustTrace, dctx)
== offset_of!(ZSTD_rustTrace, dictionary_size) + 5 * size_of::<usize>()
);
assert!(
size_of::<ZSTD_rustTrace>()
== offset_of!(ZSTD_rustTrace, dictionary_size) + 6 * size_of::<usize>()
);
};
/* Keep this in sync with ZSTD_VERSION_NUMBER in lib/zstd.h. */
const ZSTD_TRACE_VERSION: c_uint = 10_507;
@@ -579,7 +617,7 @@ unsafe fn trace_end_with_view(
compressed_size: compressed_size as usize,
params: ptr::null(),
cctx: ptr::null(),
dctx: view.dctx,
dctx: view.dctx.cast(),
};
if !view.ddict.is_null() {
let ddict = view.ddict.cast::<ZSTD_DDict>();
@@ -587,7 +625,7 @@ unsafe fn trace_end_with_view(
trace.dictionary_size = unsafe { ZSTD_DDict_dictSize(ddict) };
trace.dictionary_is_cold = view.dictionary_is_cold;
}
unsafe { end(trace_ctx, (&mut trace as *mut ZSTD_rustTrace).cast()) };
unsafe { end(trace_ctx, ptr::addr_of!(trace)) };
}
unsafe fn trace_begin(dctx: *mut ZSTD_DCtx) {
@@ -3053,7 +3091,7 @@ mod dctx_trace_tests {
}
}
unsafe extern "C" fn trace_begin_probe(dctx: *const c_void) -> u64 {
unsafe extern "C" fn trace_begin_probe(dctx: *const ZSTD_DCtx) -> u64 {
let probe = dctx.cast::<TraceProbe>();
if probe.is_null() {
return 0;
@@ -3064,11 +3102,11 @@ mod dctx_trace_tests {
0xD1CE
}
unsafe extern "C" fn trace_end_probe(trace_ctx: u64, trace_ptr: *const c_void) {
unsafe extern "C" fn trace_end_probe(trace_ctx: u64, trace_ptr: *const ZSTD_rustTrace) {
if trace_ptr.is_null() {
return;
}
let trace = unsafe { &*trace_ptr.cast::<ZSTD_rustTrace>() };
let trace = unsafe { &*trace_ptr };
let probe = trace.dctx.cast::<TraceProbe>();
if probe.is_null() {
return;