feat(compress): move MT overlap window policy to Rust

Move construction of the external-dictionary and active-prefix ranges into a narrow Rust ABI while retaining the C window and logging surface. Preserve byte-range half-open overlap semantics and leave the input-range overlap wrapper available to its other C caller.

Test Plan: cargo test --manifest-path rust/Cargo.toml --no-default-features --features compression (180 passed); root and CLI clippy; make -B -C lib -j2 lib; make -C tests -j2 test-cli-tests (41 passed); make -B -C tests -j2 test-zstream (84 named tests plus 6,845 and 9,628 fuzz cases passed).
This commit is contained in:
2026-07-18 04:43:41 +02:00
parent 2cd0b29790
commit d9fe5d25ab
2 changed files with 93 additions and 14 deletions
+82
View File
@@ -250,6 +250,43 @@ pub extern "C" fn ZSTDMT_rust_isOverlapped(
is_overlapped(bufferStart, bufferCapacity, rangeStart, rangeSize)
}
/// Return non-zero when a buffer overlaps either the external dictionary or
/// the active prefix represented by a C `ZSTD_window_t`.
///
/// The C window stores the two ranges as pointer/index pairs. Passing those
/// scalar fields separately keeps the private C struct out of the Rust ABI;
/// the byte-distance arithmetic mirrors the original pointer subtraction.
#[no_mangle]
pub extern "C" fn ZSTDMT_rust_doesOverlapWindow(
bufferStart: *const c_void,
bufferCapacity: usize,
nextSrc: *const c_void,
base: *const c_void,
dictBase: *const c_void,
dictLimit: u32,
lowLimit: u32,
) -> c_int {
let ext_dict_start = dictBase.cast::<u8>().wrapping_add(lowLimit as usize);
let ext_dict_size = dictLimit.wrapping_sub(lowLimit) as usize;
let prefix_start = base.cast::<u8>().wrapping_add(dictLimit as usize);
let prefix_size = (nextSrc as usize)
.wrapping_sub(base as usize)
.wrapping_sub(dictLimit as usize);
(is_overlapped(
bufferStart,
bufferCapacity,
ext_dict_start.cast(),
ext_dict_size,
) != 0
|| is_overlapped(
bufferStart,
bufferCapacity,
prefix_start.cast(),
prefix_size,
) != 0) as c_int
}
#[derive(Default)]
struct BufferPoolState {
buffer_size: usize,
@@ -926,6 +963,51 @@ mod tests {
);
}
#[test]
fn overlap_window_checks_external_dictionary_and_prefix() {
let bytes = [0u8; 32];
let base = bytes.as_ptr();
let next_src = base.wrapping_add(16);
let dict_base = base.wrapping_add(16);
assert_eq!(
ZSTDMT_rust_doesOverlapWindow(
base.wrapping_add(20).cast(),
4,
next_src.cast(),
base.cast(),
dict_base.cast(),
8,
4,
),
1
);
assert_eq!(
ZSTDMT_rust_doesOverlapWindow(
base.wrapping_add(12).cast(),
4,
next_src.cast(),
base.cast(),
dict_base.cast(),
8,
4,
),
1
);
assert_eq!(
ZSTDMT_rust_doesOverlapWindow(
base.cast(),
4,
next_src.cast(),
base.cast(),
dict_base.cast(),
8,
4,
),
0
);
}
#[test]
fn buffer_pool_reuses_and_resizes_buffers() {
let pool = unsafe { ZSTDMT_rust_buffer_pool_create(2, DEFAULT_MEM) };