feat(compress): route complete stream frames through Rust
Route ordinary complete-input ZSTD_compressStream2 calls through the Rust frame compressor while retaining the C state machine for partial, advanced, and dictionary-backed streams. Track explicit maxBlockSize requests so the migrated path preserves the original byte-identical default behavior, and extend the C archive smoke test across context reuse and fallback cases. Test Plan: - cargo clippy --manifest-path rust/Cargo.toml - cargo clippy --manifest-path rust/Cargo.toml --benches - cargo clippy --manifest-path rust/Cargo.toml --tests - cargo test --manifest-path rust/Cargo.toml --no-default-features --features compression (133 passed) - make -B -C tests -j2 test-rust-lib-smoke and ./tests/rustLibSmoke - make -B -C tests -j2 test-zstream (passed, including both APIs and maxBlockSize case 78)
This commit is contained in:
@@ -8,14 +8,15 @@
|
||||
//! The layout-independent one-shot entry point in this module drives the
|
||||
//! already migrated compression leaves. `ZSTD_compressCCtx` uses the same
|
||||
//! path after a narrow C-owned context reset; the public context lifecycle
|
||||
//! and streaming APIs remain C-owned because they share the
|
||||
//! configuration-dependent private `ZSTD_CCtx_s` layout. `ZSTD_compress2`
|
||||
//! dispatches simple, dictionary-free contexts through the same Rust frame
|
||||
//! path and retains the C implementation for advanced contexts. A following
|
||||
//! one-shot `ZSTD_compressStream2(..., ZSTD_e_end)` call can reuse that path.
|
||||
//! remains C-owned because it shares the configuration-dependent private
|
||||
//! `ZSTD_CCtx_s` layout. `ZSTD_compress2` and the complete-input simple
|
||||
//! `ZSTD_compressStream2(..., ZSTD_e_end)` path dispatch through Rust while
|
||||
//! retaining the C implementation for advanced and partial-stream cases.
|
||||
|
||||
use crate::errors::{ERR_isError, ZstdErrorCode, ERROR};
|
||||
use crate::mem::MEM_writeLE24;
|
||||
#[cfg(not(test))]
|
||||
use crate::zstd_compress_api::ZSTD_compressBound;
|
||||
use crate::zstd_compress_frame::{ZSTD_rust_writeFrameHeader, ZSTD_writeLastEmptyBlock};
|
||||
use crate::zstd_compress_params::{
|
||||
ZSTD_rust_params_adjustCParams, ZSTD_rust_params_maxNbSeq, ZSTD_rust_params_selectCParams,
|
||||
@@ -40,6 +41,7 @@ unsafe extern "C" {
|
||||
fn ZSTD_rust_resetCCtxForSimpleCompressionSession(cctx: *mut c_void) -> usize;
|
||||
fn ZSTD_rust_markSimpleCompression2Complete(cctx: *mut c_void);
|
||||
fn ZSTD_rust_simpleCompress2Level(cctx: *const c_void) -> c_int;
|
||||
fn ZSTD_rust_simpleCompressStream2Level(cctx: *const c_void) -> c_int;
|
||||
fn ZSTD_compress2_c(
|
||||
cctx: *mut c_void,
|
||||
dst: *mut c_void,
|
||||
@@ -47,12 +49,36 @@ unsafe extern "C" {
|
||||
src: *const c_void,
|
||||
src_size: usize,
|
||||
) -> usize;
|
||||
fn ZSTD_compressStream2_c(
|
||||
cctx: *mut c_void,
|
||||
output: *mut ZSTD_outBuffer,
|
||||
input: *mut ZSTD_inBuffer,
|
||||
end_op: c_int,
|
||||
) -> usize;
|
||||
}
|
||||
|
||||
const ZSTD_FAST: c_int = 1;
|
||||
const ZSTD_DFAST: c_int = 2;
|
||||
const ZSTD_BLOCKSIZE_MAX: usize = 1 << 17;
|
||||
const ZSTD_CONTENTSIZE_UNKNOWN: u64 = u64::MAX;
|
||||
#[cfg(not(test))]
|
||||
const ZSTD_E_END: c_int = 2;
|
||||
|
||||
#[cfg(not(test))]
|
||||
#[repr(C)]
|
||||
pub struct ZSTD_inBuffer {
|
||||
src: *const c_void,
|
||||
size: usize,
|
||||
pos: usize,
|
||||
}
|
||||
|
||||
#[cfg(not(test))]
|
||||
#[repr(C)]
|
||||
pub struct ZSTD_outBuffer {
|
||||
dst: *mut c_void,
|
||||
size: usize,
|
||||
pos: usize,
|
||||
}
|
||||
|
||||
/* HUF_WORKSPACE_SIZE + (MaxSeq + 2) * sizeof(unsigned), rounded up. The
|
||||
* superblock leaf also accepts the larger pre-split workspace, so a fixed
|
||||
@@ -433,6 +459,70 @@ pub unsafe extern "C" fn ZSTD_compress2(
|
||||
}
|
||||
}
|
||||
|
||||
/// Compress a streaming call when the complete input and a full output bound
|
||||
/// are already available for the ordinary context configuration.
|
||||
///
|
||||
/// The C implementation remains the fallback for partial-output streaming,
|
||||
/// `ZSTD_e_continue`/`ZSTD_e_flush`, dictionaries, and every advanced context
|
||||
/// configuration. The Rust path resets the C-owned session after emitting a
|
||||
/// complete frame so the same context can immediately start another frame.
|
||||
#[cfg(not(test))]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn ZSTD_compressStream2(
|
||||
cctx: *mut c_void,
|
||||
output: *mut ZSTD_outBuffer,
|
||||
input: *mut ZSTD_inBuffer,
|
||||
end_op: c_int,
|
||||
) -> usize {
|
||||
if cctx.is_null() || output.is_null() || input.is_null() {
|
||||
return ERROR(ZstdErrorCode::Generic);
|
||||
}
|
||||
|
||||
let output_ref = unsafe { &mut *output };
|
||||
let input_ref = unsafe { &mut *input };
|
||||
if output_ref.pos > output_ref.size {
|
||||
return ERROR(ZstdErrorCode::DstSizeTooSmall);
|
||||
}
|
||||
if input_ref.pos > input_ref.size {
|
||||
return ERROR(ZstdErrorCode::SrcSizeWrong);
|
||||
}
|
||||
|
||||
if end_op == ZSTD_E_END {
|
||||
let level = unsafe { ZSTD_rust_simpleCompressStream2Level(cctx.cast_const()) };
|
||||
if level != c_int::MIN {
|
||||
let src_size = input_ref.size - input_ref.pos;
|
||||
let dst_capacity = output_ref.size - output_ref.pos;
|
||||
let bound = ZSTD_compressBound(src_size);
|
||||
if !ERR_isError(bound) && dst_capacity >= bound {
|
||||
if dst_capacity != 0 && output_ref.dst.is_null() {
|
||||
return ERROR(ZstdErrorCode::DstBufferNull);
|
||||
}
|
||||
if src_size != 0 && input_ref.src.is_null() {
|
||||
return ERROR(ZstdErrorCode::SrcSizeWrong);
|
||||
}
|
||||
let dst = if output_ref.dst.is_null() {
|
||||
ptr::null_mut()
|
||||
} else {
|
||||
unsafe { output_ref.dst.cast::<u8>().add(output_ref.pos).cast() }
|
||||
};
|
||||
let src = if input_ref.src.is_null() {
|
||||
ptr::null()
|
||||
} else {
|
||||
unsafe { input_ref.src.cast::<u8>().add(input_ref.pos).cast() }
|
||||
};
|
||||
let result = unsafe { compress_frame(dst, dst_capacity, src, src_size, level) };
|
||||
if !ERR_isError(result) {
|
||||
output_ref.pos += result;
|
||||
input_ref.pos = input_ref.size;
|
||||
return unsafe { ZSTD_rust_resetCCtxForSimpleCompressionSession(cctx) };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe { ZSTD_compressStream2_c(cctx, output, input, end_op) }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
Reference in New Issue
Block a user