From 56ae331f09b3973d952cc207c308c840b7f7258c Mon Sep 17 00:00:00 2001 From: ddidderr Date: Sat, 18 Jul 2026 08:23:28 +0200 Subject: [PATCH] feat(compress): move block-state confirmation to Rust Keep C ownership of the block-state structure while delegating the confirmed-block pointer swap through a narrow two-pointer ABI leaf. Preserve every existing confirmation call site and add direct pointer-swap coverage. Test Plan: - cargo test --manifest-path rust/Cargo.toml --no-default-features --features compression - cargo clippy --manifest-path rust/Cargo.toml --no-default-features --features compression --all-targets - cargo +nightly fmt --manifest-path rust/Cargo.toml - make -B -C lib -j2 lib - tests/fuzzer -s4560 -t47 -i48 -v - make -C tests -j2 test-zstream --- lib/compress/zstd_compress.c | 8 +++++--- rust/src/zstd_compress_stats.rs | 29 +++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 278b1925c..8c7819947 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -269,6 +269,9 @@ size_t ZSTD_rust_copyBlockSequences( SeqCollector* seqCollector, const SeqStore_t* seqStore, const U32 prevRepcodes[ZSTD_REP_NUM]); void ZSTD_rust_resetCompressedBlockState(ZSTD_compressedBlockState_t* bs); +void ZSTD_rust_confirmRepcodesAndEntropyTables( + ZSTD_compressedBlockState_t** prevCBlock, + ZSTD_compressedBlockState_t** nextCBlock); void ZSTD_rust_storeLastLiterals(SeqStore_t* seqStorePtr, const BYTE* anchor, size_t lastLLSize); void ZSTD_rust_resetSeqStore(SeqStore_t* ssPtr); @@ -2596,9 +2599,8 @@ static int ZSTD_maybeRLE(SeqStore_t const* seqStore) static void ZSTD_blockState_confirmRepcodesAndEntropyTables(ZSTD_blockState_t* const bs) { - ZSTD_compressedBlockState_t* const tmp = bs->prevCBlock; - bs->prevCBlock = bs->nextCBlock; - bs->nextCBlock = tmp; + ZSTD_rust_confirmRepcodesAndEntropyTables( + &bs->prevCBlock, &bs->nextCBlock); } /* Writes the block header */ diff --git a/rust/src/zstd_compress_stats.rs b/rust/src/zstd_compress_stats.rs index 160466f16..53fc13948 100644 --- a/rust/src/zstd_compress_stats.rs +++ b/rust/src/zstd_compress_stats.rs @@ -1095,6 +1095,18 @@ pub unsafe extern "C" fn ZSTD_rust_resetCompressedBlockState( block_state.entropy.fse.litlength_repeatMode = FSE_REPEAT_NONE; } +/// Swaps the two C-owned block-state pointers after a block is confirmed. +/// +/// The enclosing `ZSTD_blockState_t` contains C-only match-state storage, so +/// the ABI deliberately passes only the two pointer fields separately. +#[no_mangle] +pub unsafe extern "C" fn ZSTD_rust_confirmRepcodesAndEntropyTables( + prev_c_block: *mut *mut ZSTD_compressedBlockState_t, + next_c_block: *mut *mut ZSTD_compressedBlockState_t, +) { + unsafe { ptr::swap(prev_c_block, next_c_block) }; +} + /// Appends the final literals of a block to its sequence store. /// /// The source and destination ranges must be valid and non-overlapping, as @@ -3258,6 +3270,23 @@ mod tests { ); } + #[test] + fn confirm_repcodes_and_entropy_tables_swaps_block_state_pointers() { + let mut previous_storage = std::mem::MaybeUninit::::uninit(); + let mut next_storage = std::mem::MaybeUninit::::uninit(); + let previous = previous_storage.as_mut_ptr(); + let next = next_storage.as_mut_ptr(); + let mut previous_ptr = previous; + let mut next_ptr = next; + + unsafe { + ZSTD_rust_confirmRepcodesAndEntropyTables(&mut previous_ptr, &mut next_ptr); + } + + assert_eq!(previous_ptr, next); + assert_eq!(next_ptr, previous); + } + #[test] fn store_last_literals_copies_bytes_and_advances_only_the_literal_cursor() { let mut sequences = [SeqDef::default(); 2];