feat(compress): move external sequence store reset into Rust

Move the mutable external raw-sequence-store assignment and cursor reset
behind a Rust-owned pointer projection. Keep the public C entry point and
its stage/LDM assertions in C, without exposing RawSeqStore_t to Rust.

Test Plan:
- cargo test --manifest-path rust/Cargo.toml --lib
- cargo clippy --manifest-path rust/Cargo.toml --all-targets -- -D warnings
- make -B -C programs -j1 zstd
- make -C tests -j1 test-zstream ZSTREAM_TESTTIME=-T1s
- focused reference_external_sequences unit tests
This commit is contained in:
2026-07-19 14:48:30 +02:00
parent 9a68253710
commit 814b7af16d
2 changed files with 130 additions and 5 deletions
+97
View File
@@ -403,6 +403,55 @@ pub unsafe extern "C" fn ZSTD_rust_tryExternalSequenceProducer(
0
}
/// Reset the externally referenced raw-sequence store without exposing its C
/// representation to Rust.
#[repr(C)]
pub struct ZSTD_rust_externalSequenceStoreState {
seq: *mut *mut c_void,
pos: *mut usize,
pos_in_sequence: *mut usize,
size: *mut usize,
capacity: *mut usize,
}
const _: () = {
assert!(offset_of!(ZSTD_rust_externalSequenceStoreState, seq) == 0);
assert!(offset_of!(ZSTD_rust_externalSequenceStoreState, pos) == size_of::<usize>());
assert!(
offset_of!(ZSTD_rust_externalSequenceStoreState, pos_in_sequence) == 2 * size_of::<usize>()
);
assert!(offset_of!(ZSTD_rust_externalSequenceStoreState, size) == 3 * size_of::<usize>());
assert!(offset_of!(ZSTD_rust_externalSequenceStoreState, capacity) == 4 * size_of::<usize>());
assert!(size_of::<ZSTD_rust_externalSequenceStoreState>() == 5 * size_of::<usize>());
};
#[no_mangle]
pub unsafe extern "C" fn ZSTD_rust_referenceExternalSequences(
state: *const ZSTD_rust_externalSequenceStoreState,
seq: *mut c_void,
nb_seq: usize,
) {
let Some(state) = state.as_ref() else {
return;
};
if state.seq.is_null()
|| state.pos.is_null()
|| state.pos_in_sequence.is_null()
|| state.size.is_null()
|| state.capacity.is_null()
{
return;
}
unsafe {
*state.seq = seq;
*state.size = nb_seq;
*state.capacity = nb_seq;
*state.pos = 0;
*state.pos_in_sequence = 0;
}
}
/// Explicit projection of the state used by `ZSTD_compress_frameChunk`.
///
/// The Rust side owns the per-frame block loop and its savings/dispatch
@@ -6214,6 +6263,54 @@ mod tests {
const ZSTD_BTOPT: c_int = 7;
const ZSTD_BTULTRA2: c_int = 9;
#[test]
fn reference_external_sequences_resets_store_state() {
let mut source = [0u8; 3];
let sequence = source.as_mut_ptr().cast::<c_void>();
let mut stored_sequence = ptr::null_mut();
let mut pos = 7;
let mut pos_in_sequence = 8;
let mut size = 9;
let mut capacity = 10;
let state = ZSTD_rust_externalSequenceStoreState {
seq: &mut stored_sequence,
pos: &mut pos,
pos_in_sequence: &mut pos_in_sequence,
size: &mut size,
capacity: &mut capacity,
};
unsafe { ZSTD_rust_referenceExternalSequences(&state, sequence, 11) };
assert_eq!(stored_sequence, sequence);
assert_eq!(pos, 0);
assert_eq!(pos_in_sequence, 0);
assert_eq!(size, 11);
assert_eq!(capacity, 11);
}
#[test]
fn reference_external_sequences_rejects_incomplete_state() {
let mut pos = 7;
let mut pos_in_sequence = 8;
let mut size = 9;
let mut capacity = 10;
let state = ZSTD_rust_externalSequenceStoreState {
seq: ptr::null_mut(),
pos: &mut pos,
pos_in_sequence: &mut pos_in_sequence,
size: &mut size,
capacity: &mut capacity,
};
unsafe { ZSTD_rust_referenceExternalSequences(&state, ptr::null_mut(), 11) };
assert_eq!(pos, 7);
assert_eq!(pos_in_sequence, 8);
assert_eq!(size, 9);
assert_eq!(capacity, 10);
}
#[derive(Default)]
struct ExternalSequenceProducerProbe {
events: Vec<&'static str>,