feat(compress): move frame header projection into Rust
Remove the C frame-header callback from the Rust-owned compressContinue orchestration. Project the applied frame parameters and dictionary ID as scalars, so Rust can call the existing header serializer directly while preserving pledged-size subtraction, stage transitions, and output accounting. Route the sequence API's remaining header call directly to the same Rust leaf and delete the redundant C wrapper. Test Plan: - ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo test --lib zstd_compress::tests::compress_continue -- --nocapture - ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo clippy --all-targets -- -D warnings - ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo test - ulimit -v 41943040; make -j1 - ulimit -v 41943040; make -j1 -C tests test-zstream ZSTREAM_TESTTIME=-T2s - ulimit -v 41943040; make -j1 -C tests test-fuzzer FUZZERTEST=-T3s FUZZER_FLAGS=--no-big-tests
This commit is contained in:
+73
-43
@@ -790,7 +790,6 @@ pub unsafe extern "C" fn ZSTD_rust_compressFrameChunk(
|
||||
}
|
||||
}
|
||||
|
||||
type CompressContinueHeaderFn = unsafe extern "C" fn(*mut c_void, *mut c_void, usize) -> usize;
|
||||
type CompressContinueWindowFn = unsafe extern "C" fn(*mut c_void, *const c_void, usize);
|
||||
type CompressContinueBlockFn =
|
||||
unsafe extern "C" fn(*mut c_void, *mut c_void, usize, *const c_void, usize, c_uint) -> usize;
|
||||
@@ -799,12 +798,12 @@ type CompressContinueBlockFn =
|
||||
///
|
||||
/// Rust owns stage transitions, frame-header sequencing, input progression,
|
||||
/// and dispatch between the already-migrated frame-chunk/block bodies. The
|
||||
/// opaque callback context remains in C, where callbacks update the private
|
||||
/// match-state windows and invoke the C-owned context-sensitive operations.
|
||||
/// frame-header parameters are projected as scalars, while the opaque callback
|
||||
/// context remains in C, where callbacks update the private match-state
|
||||
/// windows and invoke the C-owned context-sensitive operations.
|
||||
#[repr(C)]
|
||||
pub struct ZSTD_rust_compressContinueState {
|
||||
callback_context: *mut c_void,
|
||||
write_frame_header: CompressContinueHeaderFn,
|
||||
update_window: CompressContinueWindowFn,
|
||||
correct_overflow: CompressContinueWindowFn,
|
||||
compress_frame_chunk: CompressContinueBlockFn,
|
||||
@@ -815,42 +814,74 @@ pub struct ZSTD_rust_compressContinueState {
|
||||
pledged_src_size_plus_one: u64,
|
||||
block_size_max: usize,
|
||||
check_block_size: c_int,
|
||||
no_dict_id_flag: c_int,
|
||||
checksum_flag: c_int,
|
||||
content_size_flag: c_int,
|
||||
format: c_int,
|
||||
window_log: c_uint,
|
||||
dict_id: c_uint,
|
||||
}
|
||||
|
||||
const COMPRESS_CONTINUE_SCALARS_OFFSET: usize =
|
||||
size_of::<[usize; 8]>() + size_of::<u64>() + size_of::<usize>();
|
||||
|
||||
const _: () = {
|
||||
assert!(offset_of!(ZSTD_rust_compressContinueState, callback_context) == 0);
|
||||
assert!(offset_of!(ZSTD_rust_compressContinueState, write_frame_header) == size_of::<usize>());
|
||||
assert!(offset_of!(ZSTD_rust_compressContinueState, update_window) == 2 * size_of::<usize>());
|
||||
assert!(offset_of!(ZSTD_rust_compressContinueState, update_window) == size_of::<usize>());
|
||||
assert!(
|
||||
offset_of!(ZSTD_rust_compressContinueState, correct_overflow) == 3 * size_of::<usize>()
|
||||
offset_of!(ZSTD_rust_compressContinueState, correct_overflow) == 2 * size_of::<usize>()
|
||||
);
|
||||
assert!(
|
||||
offset_of!(ZSTD_rust_compressContinueState, compress_frame_chunk) == 4 * size_of::<usize>()
|
||||
offset_of!(ZSTD_rust_compressContinueState, compress_frame_chunk) == 3 * size_of::<usize>()
|
||||
);
|
||||
assert!(offset_of!(ZSTD_rust_compressContinueState, compress_block) == 5 * size_of::<usize>());
|
||||
assert!(offset_of!(ZSTD_rust_compressContinueState, stage) == 6 * size_of::<usize>());
|
||||
assert!(offset_of!(ZSTD_rust_compressContinueState, compress_block) == 4 * size_of::<usize>());
|
||||
assert!(offset_of!(ZSTD_rust_compressContinueState, stage) == 5 * size_of::<usize>());
|
||||
assert!(
|
||||
offset_of!(ZSTD_rust_compressContinueState, consumed_src_size) == 7 * size_of::<usize>()
|
||||
offset_of!(ZSTD_rust_compressContinueState, consumed_src_size) == 6 * size_of::<usize>()
|
||||
);
|
||||
assert!(
|
||||
offset_of!(ZSTD_rust_compressContinueState, produced_c_size)
|
||||
== 8 * (usize::BITS as usize / 8)
|
||||
== 7 * (usize::BITS as usize / 8)
|
||||
);
|
||||
assert!(
|
||||
offset_of!(ZSTD_rust_compressContinueState, pledged_src_size_plus_one)
|
||||
== 9 * size_of::<usize>()
|
||||
== size_of::<[usize; 8]>()
|
||||
);
|
||||
assert!(
|
||||
offset_of!(ZSTD_rust_compressContinueState, block_size_max)
|
||||
== 9 * size_of::<usize>() + size_of::<u64>()
|
||||
== size_of::<[usize; 8]>() + size_of::<u64>()
|
||||
);
|
||||
assert!(
|
||||
offset_of!(ZSTD_rust_compressContinueState, check_block_size)
|
||||
== 9 * size_of::<usize>() + size_of::<u64>() + size_of::<usize>()
|
||||
== COMPRESS_CONTINUE_SCALARS_OFFSET
|
||||
);
|
||||
assert!(
|
||||
offset_of!(ZSTD_rust_compressContinueState, no_dict_id_flag)
|
||||
== COMPRESS_CONTINUE_SCALARS_OFFSET + size_of::<c_int>()
|
||||
);
|
||||
assert!(
|
||||
offset_of!(ZSTD_rust_compressContinueState, checksum_flag)
|
||||
== COMPRESS_CONTINUE_SCALARS_OFFSET + size_of::<[c_int; 2]>()
|
||||
);
|
||||
assert!(
|
||||
offset_of!(ZSTD_rust_compressContinueState, content_size_flag)
|
||||
== COMPRESS_CONTINUE_SCALARS_OFFSET + size_of::<[c_int; 3]>()
|
||||
);
|
||||
assert!(
|
||||
offset_of!(ZSTD_rust_compressContinueState, format)
|
||||
== COMPRESS_CONTINUE_SCALARS_OFFSET + size_of::<[c_int; 4]>()
|
||||
);
|
||||
assert!(
|
||||
offset_of!(ZSTD_rust_compressContinueState, window_log)
|
||||
== COMPRESS_CONTINUE_SCALARS_OFFSET + size_of::<[c_int; 5]>()
|
||||
);
|
||||
assert!(
|
||||
offset_of!(ZSTD_rust_compressContinueState, dict_id)
|
||||
== COMPRESS_CONTINUE_SCALARS_OFFSET + size_of::<[c_int; 5]>() + size_of::<c_uint>()
|
||||
);
|
||||
assert!(
|
||||
size_of::<ZSTD_rust_compressContinueState>()
|
||||
== if size_of::<usize>() == 8 { 96 } else { 52 }
|
||||
== if size_of::<usize>() == 8 { 112 } else { 72 }
|
||||
);
|
||||
};
|
||||
|
||||
@@ -885,8 +916,19 @@ unsafe fn compress_continue_body_with(
|
||||
|
||||
let mut frame_header_size = 0usize;
|
||||
if frame != 0 && unsafe { *state.stage } == ZSTD_COMPRESSION_STAGE_INIT {
|
||||
frame_header_size =
|
||||
unsafe { (state.write_frame_header)(state.callback_context, dst, dst_capacity) };
|
||||
frame_header_size = unsafe {
|
||||
ZSTD_rust_writeFrameHeader(
|
||||
dst,
|
||||
dst_capacity,
|
||||
state.no_dict_id_flag,
|
||||
state.checksum_flag,
|
||||
state.content_size_flag,
|
||||
state.format,
|
||||
state.window_log,
|
||||
state.pledged_src_size_plus_one.wrapping_sub(1),
|
||||
state.dict_id,
|
||||
)
|
||||
};
|
||||
if ERR_isError(frame_header_size) {
|
||||
return frame_header_size;
|
||||
}
|
||||
@@ -10964,13 +11006,11 @@ mod tests {
|
||||
|
||||
#[derive(Default)]
|
||||
struct CompressContinueTestContext {
|
||||
header_calls: usize,
|
||||
update_window_calls: usize,
|
||||
overflow_calls: usize,
|
||||
frame_calls: usize,
|
||||
block_calls: usize,
|
||||
last_frame_chunk: c_uint,
|
||||
header_result: usize,
|
||||
frame_result: usize,
|
||||
block_result: usize,
|
||||
}
|
||||
@@ -10981,16 +11021,6 @@ mod tests {
|
||||
unsafe { &mut *context.cast::<CompressContinueTestContext>() }
|
||||
}
|
||||
|
||||
unsafe extern "C" fn compress_continue_test_header(
|
||||
context: *mut c_void,
|
||||
_dst: *mut c_void,
|
||||
_dst_capacity: usize,
|
||||
) -> usize {
|
||||
let context = unsafe { compress_continue_test_context(context) };
|
||||
context.header_calls += 1;
|
||||
context.header_result
|
||||
}
|
||||
|
||||
unsafe extern "C" fn compress_continue_test_window(
|
||||
context: *mut c_void,
|
||||
_src: *const c_void,
|
||||
@@ -11047,7 +11077,6 @@ mod tests {
|
||||
) -> ZSTD_rust_compressContinueState {
|
||||
ZSTD_rust_compressContinueState {
|
||||
callback_context: (context as *mut CompressContinueTestContext).cast(),
|
||||
write_frame_header: compress_continue_test_header,
|
||||
update_window: compress_continue_test_window,
|
||||
correct_overflow: compress_continue_test_overflow,
|
||||
compress_frame_chunk: compress_continue_test_frame,
|
||||
@@ -11058,13 +11087,18 @@ mod tests {
|
||||
pledged_src_size_plus_one,
|
||||
block_size_max,
|
||||
check_block_size,
|
||||
no_dict_id_flag: 0,
|
||||
checksum_flag: 0,
|
||||
content_size_flag: 0,
|
||||
format: 0,
|
||||
window_log: 10,
|
||||
dict_id: 0,
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compress_continue_starts_frame_and_updates_progression() {
|
||||
let mut context = CompressContinueTestContext {
|
||||
header_result: 4,
|
||||
frame_result: 6,
|
||||
..CompressContinueTestContext::default()
|
||||
};
|
||||
@@ -11095,11 +11129,10 @@ mod tests {
|
||||
)
|
||||
};
|
||||
|
||||
assert_eq!(result, 10);
|
||||
assert_eq!(result, 12);
|
||||
assert_eq!(stage, ZSTD_COMPRESSION_STAGE_ONGOING);
|
||||
assert_eq!(consumed, 12);
|
||||
assert_eq!(produced, 21);
|
||||
assert_eq!(context.header_calls, 1);
|
||||
assert_eq!(produced, 23);
|
||||
assert_eq!(context.update_window_calls, 1);
|
||||
assert_eq!(context.overflow_calls, 0);
|
||||
assert_eq!(context.frame_calls, 1);
|
||||
@@ -11109,10 +11142,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn compress_continue_empty_frame_only_writes_header() {
|
||||
let mut context = CompressContinueTestContext {
|
||||
header_result: 3,
|
||||
..CompressContinueTestContext::default()
|
||||
};
|
||||
let mut context = CompressContinueTestContext::default();
|
||||
let mut stage = ZSTD_COMPRESSION_STAGE_INIT;
|
||||
let mut consumed = 7;
|
||||
let mut produced = 11;
|
||||
@@ -11125,7 +11155,7 @@ mod tests {
|
||||
16,
|
||||
0,
|
||||
);
|
||||
let mut output = [0xa5u8; 8];
|
||||
let mut output = [0xa5u8; 18];
|
||||
|
||||
let result = unsafe {
|
||||
ZSTD_rust_compressContinue(
|
||||
@@ -11139,13 +11169,13 @@ mod tests {
|
||||
)
|
||||
};
|
||||
|
||||
assert_eq!(result, 3);
|
||||
assert_eq!(result, 6);
|
||||
assert_eq!(stage, ZSTD_COMPRESSION_STAGE_ONGOING);
|
||||
assert_eq!((consumed, produced), (7, 11));
|
||||
assert_eq!(context.header_calls, 1);
|
||||
assert_eq!(context.update_window_calls, 0);
|
||||
assert_eq!(context.frame_calls, 0);
|
||||
assert_eq!(output, [0xa5; 8]);
|
||||
assert_eq!(&output[..6], &[0x28, 0xb5, 0x2f, 0xfd, 0x00, 0x00]);
|
||||
assert_eq!(&output[6..], &[0xa5; 12]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -112,9 +112,9 @@ pub unsafe extern "C" fn ZSTD_rust_writeBlockHeader(
|
||||
/// Rust implementation of the private `ZSTD_writeFrameHeader()` leaf.
|
||||
///
|
||||
/// `no_dict_id_flag`, `checksum_flag`, `content_size_flag`, `format`, and
|
||||
/// `window_log` are extracted by a C wrapper from `ZSTD_CCtx_params`. The
|
||||
/// wrapper preserves the existing static C function signature, avoiding any
|
||||
/// dependency on the full context-parameter layout here.
|
||||
/// `window_log` are extracted by C callers from `ZSTD_CCtx_params`. Keeping
|
||||
/// those projections scalar avoids any dependency on the full
|
||||
/// context-parameter layout here.
|
||||
///
|
||||
/// The caller must provide a writable buffer of at least
|
||||
/// `ZSTD_FRAMEHEADERSIZE_MAX` bytes, or this returns `dstSize_tooSmall`. As
|
||||
|
||||
Reference in New Issue
Block a user