feat(compress): move deprecated block adapter into Rust

Project the existing sequence-store and block-internal states through the
continue context so Rust builds deprecated blocks and enters the migrated
block leaf directly. Remove the C forwarding adapter while retaining the
private matchfinder and CCtx callbacks behind the existing build projection.

Test Plan:
- ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo fmt --all -- --check
- ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo test --lib zstd_compress::tests::compress_continue -- --nocapture
- ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo clippy --all-targets -- -D warnings
- ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo test
- ulimit -v 41943040; make -j1
- ulimit -v 41943040; make -j1 -C tests test-zstream ZSTREAM_TESTTIME=-T2s
- ulimit -v 41943040; make -j1 -C tests test-fuzzer FUZZERTEST=-T3s FUZZER_FLAGS=--no-big-tests
This commit is contained in:
2026-07-20 01:15:02 +02:00
parent 6da0296af6
commit ad49e4466c
2 changed files with 138 additions and 16 deletions
+108 -4
View File
@@ -796,6 +796,24 @@ pub unsafe extern "C" fn ZSTD_rust_compressFrameChunk(
type CompressContinueBlockFn =
unsafe extern "C" fn(*mut c_void, *mut c_void, usize, *const c_void, usize, c_uint) -> usize;
/// Explicit projection for the deprecated block adapter. Rust builds the
/// sequence store and then enters the already-Rust-owned block body; the
/// projected states retain only the matchfinder and CCtx storage callbacks.
#[repr(C)]
struct ZSTD_rust_compressContinueBlockState {
build_seq_store_state: *const ZSTD_rust_buildSeqStoreState,
block_internal_state: *const ZSTD_rust_blockInternalState,
}
const _: () = {
assert!(offset_of!(ZSTD_rust_compressContinueBlockState, build_seq_store_state) == 0);
assert!(
offset_of!(ZSTD_rust_compressContinueBlockState, block_internal_state)
== size_of::<usize>()
);
assert!(size_of::<ZSTD_rust_compressContinueBlockState>() == 2 * size_of::<usize>());
};
/// Pointer projection for one C-owned `ZSTD_window_t` and the match-state
/// fields which follow its update. Each field points directly at the C
/// storage so later callbacks observe the updated window immediately.
@@ -942,6 +960,39 @@ const ZSTD_COMPRESSION_STAGE_ONGOING: c_int = 2;
#[cfg(test)]
const ZSTD_COMPRESSION_STAGE_ENDING: c_int = 3;
#[no_mangle]
pub unsafe extern "C" fn ZSTD_rust_compressContinueBlock(
context: *mut c_void,
dst: *mut c_void,
dst_capacity: usize,
src: *const c_void,
src_size: usize,
_last_frame_chunk: c_uint,
) -> usize {
if context.is_null() {
return ERROR(ZstdErrorCode::Generic);
}
let state = unsafe { &*context.cast::<ZSTD_rust_compressContinueBlockState>() };
if state.build_seq_store_state.is_null() || state.block_internal_state.is_null() {
return ERROR(ZstdErrorCode::Generic);
}
let bss = unsafe { ZSTD_rust_buildSeqStore(state.build_seq_store_state, src, src_size) };
if ERR_isError(bss) {
return bss;
}
unsafe {
ZSTD_rust_compressBlockInternalAfterBuild(
state.block_internal_state,
dst,
dst_capacity,
src,
src_size,
0,
bss as c_int,
)
}
}
unsafe fn compress_continue_update_window(
projection: *const ZSTD_rust_compressContinueWindowProjection,
src: *const c_void,
@@ -4097,10 +4148,10 @@ const _: () = {
/// Explicit projection of the state used by `ZSTD_compressBlock_internal`.
///
/// Sequence-store construction and the no-compress fallback remain in C.
/// Rust owns sequence collection, entropy emission, the legacy first-block
/// RLE gate, and the compressed-block state transitions after the store is
/// ready.
/// Sequence-store construction enters through an explicit build-state
/// projection. Rust owns sequence collection, entropy emission, the legacy
/// first-block RLE gate, and the compressed-block state transitions after the
/// store is ready.
#[repr(C)]
pub struct ZSTD_rust_blockInternalState {
seq_store: *const SeqStore_t,
@@ -11525,6 +11576,59 @@ mod tests {
}
}
#[test]
fn compress_continue_block_builds_small_block_through_projected_states() {
let mut probe = BuildSeqStoreSelectProbe::default();
let mut seq_store = unsafe { MaybeUninit::<SeqStore_t>::zeroed().assume_init() };
let mut build_state = build_seq_store_select_test_state(&mut probe, 0, 0, 0, 0);
build_state.seq_store = &mut seq_store;
let mut prev_block = zeroed_state();
let mut next_block = zeroed_state();
let mut prev_c_block = &mut prev_block as *mut _;
let mut next_c_block = &mut next_block as *mut _;
let mut seq_collector = SeqCollector {
collectSequences: 0,
seqStart: ptr::null_mut(),
seqIndex: 0,
maxSequences: 0,
};
let block_state = ZSTD_rust_blockInternalState {
seq_store: &seq_store,
prev_c_block: &mut prev_c_block,
next_c_block: &mut next_c_block,
tmp_workspace: ptr::null_mut(),
tmp_wksp_size: 0,
seq_collector: &mut seq_collector,
strategy: 0,
disable_literal_compression: 0,
bmi2: 0,
is_first_block: 1,
};
let state = ZSTD_rust_compressContinueBlockState {
build_seq_store_state: &build_state,
block_internal_state: &block_state,
};
let source = [0u8; 1];
let mut output = [0xa5u8; 8];
let result = unsafe {
ZSTD_rust_compressContinueBlock(
(&state as *const ZSTD_rust_compressContinueBlockState)
.cast_mut()
.cast(),
output.as_mut_ptr().cast(),
output.len(),
source.as_ptr().cast(),
source.len(),
0,
)
};
assert_eq!(result, 0);
assert_eq!(output, [0xa5; 8]);
}
#[test]
fn compress_continue_starts_frame_and_updates_progression() {
let mut context = CompressContinueTestContext {