refactor(cli): make decompression finish policy explicit in Rust

Extract the mixed-format decompression finish status mapping into a pure Rust policy helper and keep the existing callback side effects, diagnostics, and return values in the ABI wrapper. The explicit enum makes the success, pass-through, report, and impossible-status branches auditable and testable without widening the private fileio boundary.

Test Plan: ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo clippy --manifest-path rust/Cargo.toml --all-targets -- -D warnings; cargo +nightly fmt --manifest-path rust/Cargo.toml --all -- --check; make -j1; ./tests/rustLibSmoke; make -j1 -C tests test (all shell tests, large streaming tests, native tester, fuzzer phases, and zstream tester passed).
This commit is contained in:
2026-07-20 18:25:37 +02:00
parent 701bc899ad
commit 6caba856d4
+86 -13
View File
@@ -5218,6 +5218,31 @@ pub unsafe extern "C" fn FIO_rust_decompressFrames(
/// successful-file finalization. C keeps the diagnostic and accounting
/// callbacks because they touch `DISPLAY*` state and the private `FIO_ctx_t`
/// layout; Rust owns the result policy and decides which callback is legal.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum DecompressFinishAction {
Finish,
PassThrough,
ReportStatus,
Invalid,
}
fn classify_decompress_finish_status(status: c_int) -> DecompressFinishAction {
match status {
FIO_RUST_DECOMPRESS_OK => DecompressFinishAction::Finish,
FIO_RUST_DECOMPRESS_PASS_THROUGH => DecompressFinishAction::PassThrough,
FIO_RUST_DECOMPRESS_EMPTY_INPUT
| FIO_RUST_DECOMPRESS_SHORT_INPUT
| FIO_RUST_DECOMPRESS_GZIP_UNSUPPORTED
| FIO_RUST_DECOMPRESS_LZMA_UNSUPPORTED
| FIO_RUST_DECOMPRESS_LZ4_UNSUPPORTED
| FIO_RUST_DECOMPRESS_FRAME_ERROR
| FIO_RUST_DECOMPRESS_UNSUPPORTED_FORMAT
| FIO_RUST_DECOMPRESS_PASS_THROUGH_ERROR
| FIO_RUST_DECOMPRESS_ZSTD_UNSUPPORTED => DecompressFinishAction::ReportStatus,
_ => DecompressFinishAction::Invalid,
}
}
#[no_mangle]
pub unsafe extern "C" fn FIO_rust_finishDecompressFrames(
status: c_int,
@@ -5229,29 +5254,21 @@ pub unsafe extern "C" fn FIO_rust_finishDecompressFrames(
assert!(!callbacks.is_null());
let callbacks = unsafe { &*callbacks };
match status {
FIO_RUST_DECOMPRESS_OK => {
match classify_decompress_finish_status(status) {
DecompressFinishAction::Finish => {
if let Some(finish) = callbacks.finish {
unsafe { finish(callbacks.opaque, src_file_name, decoded_size) };
}
0
}
FIO_RUST_DECOMPRESS_PASS_THROUGH => 0,
FIO_RUST_DECOMPRESS_EMPTY_INPUT
| FIO_RUST_DECOMPRESS_SHORT_INPUT
| FIO_RUST_DECOMPRESS_GZIP_UNSUPPORTED
| FIO_RUST_DECOMPRESS_LZMA_UNSUPPORTED
| FIO_RUST_DECOMPRESS_LZ4_UNSUPPORTED
| FIO_RUST_DECOMPRESS_FRAME_ERROR
| FIO_RUST_DECOMPRESS_UNSUPPORTED_FORMAT
| FIO_RUST_DECOMPRESS_PASS_THROUGH_ERROR
| FIO_RUST_DECOMPRESS_ZSTD_UNSUPPORTED => {
DecompressFinishAction::PassThrough => 0,
DecompressFinishAction::ReportStatus => {
if let Some(report_status) = callbacks.report_status {
unsafe { report_status(callbacks.opaque, status, src_file_name) };
}
1
}
_ => {
DecompressFinishAction::Invalid => {
unreachable!("unknown Rust decompression status: {status}");
}
}
@@ -9208,6 +9225,62 @@ mod tests {
state.finished_sizes.push(decoded_size);
}
#[test]
fn classifies_decompression_finish_statuses() {
for (status, expected_action) in [
(FIO_RUST_DECOMPRESS_OK, DecompressFinishAction::Finish),
(
FIO_RUST_DECOMPRESS_PASS_THROUGH,
DecompressFinishAction::PassThrough,
),
(
FIO_RUST_DECOMPRESS_EMPTY_INPUT,
DecompressFinishAction::ReportStatus,
),
(
FIO_RUST_DECOMPRESS_SHORT_INPUT,
DecompressFinishAction::ReportStatus,
),
(
FIO_RUST_DECOMPRESS_GZIP_UNSUPPORTED,
DecompressFinishAction::ReportStatus,
),
(
FIO_RUST_DECOMPRESS_LZMA_UNSUPPORTED,
DecompressFinishAction::ReportStatus,
),
(
FIO_RUST_DECOMPRESS_LZ4_UNSUPPORTED,
DecompressFinishAction::ReportStatus,
),
(
FIO_RUST_DECOMPRESS_FRAME_ERROR,
DecompressFinishAction::ReportStatus,
),
(
FIO_RUST_DECOMPRESS_UNSUPPORTED_FORMAT,
DecompressFinishAction::ReportStatus,
),
(
FIO_RUST_DECOMPRESS_PASS_THROUGH_ERROR,
DecompressFinishAction::ReportStatus,
),
(
FIO_RUST_DECOMPRESS_ZSTD_UNSUPPORTED,
DecompressFinishAction::ReportStatus,
),
] {
assert_eq!(classify_decompress_finish_status(status), expected_action);
}
for status in [-1, 99] {
assert_eq!(
classify_decompress_finish_status(status),
DecompressFinishAction::Invalid
);
}
}
#[test]
fn maps_decompression_status_and_finishes_only_success() {
let mut state = DecompressResultState {