feat(cli): move multi-file summary policy to Rust

The multi-file compression and decompression entry points already delegate
file iteration and resource-sensitive work to Rust, but each still kept the
final summary decision and progress-to-summary ordering in C. Move that
scalar policy into a Rust ABI function. The C side now supplies only exact
legacy display callbacks and unchanged format strings, while Rust receives
plain counters and a summary kind without exposing FIO, cRess, dRess, or
codec layouts. Focused unit tests cover both summary modes, callback order,
argument forwarding, and sessions that must not display a summary.

Test Plan:
- `git diff --check -- programs/fileio.c rust/src/fileio_asyncio.rs` -- passed
- `git diff --cached --check` -- passed
- `rustfmt --check --edition 2021 rust/src/fileio_asyncio.rs` -- parsed the file;
  reports pre-existing formatting differences elsewhere in the file, so no
  unrelated formatting was applied
- Cargo, make, and runtime tests were intentionally not run per worker scope
This commit is contained in:
2026-07-21 20:37:11 +02:00
parent f154f511dd
commit cc43ebac4e
2 changed files with 274 additions and 23 deletions
+94 -23
View File
@@ -292,6 +292,44 @@ typedef char FIO_rust_compression_params_size[
int FIO_shouldDisplayFileSummary(const FIO_ctx_t* fCtx);
int FIO_shouldDisplayMultipleFileSummary(const FIO_ctx_t* fCtx);
enum {
FIO_RUST_MULTIPLE_SUMMARY_DECOMPRESSION = 0,
FIO_RUST_MULTIPLE_SUMMARY_COMPRESSION = 1
};
typedef void (*FIO_rust_multiple_summary_progress_fn)(void* opaque);
typedef void (*FIO_rust_compress_multiple_summary_fn)(
void* opaque, int nbFilesProcessed, U64 totalBytesInput, U64 totalBytesOutput);
typedef void (*FIO_rust_decompress_multiple_summary_fn)(
void* opaque, int nbFilesProcessed, U64 totalBytesOutput);
typedef struct {
void* opaque;
FIO_rust_multiple_summary_progress_fn displayProgress;
FIO_rust_compress_multiple_summary_fn displayCompression;
FIO_rust_decompress_multiple_summary_fn displayDecompression;
} FIO_rust_multiple_summary_callbacks_t;
typedef char FIO_rust_multiple_summary_callback_sizes[
(sizeof(FIO_rust_multiple_summary_progress_fn) == sizeof(void*)
&& sizeof(FIO_rust_compress_multiple_summary_fn) == sizeof(void*)
&& sizeof(FIO_rust_decompress_multiple_summary_fn) == sizeof(void*)) ? 1 : -1];
typedef char FIO_rust_multiple_summary_opaque_offset[
(offsetof(FIO_rust_multiple_summary_callbacks_t, opaque) == 0) ? 1 : -1];
typedef char FIO_rust_multiple_summary_progress_offset[
(offsetof(FIO_rust_multiple_summary_callbacks_t, displayProgress)
== sizeof(void*)) ? 1 : -1];
typedef char FIO_rust_multiple_summary_compression_offset[
(offsetof(FIO_rust_multiple_summary_callbacks_t, displayCompression)
== 2 * sizeof(void*)) ? 1 : -1];
typedef char FIO_rust_multiple_summary_decompression_offset[
(offsetof(FIO_rust_multiple_summary_callbacks_t, displayDecompression)
== 3 * sizeof(void*)) ? 1 : -1];
typedef char FIO_rust_multiple_summary_callbacks_size[
(sizeof(FIO_rust_multiple_summary_callbacks_t) == 4 * sizeof(void*)) ? 1 : -1];
void FIO_rust_displayMultipleFileSummary(
int nbFilesTotal, int nbFilesProcessed,
U64 totalBytesInput, U64 totalBytesOutput, int summaryKind,
const FIO_rust_multiple_summary_callbacks_t* callbacks);
typedef void (*FIO_rust_multi_files_concat_fatal_fn)(void* opaque);
typedef void (*FIO_rust_multi_files_concat_warning_fn)(void* opaque,
int hasStdoutOutput,
@@ -1297,6 +1335,58 @@ static int FIO_multiFilesConcatWarning(const FIO_ctx_t* fCtx, FIO_prefs_t* prefs
outFileName, &callbacks);
}
/* Rust owns the final multi-file summary decision and ordering. These
* callbacks retain the exact C display sinks and format strings. */
static void FIO_rust_multipleSummaryDisplayProgress(void* opaque)
{
(void)opaque;
DISPLAY_PROGRESS("\r%79s\r", "");
}
static void FIO_rust_compressMultipleSummary(void* opaque, int nbFilesProcessed,
U64 totalBytesInput, U64 totalBytesOutput)
{
UTIL_HumanReadableSize_t const hr_isize =
UTIL_makeHumanReadableSize(totalBytesInput);
UTIL_HumanReadableSize_t const hr_osize =
UTIL_makeHumanReadableSize(totalBytesOutput);
(void)opaque;
if (totalBytesInput == 0) {
DISPLAY_SUMMARY("%3d files compressed : (%6.*f%4s => %6.*f%4s)\n",
nbFilesProcessed,
hr_isize.precision, hr_isize.value, hr_isize.suffix,
hr_osize.precision, hr_osize.value, hr_osize.suffix);
} else {
DISPLAY_SUMMARY("%3d files compressed : %.2f%% (%6.*f%4s => %6.*f%4s)\n",
nbFilesProcessed,
(double)totalBytesOutput/(double)totalBytesInput*100,
hr_isize.precision, hr_isize.value, hr_isize.suffix,
hr_osize.precision, hr_osize.value, hr_osize.suffix);
}
}
static void FIO_rust_decompressMultipleSummary(void* opaque, int nbFilesProcessed,
U64 totalBytesOutput)
{
(void)opaque;
DISPLAY_SUMMARY("%d files decompressed : %6llu bytes total \n",
nbFilesProcessed, (unsigned long long)totalBytesOutput);
}
static void FIO_displayMultipleFileSummary(const FIO_ctx_t* fCtx, int summaryKind)
{
FIO_rust_multiple_summary_callbacks_t callbacks;
callbacks.opaque = NULL;
callbacks.displayProgress = FIO_rust_multipleSummaryDisplayProgress;
callbacks.displayCompression = FIO_rust_compressMultipleSummary;
callbacks.displayDecompression = FIO_rust_decompressMultipleSummary;
FIO_rust_displayMultipleFileSummary(
fCtx->nbFilesTotal, fCtx->nbFilesProcessed,
(U64)fCtx->totalBytesInput, (U64)fCtx->totalBytesOutput,
summaryKind, &callbacks);
}
#ifndef ZSTD_NOCOMPRESS
/* **********************************************************************
@@ -3913,24 +4003,8 @@ int FIO_compressMultipleFilenames(FIO_ctx_t* const fCtx,
FIO_checkFilenameCollisions(inFileNamesTable , (unsigned)fCtx->nbFilesTotal);
}
if (FIO_shouldDisplayMultipleFileSummary(fCtx)) {
UTIL_HumanReadableSize_t hr_isize = UTIL_makeHumanReadableSize((U64) fCtx->totalBytesInput);
UTIL_HumanReadableSize_t hr_osize = UTIL_makeHumanReadableSize((U64) fCtx->totalBytesOutput);
DISPLAY_PROGRESS("\r%79s\r", "");
if (fCtx->totalBytesInput == 0) {
DISPLAY_SUMMARY("%3d files compressed : (%6.*f%4s => %6.*f%4s)\n",
fCtx->nbFilesProcessed,
hr_isize.precision, hr_isize.value, hr_isize.suffix,
hr_osize.precision, hr_osize.value, hr_osize.suffix);
} else {
DISPLAY_SUMMARY("%3d files compressed : %.2f%% (%6.*f%4s => %6.*f%4s)\n",
fCtx->nbFilesProcessed,
(double)fCtx->totalBytesOutput/((double)fCtx->totalBytesInput)*100,
hr_isize.precision, hr_isize.value, hr_isize.suffix,
hr_osize.precision, hr_osize.value, hr_osize.suffix);
}
}
FIO_displayMultipleFileSummary(
fCtx, FIO_RUST_MULTIPLE_SUMMARY_COMPRESSION);
FIO_freeCResources(&ress);
return error;
@@ -5185,11 +5259,8 @@ FIO_decompressMultipleFilenames(FIO_ctx_t* const fCtx,
FIO_checkFilenameCollisions(srcNamesTable , (unsigned)fCtx->nbFilesTotal);
}
if (FIO_shouldDisplayMultipleFileSummary(fCtx)) {
DISPLAY_PROGRESS("\r%79s\r", "");
DISPLAY_SUMMARY("%d files decompressed : %6llu bytes total \n",
fCtx->nbFilesProcessed, (unsigned long long)fCtx->totalBytesOutput);
}
FIO_displayMultipleFileSummary(
fCtx, FIO_RUST_MULTIPLE_SUMMARY_DECOMPRESSION);
FIO_freeDResources(ress);
return error;