refactor(cli): derive window error log in Rust

Move the historical ceil(log2(windowSize)) calculation used by
FIO_zstdErrorHelp into Rust. C retains frame-header parsing, private read-pool
access, the ABI slot, callbacks, diagnostics, and output formatting. The
zero-size and non-power-of-two behavior remains explicit and tested at the
u64 boundary.

Test Plan:
- `ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo clippy --manifest-path rust/Cargo.toml --all-targets -- -D warnings` -- passed
- `ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo clippy --manifest-path rust/cli/Cargo.toml --all-targets -- -D warnings` -- passed
- `ulimit -v 41943040; cargo +nightly fmt --manifest-path rust/Cargo.toml --all -- --check` -- passed
- `ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo test --manifest-path rust/cli/Cargo.toml --all-targets` -- passed, 190 tests
- `ulimit -v 41943040; CARGO_BUILD_JOBS=1 make -j1` -- passed
- `ulimit -v 41943040; CARGO_BUILD_JOBS=1 ./tests/rustLibSmoke` -- passed
- `ulimit -v 41943040; CARGO_BUILD_JOBS=1 make -j1 -C tests test` -- passed, including large streaming, native, fuzzer, and zstream phases
This commit is contained in:
2026-07-20 19:29:56 +02:00
parent e9850abbb7
commit a152fe6498
2 changed files with 48 additions and 17 deletions
+1 -5
View File
@@ -3654,7 +3654,7 @@ typedef struct {
const char* srcFileName;
unsigned long long windowSize;
size_t headerError;
unsigned windowLog;
unsigned windowLog; /* Rust derives this from windowSize; retain ABI layout. */
unsigned memLimit;
int errorCode;
FIO_rust_zstdErrorHelpDisplayFn display;
@@ -3725,7 +3725,6 @@ FIO_zstdErrorHelp(const FIO_prefs_t* const prefs,
int const errorCode = (int)ZSTD_getErrorCode(err);
size_t headerError = 1;
unsigned long long windowSize = 0;
unsigned windowLog = 0;
unsigned memLimit = 0;
FIO_rust_zstdErrorHelpState state = { 0 };
@@ -3735,8 +3734,6 @@ FIO_zstdErrorHelp(const FIO_prefs_t* const prefs,
&header, ress->readCtx->srcBuffer, ress->readCtx->srcBufferLoaded);
if (headerError == 0) {
windowSize = header.windowSize;
windowLog = FIO_highbit64(windowSize)
+ ((windowSize & (windowSize - 1)) != 0);
memLimit = prefs->memLimit;
}
}
@@ -3745,7 +3742,6 @@ FIO_zstdErrorHelp(const FIO_prefs_t* const prefs,
state.srcFileName = srcFileName;
state.windowSize = windowSize;
state.headerError = headerError;
state.windowLog = windowLog;
state.memLimit = memLimit;
state.errorCode = errorCode;
state.display = FIO_rust_zstdErrorHelp_display;
+47 -12
View File
@@ -390,9 +390,10 @@ type FIO_rust_zstdErrorHelpDisplayFn =
/// Scalar projection for the zstd window-size error diagnostic.
///
/// C keeps frame-header decoding, window-log extraction, and output formatting
/// in C. Rust owns the error filter and selects the concrete or unsupported
/// diagnostic through the display callback.
/// C keeps frame-header decoding and output formatting in C. Rust derives the
/// historical window log, owns the error filter, and selects the concrete or
/// unsupported diagnostic through the display callback. The `window_log`
/// projection field remains part of the C ABI layout but is not consumed.
#[cfg(feature = "decompression")]
#[repr(C)]
pub struct FIO_rust_zstdErrorHelpState {
@@ -406,6 +407,16 @@ pub struct FIO_rust_zstdErrorHelpState {
display: Option<FIO_rust_zstdErrorHelpDisplayFn>,
}
#[cfg(feature = "decompression")]
#[inline]
fn ceil_log2_window_size(window_size: u64) -> c_uint {
if window_size == 0 {
return 0;
}
highbit64(window_size)
+ c_uint::from((window_size & window_size.wrapping_sub(1)) != 0)
}
#[cfg(feature = "decompression")]
const _: () = {
let callback_offset = (offset_of!(FIO_rust_zstdErrorHelpState, error_code)
@@ -448,6 +459,7 @@ pub unsafe extern "C" fn FIO_rust_zstdErrorHelp(state: *const FIO_rust_zstdError
let Some(display) = state.display else {
return;
};
let window_log = ceil_log2_window_size(state.window_size);
if state.header_error == 0 {
assert!(state.mem_limit > 0);
@@ -457,12 +469,12 @@ pub unsafe extern "C" fn FIO_rust_zstdErrorHelp(state: *const FIO_rust_zstdError
FIO_RUST_ZSTD_ERROR_HELP_WINDOW_SIZE,
state.src_file_name,
state.window_size,
state.window_log,
window_log,
0,
state.mem_limit,
);
}
if state.window_log <= ZSTD_WINDOWLOG_MAX {
if window_log <= ZSTD_WINDOWLOG_MAX {
let window_mb = ((state.window_size >> 20)
+ u64::from((state.window_size & ((1u64 << 20) - 1)) != 0))
as c_uint;
@@ -473,7 +485,7 @@ pub unsafe extern "C" fn FIO_rust_zstdErrorHelp(state: *const FIO_rust_zstdError
FIO_RUST_ZSTD_ERROR_HELP_WINDOW_GUIDANCE,
state.src_file_name,
state.window_size,
state.window_log,
window_log,
window_mb,
state.mem_limit,
);
@@ -488,7 +500,7 @@ pub unsafe extern "C" fn FIO_rust_zstdErrorHelp(state: *const FIO_rust_zstdError
FIO_RUST_ZSTD_ERROR_HELP_UNSUPPORTED_WINDOW_LOG,
state.src_file_name,
state.window_size,
state.window_log,
window_log,
0,
state.mem_limit,
);
@@ -2700,7 +2712,6 @@ mod tests {
error_code: c_int,
header_error: usize,
window_size: u64,
window_log: c_uint,
mem_limit: c_uint,
) -> FIO_rust_zstdErrorHelpState {
FIO_rust_zstdErrorHelpState {
@@ -2708,18 +2719,44 @@ mod tests {
src_file_name: ptr::null(),
window_size,
header_error,
window_log,
window_log: c_uint::MAX,
mem_limit,
error_code,
display: Some(zstd_error_help_display_test),
}
}
#[cfg(feature = "decompression")]
#[test]
fn ceil_log2_window_size_handles_zero_powers_non_powers_and_boundaries() {
let cases = [
(0, 0),
(1, 0),
(2, 1),
(4, 2),
(3, 2),
(5, 3),
((1u64 << 63) - 1, 63),
(1u64 << 63, 63),
((1u64 << 63) + 1, 64),
(u64::MAX - 1, 64),
(u64::MAX, 64),
];
for (window_size, expected_window_log) in cases {
assert_eq!(
ceil_log2_window_size(window_size),
expected_window_log,
"unexpected window log for window size {window_size}"
);
}
}
#[cfg(feature = "decompression")]
#[test]
fn zstd_error_help_ignores_irrelevant_errors() {
let mut context = ZstdErrorHelpTestState::default();
let state = zstd_error_help_test_state(&mut context, 0, 0, 8u64 << 20, 23, 64);
let state = zstd_error_help_test_state(&mut context, 0, 0, 8u64 << 20, 64);
unsafe { FIO_rust_zstdErrorHelp(&state) };
@@ -2735,7 +2772,6 @@ mod tests {
ZSTD_ERROR_FRAME_PARAMETER_WINDOW_TOO_LARGE,
0,
9u64 << 20,
24,
64,
);
@@ -2766,7 +2802,6 @@ mod tests {
ZSTD_ERROR_FRAME_PARAMETER_WINDOW_TOO_LARGE,
0,
1u64 << window_log,
window_log,
64,
);