feat(compress): move dictionary match-state publication to Rust

Replace the dictionary loader's C match-state publication callback with a live
field projection. Rust now publishes nextToUpdate, loadedDictEnd, and
forceNonContiguous at the existing orchestration point while C retains the
private match-state layout. Keep the window base indirect so a preceding
window update cannot leave Rust with a stale offset origin.

Test Plan:
- git diff --cached --check
- capped cargo check --tests
- capped cargo clippy --tests -- -A clippy::manual-bits -D warnings
- capped make -j1
- capped make -j1 -C tests test
This commit is contained in:
2026-07-21 22:44:37 +02:00
parent 6b8051b98a
commit 87b616c49b
2 changed files with 149 additions and 34 deletions
+120 -15
View File
@@ -129,17 +129,50 @@ type LoadDictionaryContentWindowUpdateFn =
unsafe extern "C" fn(context: *mut c_void, ldm: c_int, src: *const c_void, src_size: usize);
type LoadDictionaryContentSetLdmLoadedDictEndFn =
unsafe extern "C" fn(context: *mut c_void, iend: *const c_void, force_window: c_int);
type LoadDictionaryContentPublishMatchStateFn = unsafe extern "C" fn(
context: *mut c_void,
ip: *const c_void,
iend: *const c_void,
force_window: c_int,
deterministic_ref_prefix: c_int,
);
type LoadDictionaryContentFillLdmFn =
unsafe extern "C" fn(context: *mut c_void, ip: *const c_void, iend: *const c_void);
type LoadDictionaryContentOverflowCorrectFn =
unsafe extern "C" fn(context: *mut c_void, ip: *const c_void, iend: *const c_void);
/// Live match-state fields used when the dictionary loader publishes the
/// current prefix. The base is indirect because window updates may replace it
/// before this publication point.
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
struct ZSTD_rust_loadDictionaryContentMatchStatePublicationState {
base: *const *const u8,
next_to_update: *mut c_uint,
loaded_dict_end: *mut c_uint,
force_non_contiguous: *mut c_int,
}
const _: () = {
assert!(
offset_of!(ZSTD_rust_loadDictionaryContentMatchStatePublicationState, base) == 0
);
assert!(
offset_of!(
ZSTD_rust_loadDictionaryContentMatchStatePublicationState,
next_to_update
) == size_of::<usize>()
);
assert!(
offset_of!(
ZSTD_rust_loadDictionaryContentMatchStatePublicationState,
loaded_dict_end
) == 2 * size_of::<usize>()
);
assert!(
offset_of!(
ZSTD_rust_loadDictionaryContentMatchStatePublicationState,
force_non_contiguous
) == 3 * size_of::<usize>()
);
assert!(
size_of::<ZSTD_rust_loadDictionaryContentMatchStatePublicationState>()
== 4 * size_of::<usize>()
);
};
/// Direct projection for the Fast dictionary-table leaf.
///
/// C exposes pointers to the live scalar fields needed by the Fast leaf.
@@ -210,7 +243,7 @@ pub struct ZSTD_rust_loadDictionaryContentState {
assert_window_empty: LoadDictionaryContentAssertWindowEmptyFn,
window_update: LoadDictionaryContentWindowUpdateFn,
set_ldm_loaded_dict_end: LoadDictionaryContentSetLdmLoadedDictEndFn,
publish_match_state: LoadDictionaryContentPublishMatchStateFn,
publish_match_state: *const ZSTD_rust_loadDictionaryContentMatchStatePublicationState,
fill_ldm: LoadDictionaryContentFillLdmFn,
overflow_correct: LoadDictionaryContentOverflowCorrectFn,
fast_table: *const ZSTD_rust_loadDictionaryContentFastTableState,
@@ -229,7 +262,6 @@ const _: () = {
assert!(size_of::<LoadDictionaryContentAssertWindowEmptyFn>() == size_of::<usize>());
assert!(size_of::<LoadDictionaryContentWindowUpdateFn>() == size_of::<usize>());
assert!(size_of::<LoadDictionaryContentSetLdmLoadedDictEndFn>() == size_of::<usize>());
assert!(size_of::<LoadDictionaryContentPublishMatchStateFn>() == size_of::<usize>());
assert!(size_of::<LoadDictionaryContentFillLdmFn>() == size_of::<usize>());
assert!(size_of::<LoadDictionaryContentOverflowCorrectFn>() == size_of::<usize>());
assert!(offset_of!(ZSTD_rust_loadDictionaryContentFastTableState, hash_table) == 0);
@@ -314,6 +346,10 @@ const _: () = {
offset_of!(ZSTD_rust_loadDictionaryContentState, assert_c_params)
== 18 * size_of::<usize>()
);
assert!(
offset_of!(ZSTD_rust_loadDictionaryContentState, publish_match_state)
== 22 * size_of::<usize>()
);
assert!(
offset_of!(ZSTD_rust_loadDictionaryContentState, fast_table) == 25 * size_of::<usize>()
);
@@ -470,11 +506,35 @@ unsafe fn fill_double_fast_dictionary_table(
true
}
#[inline]
unsafe fn publish_dictionary_match_state(
publication: &ZSTD_rust_loadDictionaryContentMatchStatePublicationState,
ip: *const u8,
iend: *const u8,
force_window: usize,
deterministic_ref_prefix: usize,
) {
let base = unsafe { *publication.base };
unsafe {
*publication.next_to_update = ip.offset_from(base) as c_uint;
*publication.loaded_dict_end = if force_window != 0 {
0
} else {
iend.offset_from(base) as c_uint
};
*publication.force_non_contiguous = deterministic_ref_prefix as c_int;
}
}
unsafe fn load_dictionary_content(
state: &ZSTD_rust_loadDictionaryContentState,
src: *const c_void,
src_size: usize,
) -> usize {
if state.publish_match_state.is_null() {
return ERROR(ZstdErrorCode::Generic);
}
let match_state_publication = unsafe { &*state.publish_match_state };
unsafe { (state.assert_c_params)(state.callback_context) };
let load_ldm_dict = state.ldm_enabled != 0 && state.has_ldm_state != 0;
@@ -524,12 +584,12 @@ unsafe fn load_dictionary_content(
}
unsafe {
(state.publish_match_state)(
state.callback_context,
ip.cast(),
iend.cast(),
(state.force_window != 0) as c_int,
(state.deterministic_ref_prefix != 0) as c_int,
publish_dictionary_match_state(
match_state_publication,
ip,
iend,
state.force_window,
state.deterministic_ref_prefix,
)
};
@@ -6805,6 +6865,51 @@ mod tests {
);
}
#[test]
fn dictionary_match_state_projection_publishes_live_offsets() {
let input = [0u8; 64];
let mut base_ptr = input.as_ptr();
let mut next_to_update = 0u32;
let mut loaded_dict_end = 0u32;
let mut force_non_contiguous = 0i32;
let projection = ZSTD_rust_loadDictionaryContentMatchStatePublicationState {
base: &base_ptr,
next_to_update: &mut next_to_update,
loaded_dict_end: &mut loaded_dict_end,
force_non_contiguous: &mut force_non_contiguous,
};
unsafe {
publish_dictionary_match_state(
&projection,
input.as_ptr().add(7),
input.as_ptr().add(42),
0,
1,
)
};
assert_eq!(next_to_update, 7);
assert_eq!(loaded_dict_end, 42);
assert_eq!(force_non_contiguous, 1);
unsafe {
ptr::write(&mut base_ptr, input.as_ptr().add(3));
assert_eq!(*projection.base, input.as_ptr().add(3));
}
unsafe {
publish_dictionary_match_state(
&projection,
input.as_ptr().add(10),
input.as_ptr().add(30),
1,
0,
)
};
assert_eq!(next_to_update, 7);
assert_eq!(loaded_dict_end, 0);
assert_eq!(force_non_contiguous, 0);
}
#[test]
fn fast_dictionary_table_projection_dispatches_to_rust_leaf() {
let hash_log = 4u32;