From 8919e0d292eae01212e22f41bd30c54442ed1bff Mon Sep 17 00:00:00 2001 From: ddidderr Date: Mon, 20 Jul 2026 13:59:15 +0200 Subject: [PATCH] refactor(mt): export window overlap policy from Rust Move the MT LDM overlap predicate behind the original ZSTDMT_doesOverlapWindow() by-value ABI. Rust now owns the half-open range calculation through a checked representation of Buffer and ZSTD_window_t; C retains the synchronization and context orchestration around the callback. Test Plan: - `cc -fsyntax-only -Ilib -Ilib/common -Ilib/compress -Ilib/decompress -Ilib/dict -Ilib/legacy lib/compress/zstdmt_compress.c` -- passed. - `cargo +nightly fmt --manifest-path rust/Cargo.toml --all -- --check` -- passed. - `git diff --check` and `git diff --cached --check` -- passed. - Heavy verification intentionally deferred until the combined seam set is ready. --- lib/compress/zstdmt_compress.c | 16 +------- rust/src/zstdmt_compress.rs | 68 ++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 15 deletions(-) diff --git a/lib/compress/zstdmt_compress.c b/lib/compress/zstdmt_compress.c index 29acfdb6a..1c3520364 100644 --- a/lib/compress/zstdmt_compress.c +++ b/lib/compress/zstdmt_compress.c @@ -2910,21 +2910,7 @@ static Range ZSTDMT_getInputDataInUse(ZSTDMT_CCtx* mtctx) return (Range){ range.start, range.size }; } -static int ZSTDMT_doesOverlapWindow(Buffer buffer, ZSTD_window_t window) -{ - DEBUGLOG(5, "ZSTDMT_doesOverlapWindow"); - DEBUGLOG(5, "extDict [0x%zx, 0x%zx)", - (size_t)window.dictBase + window.lowLimit, - (size_t)window.dictBase + window.dictLimit); - DEBUGLOG(5, "prefix [0x%zx, 0x%zx)", - (size_t)window.base + window.dictLimit, - (size_t)window.nextSrc); - - return ZSTDMT_rust_doesOverlapWindow(buffer.start, buffer.capacity, - window.nextSrc, window.base, - window.dictBase, window.dictLimit, - window.lowLimit); -} +int ZSTDMT_doesOverlapWindow(Buffer buffer, ZSTD_window_t window); static void ZSTDMT_waitForLdmLock(void* opaque) { diff --git a/rust/src/zstdmt_compress.rs b/rust/src/zstdmt_compress.rs index cdf9b76a8..c5a6ae52e 100644 --- a/rust/src/zstdmt_compress.rs +++ b/rust/src/zstdmt_compress.rs @@ -3420,6 +3420,27 @@ pub struct ZstdMtBuffer { pub capacity: usize, } +/// ABI-compatible representation of the private C `ZSTD_window_t` used by +/// the MT LDM overlap callback. +#[repr(C)] +#[derive(Clone, Copy, Default)] +pub struct ZstdMtWindow { + pub nextSrc: *const u8, + pub base: *const u8, + pub dictBase: *const u8, + pub dictLimit: u32, + pub lowLimit: u32, + pub nbOverflowCorrections: u32, +} + +const _: () = { + assert!(std::mem::offset_of!(ZstdMtWindow, nextSrc) == 0); + assert!(std::mem::offset_of!(ZstdMtWindow, base) == size_of::()); + assert!(std::mem::offset_of!(ZstdMtWindow, dictBase) == 2 * size_of::()); + assert!(std::mem::offset_of!(ZstdMtWindow, dictLimit) == 3 * size_of::()); + assert!(size_of::() == if size_of::() == 8 { 40 } else { 24 }); +}; + /// ABI-compatible representation of `rawSeq` from `zstd_compress_internal.h`. #[repr(C)] #[derive(Clone, Copy, Default)] @@ -3548,6 +3569,24 @@ pub extern "C" fn ZSTDMT_rust_doesOverlapWindow( ) != 0) as c_int } +/// Return non-zero when a buffer overlaps either range in a C window. +/// +/// This keeps the original by-value internal ABI while the scalar helper +/// above remains available to projections that cannot expose the private +/// window layout. +#[no_mangle] +pub extern "C" fn ZSTDMT_doesOverlapWindow(buffer: ZstdMtBuffer, window: ZstdMtWindow) -> c_int { + ZSTDMT_rust_doesOverlapWindow( + buffer.start as *const c_void, + buffer.capacity, + window.nextSrc.cast(), + window.base.cast(), + window.dictBase.cast(), + window.dictLimit, + window.lowLimit, + ) +} + #[derive(Default)] struct BufferPoolState { buffer_size: usize, @@ -7850,6 +7889,35 @@ mod tests { ); } + #[test] + fn direct_overlap_window_abi_matches_scalar_policy() { + let bytes = [0u8; 32]; + let base = bytes.as_ptr(); + let window = ZstdMtWindow { + nextSrc: base.wrapping_add(16), + base, + dictBase: base.wrapping_add(16), + dictLimit: 8, + lowLimit: 4, + nbOverflowCorrections: 0, + }; + let buffer = ZstdMtBuffer { + start: base.wrapping_add(20) as *mut c_void, + capacity: 4, + }; + assert_eq!(ZSTDMT_doesOverlapWindow(buffer, window), 1); + assert_eq!( + ZSTDMT_doesOverlapWindow( + ZstdMtBuffer { + start: base as *mut u8 as *mut c_void, + capacity: 4, + }, + window, + ), + 0 + ); + } + #[test] fn buffer_pool_reuses_and_resizes_buffers() { let pool = unsafe { ZSTDMT_rust_buffer_pool_create(2, DEFAULT_MEM) };