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:
+1
-5
@@ -3654,7 +3654,7 @@ typedef struct {
|
|||||||
const char* srcFileName;
|
const char* srcFileName;
|
||||||
unsigned long long windowSize;
|
unsigned long long windowSize;
|
||||||
size_t headerError;
|
size_t headerError;
|
||||||
unsigned windowLog;
|
unsigned windowLog; /* Rust derives this from windowSize; retain ABI layout. */
|
||||||
unsigned memLimit;
|
unsigned memLimit;
|
||||||
int errorCode;
|
int errorCode;
|
||||||
FIO_rust_zstdErrorHelpDisplayFn display;
|
FIO_rust_zstdErrorHelpDisplayFn display;
|
||||||
@@ -3725,7 +3725,6 @@ FIO_zstdErrorHelp(const FIO_prefs_t* const prefs,
|
|||||||
int const errorCode = (int)ZSTD_getErrorCode(err);
|
int const errorCode = (int)ZSTD_getErrorCode(err);
|
||||||
size_t headerError = 1;
|
size_t headerError = 1;
|
||||||
unsigned long long windowSize = 0;
|
unsigned long long windowSize = 0;
|
||||||
unsigned windowLog = 0;
|
|
||||||
unsigned memLimit = 0;
|
unsigned memLimit = 0;
|
||||||
FIO_rust_zstdErrorHelpState state = { 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);
|
&header, ress->readCtx->srcBuffer, ress->readCtx->srcBufferLoaded);
|
||||||
if (headerError == 0) {
|
if (headerError == 0) {
|
||||||
windowSize = header.windowSize;
|
windowSize = header.windowSize;
|
||||||
windowLog = FIO_highbit64(windowSize)
|
|
||||||
+ ((windowSize & (windowSize - 1)) != 0);
|
|
||||||
memLimit = prefs->memLimit;
|
memLimit = prefs->memLimit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3745,7 +3742,6 @@ FIO_zstdErrorHelp(const FIO_prefs_t* const prefs,
|
|||||||
state.srcFileName = srcFileName;
|
state.srcFileName = srcFileName;
|
||||||
state.windowSize = windowSize;
|
state.windowSize = windowSize;
|
||||||
state.headerError = headerError;
|
state.headerError = headerError;
|
||||||
state.windowLog = windowLog;
|
|
||||||
state.memLimit = memLimit;
|
state.memLimit = memLimit;
|
||||||
state.errorCode = errorCode;
|
state.errorCode = errorCode;
|
||||||
state.display = FIO_rust_zstdErrorHelp_display;
|
state.display = FIO_rust_zstdErrorHelp_display;
|
||||||
|
|||||||
+47
-12
@@ -390,9 +390,10 @@ type FIO_rust_zstdErrorHelpDisplayFn =
|
|||||||
|
|
||||||
/// Scalar projection for the zstd window-size error diagnostic.
|
/// Scalar projection for the zstd window-size error diagnostic.
|
||||||
///
|
///
|
||||||
/// C keeps frame-header decoding, window-log extraction, and output formatting
|
/// C keeps frame-header decoding and output formatting in C. Rust derives the
|
||||||
/// in C. Rust owns the error filter and selects the concrete or unsupported
|
/// historical window log, owns the error filter, and selects the concrete or
|
||||||
/// diagnostic through the display callback.
|
/// 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")]
|
#[cfg(feature = "decompression")]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct FIO_rust_zstdErrorHelpState {
|
pub struct FIO_rust_zstdErrorHelpState {
|
||||||
@@ -406,6 +407,16 @@ pub struct FIO_rust_zstdErrorHelpState {
|
|||||||
display: Option<FIO_rust_zstdErrorHelpDisplayFn>,
|
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")]
|
#[cfg(feature = "decompression")]
|
||||||
const _: () = {
|
const _: () = {
|
||||||
let callback_offset = (offset_of!(FIO_rust_zstdErrorHelpState, error_code)
|
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 {
|
let Some(display) = state.display else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
let window_log = ceil_log2_window_size(state.window_size);
|
||||||
|
|
||||||
if state.header_error == 0 {
|
if state.header_error == 0 {
|
||||||
assert!(state.mem_limit > 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,
|
FIO_RUST_ZSTD_ERROR_HELP_WINDOW_SIZE,
|
||||||
state.src_file_name,
|
state.src_file_name,
|
||||||
state.window_size,
|
state.window_size,
|
||||||
state.window_log,
|
window_log,
|
||||||
0,
|
0,
|
||||||
state.mem_limit,
|
state.mem_limit,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if state.window_log <= ZSTD_WINDOWLOG_MAX {
|
if window_log <= ZSTD_WINDOWLOG_MAX {
|
||||||
let window_mb = ((state.window_size >> 20)
|
let window_mb = ((state.window_size >> 20)
|
||||||
+ u64::from((state.window_size & ((1u64 << 20) - 1)) != 0))
|
+ u64::from((state.window_size & ((1u64 << 20) - 1)) != 0))
|
||||||
as c_uint;
|
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,
|
FIO_RUST_ZSTD_ERROR_HELP_WINDOW_GUIDANCE,
|
||||||
state.src_file_name,
|
state.src_file_name,
|
||||||
state.window_size,
|
state.window_size,
|
||||||
state.window_log,
|
window_log,
|
||||||
window_mb,
|
window_mb,
|
||||||
state.mem_limit,
|
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,
|
FIO_RUST_ZSTD_ERROR_HELP_UNSUPPORTED_WINDOW_LOG,
|
||||||
state.src_file_name,
|
state.src_file_name,
|
||||||
state.window_size,
|
state.window_size,
|
||||||
state.window_log,
|
window_log,
|
||||||
0,
|
0,
|
||||||
state.mem_limit,
|
state.mem_limit,
|
||||||
);
|
);
|
||||||
@@ -2700,7 +2712,6 @@ mod tests {
|
|||||||
error_code: c_int,
|
error_code: c_int,
|
||||||
header_error: usize,
|
header_error: usize,
|
||||||
window_size: u64,
|
window_size: u64,
|
||||||
window_log: c_uint,
|
|
||||||
mem_limit: c_uint,
|
mem_limit: c_uint,
|
||||||
) -> FIO_rust_zstdErrorHelpState {
|
) -> FIO_rust_zstdErrorHelpState {
|
||||||
FIO_rust_zstdErrorHelpState {
|
FIO_rust_zstdErrorHelpState {
|
||||||
@@ -2708,18 +2719,44 @@ mod tests {
|
|||||||
src_file_name: ptr::null(),
|
src_file_name: ptr::null(),
|
||||||
window_size,
|
window_size,
|
||||||
header_error,
|
header_error,
|
||||||
window_log,
|
window_log: c_uint::MAX,
|
||||||
mem_limit,
|
mem_limit,
|
||||||
error_code,
|
error_code,
|
||||||
display: Some(zstd_error_help_display_test),
|
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")]
|
#[cfg(feature = "decompression")]
|
||||||
#[test]
|
#[test]
|
||||||
fn zstd_error_help_ignores_irrelevant_errors() {
|
fn zstd_error_help_ignores_irrelevant_errors() {
|
||||||
let mut context = ZstdErrorHelpTestState::default();
|
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) };
|
unsafe { FIO_rust_zstdErrorHelp(&state) };
|
||||||
|
|
||||||
@@ -2735,7 +2772,6 @@ mod tests {
|
|||||||
ZSTD_ERROR_FRAME_PARAMETER_WINDOW_TOO_LARGE,
|
ZSTD_ERROR_FRAME_PARAMETER_WINDOW_TOO_LARGE,
|
||||||
0,
|
0,
|
||||||
9u64 << 20,
|
9u64 << 20,
|
||||||
24,
|
|
||||||
64,
|
64,
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -2766,7 +2802,6 @@ mod tests {
|
|||||||
ZSTD_ERROR_FRAME_PARAMETER_WINDOW_TOO_LARGE,
|
ZSTD_ERROR_FRAME_PARAMETER_WINDOW_TOO_LARGE,
|
||||||
0,
|
0,
|
||||||
1u64 << window_log,
|
1u64 << window_log,
|
||||||
window_log,
|
|
||||||
64,
|
64,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user