From 6caba856d40b51f4bac4b8f844550a6619d5a15c Mon Sep 17 00:00:00 2001 From: ddidderr Date: Mon, 20 Jul 2026 18:25:37 +0200 Subject: [PATCH] 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). --- rust/src/fileio_asyncio.rs | 99 +++++++++++++++++++++++++++++++++----- 1 file changed, 86 insertions(+), 13 deletions(-) diff --git a/rust/src/fileio_asyncio.rs b/rust/src/fileio_asyncio.rs index 225c79e39..fc2cc65ad 100644 --- a/rust/src/fileio_asyncio.rs +++ b/rust/src/fileio_asyncio.rs @@ -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 {