diff --git a/lib/compress/zstd_compress.c b/lib/compress/zstd_compress.c index 048071324..8c8e6e40d 100644 --- a/lib/compress/zstd_compress.c +++ b/lib/compress/zstd_compress.c @@ -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 */ diff --git a/rust/src/zstd_compress.rs b/rust/src/zstd_compress.rs index a7d675c99..5255dd8b4 100644 --- a/rust/src/zstd_compress.rs +++ b/rust/src/zstd_compress.rs @@ -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);