refactor(compress): move stream fast-path policy to Rust

Project the private stream state needed by the complete-input streaming fast
path into a stable C/Rust layout and let Rust own the eligibility predicate.
The C bridge keeps the CCtx private and retains the existing simple-level
selection leaf as a callback, while focused tests cover the accepted and
rejected stream states.

All heavy verification was run serially with a 40 GiB virtual-memory cap and
one build job.

Test Plan:
- git diff --cached --check
- ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo clippy --manifest-path rust/Cargo.toml --all-targets -- -D warnings
- ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo test --manifest-path rust/Cargo.toml --all-targets (788 passed)
- ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo clippy --manifest-path rust/cli/Cargo.toml --all-targets -- -D warnings
- ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo test --manifest-path rust/cli/Cargo.toml --all-targets (181 passed)
- ulimit -v 41943040; cargo +nightly fmt --manifest-path rust/Cargo.toml --all -- --check
- ulimit -v 41943040; make -j1
- ulimit -v 41943040; make -j1 -C tests test
This commit is contained in:
2026-07-20 07:56:08 +02:00
parent 429694a250
commit 9c46e18172
2 changed files with 157 additions and 7 deletions
+26 -7
View File
@@ -731,6 +731,25 @@ size_t ZSTD_compressStream2_c(ZSTD_CCtx* cctx,
ZSTD_inBuffer* input,
ZSTD_EndDirective endOp);
int ZSTD_rust_simpleCompress2Level(const void* cctx, size_t srcSize);
typedef int (*ZSTD_rust_simpleCompress2Level_f)(const void* cctx, size_t srcSize);
typedef struct {
int streamStage;
unsigned long long pledgedSrcSizePlusOne;
unsigned rustSimpleCompress2Completed;
} ZSTD_rust_simpleCompressStream2Projection;
typedef char ZSTD_rust_simple_compress_stream2_projection_layout[
(offsetof(ZSTD_rust_simpleCompressStream2Projection, streamStage) == 0
&& offsetof(ZSTD_rust_simpleCompressStream2Projection, pledgedSrcSizePlusOne)
== (sizeof(void*) == 8 ? 8 : 4)
&& offsetof(ZSTD_rust_simpleCompressStream2Projection,
rustSimpleCompress2Completed)
== (sizeof(void*) == 8 ? 16 : 12)
&& sizeof(ZSTD_rust_simpleCompressStream2Projection)
== (sizeof(void*) == 8 ? 24 : 16)) ? 1 : -1];
int ZSTD_rust_simpleCompressStream2Policy(
const ZSTD_rust_simpleCompressStream2Projection* projection,
const void* cctx, size_t srcSize,
ZSTD_rust_simpleCompress2Level_f simpleCompress2Level);
int ZSTD_rust_simpleCompressStream2Level(const void* cctx, size_t srcSize);
U32 ZSTD_rust_limitNextToUpdate(U32 curr, U32 nextToUpdate);
void ZSTD_rust_advanceHashSaltInPlace(U64* hashSalt, U64 hashSaltEntropy);
@@ -6888,13 +6907,13 @@ int ZSTD_rust_simpleCompress2Level(const void* opaqueCctx, size_t srcSize)
int ZSTD_rust_simpleCompressStream2Level(const void* opaqueCctx, size_t srcSize)
{
ZSTD_CCtx const* const cctx = (ZSTD_CCtx const*)opaqueCctx;
if (cctx == NULL
|| cctx->streamStage != zcss_init
|| cctx->pledgedSrcSizePlusOne != 0
|| cctx->rustSimpleCompress2Completed != 0) {
return (-2147483647 - 1);
}
return ZSTD_rust_simpleCompress2Level(opaqueCctx, srcSize);
ZSTD_rust_simpleCompressStream2Projection const projection = {
cctx == NULL ? 0 : (int)cctx->streamStage,
cctx == NULL ? 0 : cctx->pledgedSrcSizePlusOne,
cctx == NULL ? 0 : cctx->rustSimpleCompress2Completed
};
return ZSTD_rust_simpleCompressStream2Policy(
&projection, opaqueCctx, srcSize, ZSTD_rust_simpleCompress2Level);
}
/* ZSTD_compress() is implemented by rust/src/zstd_compress.rs. */
+131
View File
@@ -117,6 +117,40 @@ const MIN_CBLOCK_SIZE: usize = 2;
const MIN_COMPRESSIBLE_BLOCK_SIZE: usize = MIN_CBLOCK_SIZE + ZSTD_BLOCK_HEADER_SIZE + 1 + 1;
const ZSTD_ROWSIZE: usize = 16;
const ZSTD_CSTREAM_STAGE_INIT: c_int = 0;
/// Scalar stream state used to select the complete-input fast path. The C
/// context remains opaque; its private fields are projected before Rust
/// evaluates the eligibility predicate.
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct ZSTD_rust_simpleCompressStream2Projection {
stream_stage: c_int,
pledged_src_size_plus_one: u64,
rust_simple_compress2_completed: c_uint,
}
const _: () = {
assert!(offset_of!(ZSTD_rust_simpleCompressStream2Projection, stream_stage) == 0);
assert!(
offset_of!(
ZSTD_rust_simpleCompressStream2Projection,
pledged_src_size_plus_one
) == if size_of::<usize>() == 8 { 8 } else { 4 }
);
assert!(
offset_of!(
ZSTD_rust_simpleCompressStream2Projection,
rust_simple_compress2_completed
) == if size_of::<usize>() == 8 { 16 } else { 12 }
);
assert!(
size_of::<ZSTD_rust_simpleCompressStream2Projection>()
== if size_of::<usize>() == 8 { 24 } else { 16 }
);
};
pub type ZSTD_rust_simpleCompress2LevelFn = unsafe extern "C" fn(*const c_void, usize) -> c_int;
const ZSTD_WINDOW_START_INDEX: u32 = 2;
const ZSTD_DUBT_UNSORTED_MARK: u32 = 1;
const ZSTD_INDEXOVERFLOW_MARGIN: usize = 16usize << 20;
@@ -9825,6 +9859,32 @@ unsafe fn compress_frame(
output_offset
}
/// Select the complete-input streaming fast path before invoking the C-owned
/// simple-level predicate. Rust owns the stream-state branch; C keeps the
/// private context and level-selection leaf behind a callback.
#[no_mangle]
pub unsafe extern "C" fn ZSTD_rust_simpleCompressStream2Policy(
projection: *const ZSTD_rust_simpleCompressStream2Projection,
cctx: *const c_void,
src_size: usize,
simple_compress2_level: Option<ZSTD_rust_simpleCompress2LevelFn>,
) -> c_int {
let Some(projection) = (unsafe { projection.as_ref() }) else {
return c_int::MIN;
};
if cctx.is_null()
|| projection.stream_stage != ZSTD_CSTREAM_STAGE_INIT
|| projection.pledged_src_size_plus_one != 0
|| projection.rust_simple_compress2_completed != 0
{
return c_int::MIN;
}
let Some(simple_compress2_level) = simple_compress2_level else {
return c_int::MIN;
};
unsafe { simple_compress2_level(cctx, src_size) }
}
/// Simple one-shot compression entry point.
#[no_mangle]
pub unsafe extern "C" fn ZSTD_compress(
@@ -13674,6 +13734,77 @@ mod tests {
);
}
#[derive(Default)]
struct SimpleStreamPolicyTestContext {
calls: usize,
src_size: usize,
}
unsafe extern "C" fn simple_stream_policy_test_level(
context: *const c_void,
src_size: usize,
) -> c_int {
let context = unsafe { &mut *context.cast_mut().cast::<SimpleStreamPolicyTestContext>() };
context.calls += 1;
context.src_size = src_size;
7
}
#[test]
fn simple_stream_policy_calls_the_level_leaf_only_for_a_new_frame() {
let mut context = SimpleStreamPolicyTestContext::default();
let cctx = (&mut context as *mut SimpleStreamPolicyTestContext).cast();
let projection = ZSTD_rust_simpleCompressStream2Projection {
stream_stage: ZSTD_CSTREAM_STAGE_INIT,
pledged_src_size_plus_one: 0,
rust_simple_compress2_completed: 0,
};
let result = unsafe {
ZSTD_rust_simpleCompressStream2Policy(
&projection,
cctx,
123,
Some(simple_stream_policy_test_level),
)
};
assert_eq!(result, 7);
assert_eq!(context.calls, 1);
assert_eq!(context.src_size, 123);
}
#[test]
fn simple_stream_policy_rejects_non_initial_or_completed_frames() {
let mut context = SimpleStreamPolicyTestContext::default();
let cctx = (&mut context as *mut SimpleStreamPolicyTestContext).cast();
for projection in [
ZSTD_rust_simpleCompressStream2Projection {
stream_stage: ZSTD_CSTREAM_STAGE_LOAD,
..Default::default()
},
ZSTD_rust_simpleCompressStream2Projection {
pledged_src_size_plus_one: 1,
..Default::default()
},
ZSTD_rust_simpleCompressStream2Projection {
rust_simple_compress2_completed: 1,
..Default::default()
},
] {
let result = unsafe {
ZSTD_rust_simpleCompressStream2Policy(
&projection,
cctx,
123,
Some(simple_stream_policy_test_level),
)
};
assert_eq!(result, c_int::MIN);
}
assert_eq!(context.calls, 0);
}
#[test]
fn reduce_table_applies_threshold_and_wrapping_subtraction() {
let mut table = [0, 1, 2, 3, 4, 5, 6, u32::MAX, 0, 0, 0, 0, 0, 0, 0, 0];