feat(compress): move external sequence conversion to Rust

The external-sequence block path still converted public ZSTD_Sequence values
in C, with separate scalar and AVX2 implementations. Move that pure format
conversion into zstd_compress_stats.rs so both native configurations share one
implementation. Preserve offBase encoding, u16 truncation, the rep-ignored
contract, and the long-length side-band marker; leave C responsible for block
state, repcode resolution, and long-length bookkeeping.

Test Plan:
- `cargo test --manifest-path rust/Cargo.toml --no-default-features --features compression` -- 225 passed
- `cargo clippy --manifest-path rust/Cargo.toml --no-default-features --features compression` plus benches/tests -- passed before and after formatting
- `cargo +nightly fmt --manifest-path rust/Cargo.toml --all` -- passed
- `make -B -C lib -j2 lib` -- passed
- `make -C tests -j2 test-zstream` -- passed, including 84 deterministic and 14,768 randomized cases
This commit is contained in:
2026-07-18 06:50:48 +02:00
parent 684963c1a9
commit 18f5419cc6
2 changed files with 104 additions and 192 deletions
+99
View File
@@ -158,6 +158,46 @@ pub struct ZSTD_Sequence {
pub rep: u32,
}
/// Converts public sequences to the internal no-repcodes `SeqDef` format.
///
/// The return value is a side-band marker: zero means that every length fits
/// in its `u16` field; otherwise it is one plus the match-length sequence
/// index, or `nb_sequences + 1` plus the literal-length sequence index. This
/// is the Rust leaf for C's `convertSequences_noRepcodes()`.
#[no_mangle]
pub unsafe extern "C" fn ZSTD_rust_convertSequencesNoRepcodes(
dst_seqs: *mut SeqDef,
in_seqs: *const ZSTD_Sequence,
nb_sequences: usize,
) -> usize {
if nb_sequences == 0 {
return 0;
}
let dst_seqs = unsafe { std::slice::from_raw_parts_mut(dst_seqs, nb_sequences) };
let in_seqs = unsafe { std::slice::from_raw_parts(in_seqs, nb_sequences) };
let mut long_length = 0usize;
for (index, input) in in_seqs.iter().enumerate() {
dst_seqs[index] = SeqDef {
offBase: input.offset.wrapping_add(ZSTD_REP_NUM as u32),
litLength: input.litLength as u16,
mlBase: input.matchLength.wrapping_sub(MINMATCH as u32) as u16,
};
if input.matchLength > 65535 + MINMATCH as u32 {
debug_assert_eq!(long_length, 0);
long_length = index + 1;
}
if input.litLength > 65535 {
debug_assert_eq!(long_length, 0);
long_length = index + nb_sequences + 1;
}
}
long_length
}
/// Converts a raw sequence offset to the stored offBase representation.
///
/// This is the Rust leaf for C's `ZSTD_finalizeOffBase()`. The repcode
@@ -1793,6 +1833,65 @@ mod tests {
}
}
#[test]
fn convert_sequences_no_repcodes_maps_fields_and_ignores_rep() {
let input = [
ZSTD_Sequence {
offset: 1,
litLength: 7,
matchLength: 3,
rep: 99,
},
ZSTD_Sequence {
offset: 1234,
litLength: 0x12345,
matchLength: 17,
rep: 1,
},
];
let mut output = [SeqDef::default(); 2];
let long_length = unsafe {
ZSTD_rust_convertSequencesNoRepcodes(output.as_mut_ptr(), input.as_ptr(), input.len())
};
assert_eq!(long_length, input.len() + 1 + 1);
assert_eq!(output[0].offBase, 1 + ZSTD_REP_NUM as u32);
assert_eq!(output[0].litLength, 7);
assert_eq!(output[0].mlBase, 0);
assert_eq!(output[1].offBase, 1234 + ZSTD_REP_NUM as u32);
assert_eq!(output[1].litLength, 0x2345);
assert_eq!(output[1].mlBase, 14);
}
#[test]
fn convert_sequences_no_repcodes_marks_a_long_match() {
let input = [ZSTD_Sequence {
offset: 8,
litLength: 2,
matchLength: 65535 + MINMATCH as u32 + 1,
rep: 0,
}];
let mut output = [SeqDef::default()];
let long_length = unsafe {
ZSTD_rust_convertSequencesNoRepcodes(output.as_mut_ptr(), input.as_ptr(), input.len())
};
assert_eq!(long_length, 1);
assert_eq!(output[0].offBase, 8 + ZSTD_REP_NUM as u32);
assert_eq!(output[0].litLength, 2);
assert_eq!(output[0].mlBase, 0);
}
#[test]
fn convert_sequences_no_repcodes_accepts_an_empty_range() {
let result = unsafe {
ZSTD_rust_convertSequencesNoRepcodes(std::ptr::null_mut(), std::ptr::null(), 0)
};
assert_eq!(result, 0);
}
#[test]
fn compressed_block_state_reset_restores_repcodes_and_repeat_modes() {
let mut block_state =