feat(compress): move frame progression ingestion to Rust

Keep ZSTD_getFrameProgression's multithreaded path and C-owned frame
construction unchanged while moving the single-thread ingested-value
calculation behind the existing scalar C-to-Rust boundary. The Rust helper
accepts the consumed U64 value and buffered size_t value, explicitly converts
the latter to u64, and uses wrapping addition to match C's unsigned
arithmetic. Focused tests cover zero, ordinary, and overflowing inputs.

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` -- passed before and after formatting.
- The same clippy command with `--tests` -- passed before and after formatting.
- `cargo +nightly fmt --manifest-path rust/Cargo.toml` -- passed.
- Focused Rust tests for `frame_progression_ingested` -- 3 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, 5,800, and 9,479 randomized cases.
- `git diff --check` and `git diff --cached --check` -- passed.

The zstream run retains the pre-existing warning at
`tests/zstreamtest.c:1899` about an unterminated initializer string.
This commit is contained in:
2026-07-18 13:03:34 +02:00
parent fcec7d3cc6
commit bf3440aea6
2 changed files with 49 additions and 1 deletions
+2 -1
View File
@@ -48,6 +48,7 @@ int ZSTD_rust_updateFrameProgression(unsigned long long* consumedSrcSize,
unsigned long long pledgedSrcSizePlusOne,
size_t srcSize, size_t cSize,
size_t fhSize);
U64 ZSTD_rust_frameProgressionIngested(U64 consumedSrcSize, size_t buffered);
size_t ZSTD_rust_resetCCtxForSimpleCompression(void* cctx);
size_t ZSTD_rust_prepareCCtxForSimpleCompression(void* cctx,
size_t srcSize,
@@ -1437,7 +1438,7 @@ ZSTD_frameProgression ZSTD_getFrameProgression(const ZSTD_CCtx* cctx)
cctx->inBuffPos - cctx->inToCompress;
if (buffered) assert(cctx->inBuffPos >= cctx->inToCompress);
assert(buffered <= ZSTD_BLOCKSIZE_MAX);
fp.ingested = cctx->consumedSrcSize + buffered;
fp.ingested = ZSTD_rust_frameProgressionIngested(cctx->consumedSrcSize, buffered);
fp.consumed = cctx->consumedSrcSize;
fp.produced = cctx->producedCSize;
fp.flushed = cctx->producedCSize; /* simplified; some data might still be left within streaming output buffer */
+47
View File
@@ -345,6 +345,21 @@ pub unsafe extern "C" fn ZSTD_rust_updateFrameProgression(
) as c_int
}
#[inline]
fn frame_progression_ingested(consumed_src_size: u64, buffered: usize) -> u64 {
// C's usual arithmetic conversions promote size_t to U64 before wrapping.
consumed_src_size.wrapping_add(buffered as u64)
}
/// Calculate single-threaded frame input progression from consumed and buffered input.
#[no_mangle]
pub extern "C" fn ZSTD_rust_frameProgressionIngested(
consumed_src_size: u64,
buffered: usize,
) -> u64 {
frame_progression_ingested(consumed_src_size, buffered)
}
#[inline]
fn next_input_size_hint(
in_buffer_mode: c_int,
@@ -1398,6 +1413,38 @@ mod tests {
assert_eq!(produced, 220);
}
#[test]
fn frame_progression_ingested_handles_zero() {
assert_eq!(frame_progression_ingested(0, 0), 0);
assert_eq!(ZSTD_rust_frameProgressionIngested(0, 0), 0);
}
#[test]
fn frame_progression_ingested_adds_consumed_and_buffered_input() {
let consumed = 11_u64;
let buffered = 37_usize;
let expected = consumed + buffered as u64;
assert_eq!(frame_progression_ingested(consumed, buffered), expected);
assert_eq!(
ZSTD_rust_frameProgressionIngested(consumed, buffered),
expected
);
}
#[test]
fn frame_progression_ingested_wraps_u64() {
let consumed = u64::MAX - 3;
let buffered = 8_usize;
let expected = consumed.wrapping_add(buffered as u64);
assert_eq!(frame_progression_ingested(consumed, buffered), expected);
assert_eq!(
ZSTD_rust_frameProgressionIngested(consumed, buffered),
expected
);
}
#[test]
fn next_input_size_hint_uses_remaining_stable_block_capacity() {
let hint = ZSTD_rust_nextInputSizeHint(ZSTD_BM_STABLE, 256, 37, 99, 12);