feat(compress): return frame progression from Rust

Complete the single-thread branch of ZSTD_getFrameProgression behind a
narrow scalar ABI boundary. C still owns the public entry point, buffered
input extraction, assertions, and the multithreaded dispatch; Rust now owns
the six-field single-thread result construction. The Rust #[repr(C)] result
uses wrapping u64 conversion for consumed input plus buffered size, mirrors
produced into flushed, and zeros the MT-only fields.

This replaces the earlier ingested-only helper so the ABI no longer splits
one result across duplicate C and Rust construction paths. The unit tests now
cover the complete result and its u64 wrapping behavior.

Test Plan:
- All three requested compression clippy commands passed before and after
  `cargo +nightly fmt --manifest-path rust/Cargo.toml`.
- `cargo test --manifest-path rust/Cargo.toml --no-default-features
  --features compression` -- 327 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,330, and 9,772
  randomized cases.
- `git diff --check` and `git diff --cached --check` -- passed.

The zstream build retains the pre-existing warning at
`tests/zstreamtest.c:1899` about an unterminated initializer string.
This commit is contained in:
2026-07-18 13:50:36 +02:00
parent c0038a8aaa
commit 4c114b8e7b
2 changed files with 61 additions and 37 deletions
+7 -10
View File
@@ -48,7 +48,9 @@ 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);
ZSTD_frameProgression ZSTD_rust_frameProgression(U64 consumedSrcSize,
size_t buffered,
U64 producedCSize);
size_t ZSTD_rust_resetCCtxForSimpleCompression(void* cctx);
size_t ZSTD_rust_prepareCCtxForSimpleCompression(void* cctx,
size_t srcSize,
@@ -1436,19 +1438,14 @@ ZSTD_frameProgression ZSTD_getFrameProgression(const ZSTD_CCtx* cctx)
return ZSTDMT_getFrameProgression(cctx->mtctx);
}
#endif
{ ZSTD_frameProgression fp;
{
size_t const buffered = (cctx->inBuff == NULL) ? 0 :
cctx->inBuffPos - cctx->inToCompress;
if (buffered) assert(cctx->inBuffPos >= cctx->inToCompress);
assert(buffered <= ZSTD_BLOCKSIZE_MAX);
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 */
fp.currentJobID = 0;
fp.nbActiveWorkers = 0;
return fp;
} }
return ZSTD_rust_frameProgression(cctx->consumedSrcSize, buffered,
cctx->producedCSize);
} }
/*! ZSTD_toFlushNow()
* Only useful for multithreading scenarios currently (nbWorkers >= 1).
+54 -27
View File
@@ -29,7 +29,7 @@ use crate::zstd_compress_stats::{SeqStore_t, ZSTD_compressedBlockState_t};
use crate::zstd_compress_superblock::ZSTD_rust_compressSuperBlock;
use std::ffi::c_void;
use std::mem::{size_of, MaybeUninit};
use std::os::raw::c_int;
use std::os::raw::{c_int, c_uint};
use std::ptr;
#[cfg(not(test))]
@@ -345,19 +345,43 @@ 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)
/// ABI-compatible representation of `ZSTD_frameProgression` from `zstd.h`.
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct ZSTD_frameProgression {
pub ingested: u64,
pub consumed: u64,
pub produced: u64,
pub flushed: u64,
pub currentJobID: c_uint,
pub nbActiveWorkers: c_uint,
}
/// Calculate single-threaded frame input progression from consumed and buffered input.
#[no_mangle]
pub extern "C" fn ZSTD_rust_frameProgressionIngested(
#[inline]
fn frame_progression(
consumed_src_size: u64,
buffered: usize,
) -> u64 {
frame_progression_ingested(consumed_src_size, buffered)
produced_c_size: u64,
) -> ZSTD_frameProgression {
ZSTD_frameProgression {
// C's usual arithmetic conversions promote size_t to U64 before wrapping.
ingested: consumed_src_size.wrapping_add(buffered as u64),
consumed: consumed_src_size,
produced: produced_c_size,
flushed: produced_c_size,
currentJobID: 0,
nbActiveWorkers: 0,
}
}
/// Construct single-threaded frame progression from C-owned scalar state.
#[no_mangle]
pub extern "C" fn ZSTD_rust_frameProgression(
consumed_src_size: u64,
buffered: usize,
produced_c_size: u64,
) -> ZSTD_frameProgression {
frame_progression(consumed_src_size, buffered, produced_c_size)
}
#[inline]
@@ -1435,35 +1459,38 @@ mod tests {
}
#[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() {
fn frame_progression_constructs_single_thread_values() {
let consumed = 11_u64;
let buffered = 37_usize;
let expected = consumed + buffered as u64;
let produced = 53_u64;
let expected = ZSTD_frameProgression {
ingested: consumed + buffered as u64,
consumed,
produced,
flushed: produced,
currentJobID: 0,
nbActiveWorkers: 0,
};
assert_eq!(frame_progression_ingested(consumed, buffered), expected);
assert_eq!(frame_progression(consumed, buffered, produced), expected);
assert_eq!(
ZSTD_rust_frameProgressionIngested(consumed, buffered),
ZSTD_rust_frameProgression(consumed, buffered, produced),
expected
);
}
#[test]
fn frame_progression_ingested_wraps_u64() {
fn frame_progression_wraps_buffered_input_to_u64() {
let consumed = u64::MAX - 3;
let buffered = 8_usize;
let expected = consumed.wrapping_add(buffered as u64);
let progression = ZSTD_rust_frameProgression(consumed, buffered, 17);
assert_eq!(frame_progression_ingested(consumed, buffered), expected);
assert_eq!(
ZSTD_rust_frameProgressionIngested(consumed, buffered),
expected
);
assert_eq!(progression.ingested, consumed.wrapping_add(buffered as u64));
assert_eq!(progression.consumed, consumed);
assert_eq!(progression.produced, 17);
assert_eq!(progression.flushed, 17);
assert_eq!(progression.currentJobID, 0);
assert_eq!(progression.nbActiveWorkers, 0);
}
#[test]