feat(cli): move zstd frame result policy to Rust

The default zstd frame loop was already implemented in Rust, but its
completion and error-result policy still lived in the C callback wrapper.
That left the C translation unit deciding when a decoded size was valid and
when a decoding or premature-end status had to become the historical frame
sentinel. Keep the exact operator-facing diagnostics and the private
asynchronous-resource pointers in C, while giving Rust ownership of the
status-to-result policy and callback ordering.

The new C/Rust policy record has compile-time layout assertions on both sides,
and the Rust fixture covers success, decode error, premature end, sentinel
results, and callback sequencing. This keeps the bridge explicit without
making Rust depend on the private dRess_t layout.

Test Plan:
- ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo check --manifest-path rust/Cargo.toml --tests
- ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo clippy --manifest-path rust/cli/Cargo.toml --all-targets -- -D warnings
- ulimit -v 41943040; make -j1
- ulimit -v 41943040; make -j1 -C tests test
- git diff --check
This commit is contained in:
2026-07-21 16:05:56 +02:00
parent cf8953eed2
commit bf2d73fcc0
2 changed files with 254 additions and 38 deletions
+69 -37
View File
@@ -573,6 +573,42 @@ int FIO_rust_decompressZstdFrames(void* fCtx,
U64* decodedSize,
size_t* zstdError,
FIO_rust_frame_progress_fn progress);
typedef void (*FIO_rust_zstd_frame_decoding_error_fn)(void* opaque,
const char* srcFileName,
size_t zstdError);
typedef void (*FIO_rust_zstd_frame_premature_end_fn)(void* opaque,
const char* srcFileName);
typedef struct {
void* callbackContext;
void* fCtx;
void* dctx;
ReadPoolCtx_t* readCtx;
WritePoolCtx_t* writeCtx;
const char* srcFileName;
U64 alreadyDecoded;
FIO_rust_frame_progress_fn progress;
FIO_rust_zstd_frame_decoding_error_fn displayDecodingError;
FIO_rust_zstd_frame_premature_end_fn displayPrematureEnd;
} FIO_rust_zstd_frame_policy_state;
typedef char FIO_rust_zstd_frame_policy_state_layout[
(offsetof(FIO_rust_zstd_frame_policy_state, callbackContext) == 0
&& offsetof(FIO_rust_zstd_frame_policy_state, fCtx) == sizeof(void*)
&& offsetof(FIO_rust_zstd_frame_policy_state, dctx) == 2 * sizeof(void*)
&& offsetof(FIO_rust_zstd_frame_policy_state, readCtx) == 3 * sizeof(void*)
&& offsetof(FIO_rust_zstd_frame_policy_state, writeCtx) == 4 * sizeof(void*)
&& offsetof(FIO_rust_zstd_frame_policy_state, srcFileName) == 5 * sizeof(void*)
&& offsetof(FIO_rust_zstd_frame_policy_state, alreadyDecoded) == 6 * sizeof(void*)
&& offsetof(FIO_rust_zstd_frame_policy_state, progress) == 7 * sizeof(void*)
&& offsetof(FIO_rust_zstd_frame_policy_state, displayDecodingError)
== 8 * sizeof(void*)
&& offsetof(FIO_rust_zstd_frame_policy_state, displayPrematureEnd)
== 9 * sizeof(void*)
&& sizeof(FIO_rust_zstd_frame_policy_state) == 10 * sizeof(void*)
&& sizeof(FIO_rust_zstd_frame_decoding_error_fn) == sizeof(void*)
&& sizeof(FIO_rust_zstd_frame_premature_end_fn) == sizeof(void*))
? 1 : -1];
U64 FIO_rust_decompressZstdFramePolicy(
const FIO_rust_zstd_frame_policy_state* state);
enum {
FIO_RUST_DECOMPRESS_OK = 0,
FIO_RUST_DECOMPRESS_PASS_THROUGH = 1,
@@ -4177,38 +4213,6 @@ FIO_decompressZstdFrameProgress(void* const opaque,
}
}
static unsigned long long
FIO_decompressZstdFrames(FIO_ctx_t* const fCtx, dRess_t* ress,
const FIO_prefs_t* const prefs,
const char* srcFileName,
U64 alreadyDecoded) /* for multi-frames streams */
{
U64 decodedSize = 0;
size_t zstdError = 0;
int const status = FIO_rust_decompressZstdFrames(
fCtx, ress->dctx, ress->readCtx, ress->writeCtx, srcFileName,
alreadyDecoded, &decodedSize, &zstdError,
FIO_decompressZstdFrameProgress);
int const action = FIO_rust_decompressZstdFrameAction(status);
switch (action) {
case FIO_RUST_ZSTD_FRAME_ACTION_OK:
return decodedSize;
case FIO_RUST_ZSTD_FRAME_ACTION_DECODING_ERROR:
DISPLAYLEVEL(1, "%s : Decoding error (36) : %s \n",
srcFileName, ZSTD_getErrorName(zstdError));
FIO_zstdErrorHelp(prefs, ress, zstdError, srcFileName);
return FIO_ERROR_FRAME_DECODING;
case FIO_RUST_ZSTD_FRAME_ACTION_PREMATURE_END:
DISPLAYLEVEL(1, "%s : Read error (39) : premature end \n",
srcFileName);
return FIO_ERROR_FRAME_DECODING;
default:
assert(0);
return FIO_ERROR_FRAME_DECODING;
}
}
/* Rust owns the mixed-format loop, while these adapters keep each codec and
* the private dRess_t layout in this C translation unit. */
@@ -4539,6 +4543,25 @@ static int FIO_rust_decompressLz4FrameCallback(void* opaque,
}
#endif
static void FIO_rust_decompressZstdFrame_displayDecodingError(
void* opaque, const char* srcFileName, size_t zstdError)
{
FIO_rust_decompression_projection_t* const projection =
(FIO_rust_decompression_projection_t*)opaque;
DISPLAYLEVEL(1, "%s : Decoding error (36) : %s \n",
srcFileName, ZSTD_getErrorName(zstdError));
FIO_zstdErrorHelp(projection->prefs, projection->ress,
zstdError, srcFileName);
}
static void FIO_rust_decompressZstdFrame_displayPrematureEnd(
void* opaque, const char* srcFileName)
{
(void)opaque;
DISPLAYLEVEL(1, "%s : Read error (39) : premature end \n",
srcFileName);
}
static int FIO_rust_decompressZstdFrameCallback(void* opaque,
const char* srcFileName,
U64 alreadyDecoded,
@@ -4548,13 +4571,22 @@ static int FIO_rust_decompressZstdFrameCallback(void* opaque,
{
FIO_rust_decompression_projection_t* const projection =
(FIO_rust_decompression_projection_t*)opaque;
FIO_rust_zstd_frame_policy_state state;
(void)mode;
state.callbackContext = projection;
state.fCtx = projection->fCtx;
state.dctx = projection->ress->dctx;
state.readCtx = projection->ress->readCtx;
state.writeCtx = projection->ress->writeCtx;
state.srcFileName = srcFileName;
state.alreadyDecoded = alreadyDecoded;
state.progress = FIO_decompressZstdFrameProgress;
state.displayDecodingError =
FIO_rust_decompressZstdFrame_displayDecodingError;
state.displayPrematureEnd =
FIO_rust_decompressZstdFrame_displayPrematureEnd;
*errorCode = 0;
*frameSize = FIO_decompressZstdFrames(projection->fCtx,
projection->ress,
projection->prefs,
srcFileName,
alreadyDecoded);
*frameSize = FIO_rust_decompressZstdFramePolicy(&state);
return *frameSize == FIO_ERROR_FRAME_DECODING;
}