feat(cli): move shared destination lifecycle to Rust
Move the warning, destination open/attach, shared file iteration, and close ordering for multi-file compression and decompression into Rust orchestration. The C side retains the private preferences/resources, filesystem callbacks, write-pool operations, diagnostics, and exception behavior behind opaque callbacks. Decompression test mode continues to skip destination I/O. Add explicit C/Rust projection layout assertions and focused lifecycle tests covering callback order, open failure, aggregate file errors, and test mode. Test Plan: - git diff --check - ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo check --manifest-path rust/Cargo.toml --tests - ulimit -v 41943040; make -j1 - ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo clippy --manifest-path rust/cli/Cargo.toml --all-targets -- -D warnings - capped two-input shared-destination compression/decompression smoke test
This commit is contained in:
+175
-44
@@ -1388,6 +1388,44 @@ typedef char FIO_rust_compress_multiple_projection_size[
|
||||
int FIO_rust_compressMultipleFilenames(
|
||||
const FIO_rust_compress_multiple_projection_t* projection);
|
||||
|
||||
typedef int (*FIO_rust_multiple_destination_warning_fn)(void* opaque);
|
||||
typedef void* (*FIO_rust_multiple_destination_open_fn)(void* opaque);
|
||||
typedef void (*FIO_rust_multiple_destination_attach_fn)(
|
||||
void* opaque, void* destination);
|
||||
typedef int (*FIO_rust_multiple_destination_close_fn)(void* opaque);
|
||||
typedef struct {
|
||||
const FIO_rust_compress_multiple_projection_t* files;
|
||||
FIO_rust_multiple_destination_warning_fn warning;
|
||||
FIO_rust_multiple_destination_open_fn openDestination;
|
||||
FIO_rust_multiple_destination_attach_fn attachDestination;
|
||||
FIO_rust_multiple_destination_close_fn closeDestination;
|
||||
} FIO_rust_compress_multiple_destination_projection_t;
|
||||
typedef char FIO_rust_compress_multiple_destination_files_offset[
|
||||
(offsetof(FIO_rust_compress_multiple_destination_projection_t, files)
|
||||
== 0) ? 1 : -1];
|
||||
typedef char FIO_rust_compress_multiple_destination_warning_offset[
|
||||
(offsetof(FIO_rust_compress_multiple_destination_projection_t, warning)
|
||||
== sizeof(void*)) ? 1 : -1];
|
||||
typedef char FIO_rust_compress_multiple_destination_open_offset[
|
||||
(offsetof(FIO_rust_compress_multiple_destination_projection_t, openDestination)
|
||||
== 2 * sizeof(void*)) ? 1 : -1];
|
||||
typedef char FIO_rust_compress_multiple_destination_attach_offset[
|
||||
(offsetof(FIO_rust_compress_multiple_destination_projection_t, attachDestination)
|
||||
== 3 * sizeof(void*)) ? 1 : -1];
|
||||
typedef char FIO_rust_compress_multiple_destination_close_offset[
|
||||
(offsetof(FIO_rust_compress_multiple_destination_projection_t, closeDestination)
|
||||
== 4 * sizeof(void*)) ? 1 : -1];
|
||||
typedef char FIO_rust_compress_multiple_destination_callback_size[
|
||||
(sizeof(FIO_rust_multiple_destination_warning_fn) == sizeof(void*)
|
||||
&& sizeof(FIO_rust_multiple_destination_open_fn) == sizeof(void*)
|
||||
&& sizeof(FIO_rust_multiple_destination_attach_fn) == sizeof(void*)
|
||||
&& sizeof(FIO_rust_multiple_destination_close_fn) == sizeof(void*)) ? 1 : -1];
|
||||
typedef char FIO_rust_compress_multiple_destination_projection_size[
|
||||
(sizeof(FIO_rust_compress_multiple_destination_projection_t)
|
||||
== 5 * sizeof(void*)) ? 1 : -1];
|
||||
int FIO_rust_compressMultipleFilenamesWithDestination(
|
||||
const FIO_rust_compress_multiple_destination_projection_t* projection);
|
||||
|
||||
typedef int (*FIO_rust_compress_multiple_separate_file_fn)(
|
||||
void* opaque, const char* srcFileName);
|
||||
/* Rust selects the destination-mode callback; both callbacks retain their
|
||||
@@ -1456,6 +1494,40 @@ typedef char FIO_rust_decompress_multiple_projection_size[
|
||||
int FIO_rust_decompressMultipleFilenames(
|
||||
const FIO_rust_decompress_multiple_projection_t* projection);
|
||||
|
||||
typedef struct {
|
||||
const FIO_rust_decompress_multiple_projection_t* files;
|
||||
int destinationEnabled;
|
||||
FIO_rust_multiple_destination_warning_fn warning;
|
||||
FIO_rust_multiple_destination_open_fn openDestination;
|
||||
FIO_rust_multiple_destination_attach_fn attachDestination;
|
||||
FIO_rust_multiple_destination_close_fn closeDestination;
|
||||
} FIO_rust_decompress_multiple_destination_projection_t;
|
||||
typedef char FIO_rust_decompress_multiple_destination_files_offset[
|
||||
(offsetof(FIO_rust_decompress_multiple_destination_projection_t, files)
|
||||
== 0) ? 1 : -1];
|
||||
typedef char FIO_rust_decompress_multiple_destination_enabled_offset[
|
||||
(offsetof(FIO_rust_decompress_multiple_destination_projection_t, destinationEnabled)
|
||||
== sizeof(void*)) ? 1 : -1];
|
||||
typedef char FIO_rust_decompress_multiple_destination_warning_offset[
|
||||
(offsetof(FIO_rust_decompress_multiple_destination_projection_t, warning)
|
||||
== 2 * sizeof(void*)) ? 1 : -1];
|
||||
typedef char FIO_rust_decompress_multiple_destination_open_offset[
|
||||
(offsetof(FIO_rust_decompress_multiple_destination_projection_t, openDestination)
|
||||
== 3 * sizeof(void*)) ? 1 : -1];
|
||||
typedef char FIO_rust_decompress_multiple_destination_attach_offset[
|
||||
(offsetof(FIO_rust_decompress_multiple_destination_projection_t, attachDestination)
|
||||
== 4 * sizeof(void*)) ? 1 : -1];
|
||||
typedef char FIO_rust_decompress_multiple_destination_close_offset[
|
||||
(offsetof(FIO_rust_decompress_multiple_destination_projection_t, closeDestination)
|
||||
== 5 * sizeof(void*)) ? 1 : -1];
|
||||
typedef char FIO_rust_decompress_multiple_destination_int_size[
|
||||
(sizeof(int) <= sizeof(void*)) ? 1 : -1];
|
||||
typedef char FIO_rust_decompress_multiple_destination_projection_size[
|
||||
(sizeof(FIO_rust_decompress_multiple_destination_projection_t)
|
||||
== 6 * sizeof(void*)) ? 1 : -1];
|
||||
int FIO_rust_decompressMultipleFilenamesWithDestination(
|
||||
const FIO_rust_decompress_multiple_destination_projection_t* projection);
|
||||
|
||||
typedef int (*FIO_rust_decompress_multiple_separate_file_fn)(
|
||||
void* opaque, const char* srcFileName);
|
||||
typedef struct {
|
||||
@@ -3692,8 +3764,43 @@ typedef struct {
|
||||
FIO_prefs_t* prefs;
|
||||
cRess_t* ress;
|
||||
int compressionLevel;
|
||||
const char* outFileName;
|
||||
} FIO_rust_compress_multiple_context_t;
|
||||
|
||||
static int FIO_rust_compressMultipleDestinationWarning(void* opaque)
|
||||
{
|
||||
FIO_rust_compress_multiple_context_t* const context =
|
||||
(FIO_rust_compress_multiple_context_t*)opaque;
|
||||
return FIO_multiFilesConcatWarning(
|
||||
context->fCtx, context->prefs, context->outFileName, 1 /* displayLevelCutoff */);
|
||||
}
|
||||
|
||||
static void* FIO_rust_compressMultipleDestinationOpen(void* opaque)
|
||||
{
|
||||
FIO_rust_compress_multiple_context_t* const context =
|
||||
(FIO_rust_compress_multiple_context_t*)opaque;
|
||||
return (void*)FIO_openDstFile(
|
||||
context->fCtx, context->prefs, NULL,
|
||||
context->outFileName, DEFAULT_FILE_PERMISSIONS);
|
||||
}
|
||||
|
||||
static void FIO_rust_compressMultipleDestinationAttach(void* opaque, void* destination)
|
||||
{
|
||||
FIO_rust_compress_multiple_context_t* const context =
|
||||
(FIO_rust_compress_multiple_context_t*)opaque;
|
||||
AIO_WritePool_setFile(context->ress->writeCtx, (FILE*)destination);
|
||||
}
|
||||
|
||||
static int FIO_rust_compressMultipleDestinationClose(void* opaque)
|
||||
{
|
||||
FIO_rust_compress_multiple_context_t* const context =
|
||||
(FIO_rust_compress_multiple_context_t*)opaque;
|
||||
if (AIO_WritePool_closeFile(context->ress->writeCtx))
|
||||
EXM_THROW(29, "Write error (%s) : cannot properly close %s",
|
||||
strerror(errno), context->outFileName);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int FIO_rust_compressMultipleFileCallback(void* opaque,
|
||||
const char* dstFileName,
|
||||
const char* srcFileName)
|
||||
@@ -3771,28 +3878,21 @@ int FIO_compressMultipleFilenames(FIO_ctx_t* const fCtx,
|
||||
/* init */
|
||||
assert(outFileName != NULL || suffix != NULL);
|
||||
if (outFileName != NULL) { /* output into a single destination (stdout typically) */
|
||||
FILE *dstFile;
|
||||
if (FIO_multiFilesConcatWarning(fCtx, prefs, outFileName, 1 /* displayLevelCutoff */)) {
|
||||
FIO_freeCResources(&ress);
|
||||
return 1;
|
||||
}
|
||||
dstFile = FIO_openDstFile(fCtx, prefs, NULL, outFileName, DEFAULT_FILE_PERMISSIONS);
|
||||
if (dstFile == NULL) { /* could not open outFileName */
|
||||
error = 1;
|
||||
} else {
|
||||
FIO_rust_compress_multiple_context_t callbackContext = {
|
||||
fCtx, prefs, &ress, compressionLevel
|
||||
};
|
||||
FIO_rust_compress_multiple_projection_t projection = {
|
||||
fCtx, inFileNamesTable, outFileName,
|
||||
&callbackContext, FIO_rust_compressMultipleFileCallback
|
||||
};
|
||||
AIO_WritePool_setFile(ress.writeCtx, dstFile);
|
||||
error = FIO_rust_compressMultipleFilenames(&projection);
|
||||
if (AIO_WritePool_closeFile(ress.writeCtx))
|
||||
EXM_THROW(29, "Write error (%s) : cannot properly close %s",
|
||||
strerror(errno), outFileName);
|
||||
}
|
||||
FIO_rust_compress_multiple_context_t callbackContext = {
|
||||
fCtx, prefs, &ress, compressionLevel, outFileName
|
||||
};
|
||||
FIO_rust_compress_multiple_projection_t files = {
|
||||
fCtx, inFileNamesTable, outFileName,
|
||||
&callbackContext, FIO_rust_compressMultipleFileCallback
|
||||
};
|
||||
FIO_rust_compress_multiple_destination_projection_t projection = {
|
||||
&files,
|
||||
FIO_rust_compressMultipleDestinationWarning,
|
||||
FIO_rust_compressMultipleDestinationOpen,
|
||||
FIO_rust_compressMultipleDestinationAttach,
|
||||
FIO_rust_compressMultipleDestinationClose
|
||||
};
|
||||
error = FIO_rust_compressMultipleFilenamesWithDestination(&projection);
|
||||
} else {
|
||||
FIO_rust_compress_multiple_separate_context_t callbackContext = {
|
||||
fCtx, prefs, &ress, outMirroredRootDirName,
|
||||
@@ -4899,8 +4999,45 @@ typedef struct {
|
||||
FIO_ctx_t* fCtx;
|
||||
FIO_prefs_t* prefs;
|
||||
dRess_t* ress;
|
||||
const char* outFileName;
|
||||
} FIO_rust_decompress_multiple_context_t;
|
||||
|
||||
static int FIO_rust_decompressMultipleDestinationWarning(void* opaque)
|
||||
{
|
||||
FIO_rust_decompress_multiple_context_t* const context =
|
||||
(FIO_rust_decompress_multiple_context_t*)opaque;
|
||||
return FIO_multiFilesConcatWarning(
|
||||
context->fCtx, context->prefs, context->outFileName, 1 /* displayLevelCutoff */);
|
||||
}
|
||||
|
||||
static void* FIO_rust_decompressMultipleDestinationOpen(void* opaque)
|
||||
{
|
||||
FIO_rust_decompress_multiple_context_t* const context =
|
||||
(FIO_rust_decompress_multiple_context_t*)opaque;
|
||||
FILE* const dstFile = FIO_openDstFile(
|
||||
context->fCtx, context->prefs, NULL,
|
||||
context->outFileName, DEFAULT_FILE_PERMISSIONS);
|
||||
if (dstFile == 0) EXM_THROW(19, "cannot open %s", context->outFileName);
|
||||
return (void*)dstFile;
|
||||
}
|
||||
|
||||
static void FIO_rust_decompressMultipleDestinationAttach(void* opaque, void* destination)
|
||||
{
|
||||
FIO_rust_decompress_multiple_context_t* const context =
|
||||
(FIO_rust_decompress_multiple_context_t*)opaque;
|
||||
AIO_WritePool_setFile(context->ress->writeCtx, (FILE*)destination);
|
||||
}
|
||||
|
||||
static int FIO_rust_decompressMultipleDestinationClose(void* opaque)
|
||||
{
|
||||
FIO_rust_decompress_multiple_context_t* const context =
|
||||
(FIO_rust_decompress_multiple_context_t*)opaque;
|
||||
if (AIO_WritePool_closeFile(context->ress->writeCtx))
|
||||
EXM_THROW(72, "Write error : %s : cannot properly close output file",
|
||||
strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Keep private source/destination operations, format dispatch, and
|
||||
* diagnostics in C; Rust owns per-file ordering and removal policy. */
|
||||
static int FIO_rust_decompressMultipleFileCallback(void* opaque,
|
||||
@@ -5015,28 +5152,22 @@ FIO_decompressMultipleFilenames(FIO_ctx_t* const fCtx,
|
||||
dRess_t ress = FIO_createDResources(prefs, dictFileName);
|
||||
|
||||
if (outFileName) {
|
||||
if (FIO_multiFilesConcatWarning(fCtx, prefs, outFileName, 1 /* displayLevelCutoff */)) {
|
||||
FIO_freeDResources(ress);
|
||||
return 1;
|
||||
}
|
||||
if (!prefs->testMode) {
|
||||
FILE* dstFile = FIO_openDstFile(fCtx, prefs, NULL, outFileName, DEFAULT_FILE_PERMISSIONS);
|
||||
if (dstFile == 0) EXM_THROW(19, "cannot open %s", outFileName);
|
||||
AIO_WritePool_setFile(ress.writeCtx, dstFile);
|
||||
}
|
||||
{
|
||||
FIO_rust_decompress_multiple_context_t callbackContext = {
|
||||
fCtx, prefs, &ress
|
||||
};
|
||||
FIO_rust_decompress_multiple_projection_t projection = {
|
||||
fCtx, srcNamesTable, outFileName,
|
||||
&callbackContext, FIO_rust_decompressMultipleFileCallback
|
||||
};
|
||||
error = FIO_rust_decompressMultipleFilenames(&projection);
|
||||
}
|
||||
if ((!prefs->testMode) && (AIO_WritePool_closeFile(ress.writeCtx)))
|
||||
EXM_THROW(72, "Write error : %s : cannot properly close output file",
|
||||
strerror(errno));
|
||||
FIO_rust_decompress_multiple_context_t callbackContext = {
|
||||
fCtx, prefs, &ress, outFileName
|
||||
};
|
||||
FIO_rust_decompress_multiple_projection_t files = {
|
||||
fCtx, srcNamesTable, outFileName,
|
||||
&callbackContext, FIO_rust_decompressMultipleFileCallback
|
||||
};
|
||||
FIO_rust_decompress_multiple_destination_projection_t projection = {
|
||||
&files,
|
||||
!prefs->testMode,
|
||||
FIO_rust_decompressMultipleDestinationWarning,
|
||||
FIO_rust_decompressMultipleDestinationOpen,
|
||||
FIO_rust_decompressMultipleDestinationAttach,
|
||||
FIO_rust_decompressMultipleDestinationClose
|
||||
};
|
||||
error = FIO_rust_decompressMultipleFilenamesWithDestination(&projection);
|
||||
} else {
|
||||
FIO_rust_decompress_multiple_separate_context_t callbackContext = {
|
||||
fCtx, prefs, &ress, outMirroredRootDirName, outDirName
|
||||
|
||||
Reference in New Issue
Block a user