feat(compress): move end-stream estimate to Rust

Keep ZSTD_endStream's streaming call, error propagation, multithreaded
minimal estimate, logging, and context state in C. Move only the final
single-thread estimate behind a scalar Rust ABI helper so the frame-ended
branch and raw checksum flag are explicit while size_t arithmetic wraps as
in C.

Test Plan:
- `cargo clippy --manifest-path rust/Cargo.toml --no-default-features --features compression` -- passed before and after formatting.
- The same clippy command with `--benches` and `--tests` -- passed before and after formatting.
- `cargo +nightly fmt --manifest-path rust/Cargo.toml` -- passed.
- Focused end-stream Rust tests -- 4 passed.
- `make -B -C lib -j2 lib` -- passed.
- `make -C tests test-rust-lib-smoke` -- passed.
- `tests/fuzzer -s4560 -t56 -i57 -v` -- passed.
- `make -C tests -j2 test-zstream` -- passed: 84 named, 6,457, and 8,692 randomized tests. The pre-existing unterminated-string warning remains.
- `git diff --check` and `git diff --cached --check` -- passed.
This commit is contained in:
2026-07-18 12:54:13 +02:00
parent ba7cc52bcc
commit fcec7d3cc6
2 changed files with 54 additions and 3 deletions
+49
View File
@@ -198,6 +198,31 @@ pub extern "C" fn ZSTD_rust_inBufferForEndFlush(
}
}
#[inline]
fn end_stream_remaining(
remaining_to_flush: usize,
frame_ended: c_int,
checksum_flag: c_int,
) -> usize {
if frame_ended != 0 {
return remaining_to_flush;
}
remaining_to_flush
.wrapping_add(ZSTD_BLOCK_HEADER_SIZE)
.wrapping_add((checksum_flag as usize).wrapping_mul(4))
}
/// Estimate single-threaded end-stream output without crossing C context state.
#[no_mangle]
pub extern "C" fn ZSTD_rust_endStreamRemaining(
remaining_to_flush: usize,
frame_ended: c_int,
checksum_flag: c_int,
) -> usize {
end_stream_remaining(remaining_to_flush, frame_ended, checksum_flag)
}
#[inline]
fn check_buffer_stability(
in_buffer_mode: c_int,
@@ -1471,6 +1496,30 @@ mod tests {
}
}
#[test]
fn end_stream_remaining_ignores_estimate_components_after_frame_end() {
assert_eq!(end_stream_remaining(17, 1, 1), 17);
assert_eq!(ZSTD_rust_endStreamRemaining(17, 1, 1), 17);
}
#[test]
fn end_stream_remaining_adds_block_header_without_checksum() {
assert_eq!(end_stream_remaining(17, 0, 0), 20);
assert_eq!(ZSTD_rust_endStreamRemaining(17, 0, 0), 20);
}
#[test]
fn end_stream_remaining_adds_block_header_and_checksum() {
assert_eq!(end_stream_remaining(17, 0, 1), 24);
assert_eq!(ZSTD_rust_endStreamRemaining(17, 0, 1), 24);
}
#[test]
fn end_stream_remaining_wraps_size_t_additions() {
assert_eq!(end_stream_remaining(usize::MAX, 0, 1), 6);
assert_eq!(ZSTD_rust_endStreamRemaining(usize::MAX, 0, 1), 6);
}
#[test]
fn check_buffer_stability_accepts_matching_stable_input() {
let expected_src = b"input".as_ptr().cast::<c_void>();