feat(compress): move block header serialization to Rust

Keep the private writeBlockHeader signature and its debug logging in C while
moving the pure block-type, size, and 24-bit little-endian encoding behind a
narrow Rust ABI. The Rust leaf preserves the RLE blockSize path for cSize == 1
and the compressed cSize path for every other value.

Test Plan:
- `cargo test --manifest-path rust/Cargo.toml --no-default-features --features compression block_header -- --nocapture` -- passed
- `make -B -C lib -j2 lib` -- passed
- `make -C tests -j2 fuzzer` -- passed
- `./tests/fuzzer -s4560 -t47 -i48 -v` -- passed
- Required clippy, nightly fmt, and diff checks -- passed
This commit is contained in:
2026-07-18 08:52:42 +02:00
parent 9df7b55d8f
commit 934a589500
2 changed files with 47 additions and 4 deletions
+3 -4
View File
@@ -37,6 +37,8 @@ size_t ZSTD_rust_writeFrameHeader(void* dst, size_t dstCapacity,
int contentSizeFlag, int format,
U32 windowLog, U64 pledgedSrcSize,
U32 dictID);
void ZSTD_rust_writeBlockHeader(void* op, size_t cSize, size_t blockSize,
U32 lastBlock);
size_t ZSTD_rust_writeEpilogue(void* dst, size_t dstCapacity, int* stage,
int noDictIDFlag, int checksumFlag,
int contentSizeFlag, int format, U32 windowLog,
@@ -2592,10 +2594,7 @@ ZSTD_blockState_confirmRepcodesAndEntropyTables(ZSTD_blockState_t* const bs)
static void
writeBlockHeader(void* op, size_t cSize, size_t blockSize, U32 lastBlock)
{
U32 const cBlockHeader = cSize == 1 ?
lastBlock + (((U32)bt_rle)<<1) + (U32)(blockSize << 3) :
lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3);
MEM_writeLE24(op, cBlockHeader);
ZSTD_rust_writeBlockHeader(op, cSize, blockSize, lastBlock);
DEBUGLOG(5, "writeBlockHeader: cSize: %zu blockSize: %zu lastBlock: %u", cSize, blockSize, lastBlock);
}
+44
View File
@@ -25,6 +25,7 @@ const ZSTD_F_ZSTD1: c_int = 0;
const ZSTD_BLOCK_SIZE: usize = 128 << 10;
const ZSTD_FAST: c_int = 1;
const ZSTD_BTULTRA2: c_int = 9;
const ZSTD_BT_COMPRESSED: u32 = 2;
const SPLIT_LEVELS: [c_int; 10] = [0, 0, 1, 2, 2, 3, 3, 4, 4, 4];
const ZSTD_BT_RLE: u32 = 1;
const ZSTDCS_CREATED: c_int = 0;
@@ -83,6 +84,31 @@ pub(crate) unsafe fn write_raw_block(
needed
}
/// Rust implementation of the private compressed-block header serializer.
///
/// The C wrapper retains the original static helper signature and keeps its
/// debug logging at the call site. The helper itself only needs scalar
/// values and writes the low 24 bits in little-endian order, as `MEM_writeLE24`
/// does.
#[no_mangle]
pub unsafe extern "C" fn ZSTD_rust_writeBlockHeader(
op: *mut c_void,
c_size: usize,
block_size: usize,
last_block: c_uint,
) {
let block_type = if c_size == 1 {
ZSTD_BT_RLE
} else {
ZSTD_BT_COMPRESSED
};
let size = if c_size == 1 { block_size } else { c_size };
let header = last_block
.wrapping_add(block_type << 1)
.wrapping_add((size as u32).wrapping_shl(3));
unsafe { write_le24(op.cast(), header) };
}
/// Rust implementation of the private `ZSTD_writeFrameHeader()` leaf.
///
/// `no_dict_id_flag`, `checksum_flag`, `content_size_flag`, `format`, and
@@ -604,6 +630,24 @@ mod tests {
);
}
#[test]
fn writes_rle_block_header() {
let mut output = [0u8; ZSTD_BLOCKHEADERSIZE];
unsafe {
ZSTD_rust_writeBlockHeader(output.as_mut_ptr().cast(), 1, 0x12345, 1);
}
assert_eq!(output, [0x2b, 0x1a, 0x09]);
}
#[test]
fn writes_compressed_block_header() {
let mut output = [0u8; ZSTD_BLOCKHEADERSIZE];
unsafe {
ZSTD_rust_writeBlockHeader(output.as_mut_ptr().cast(), 0x23456, 0x54321, 1);
}
assert_eq!(output, [0xb5, 0xa2, 0x11]);
}
#[test]
fn optimal_block_size_keeps_small_blocks_intact() {
let result = unsafe {