refactor(cli): classify dictionary load diagnostics in Rust

The file-I/O wrapper already delegated dictionary loading to Rust but kept
all status interpretation in C. That duplicated the malloc and mmap status
families and made the platform-specific error branches part of the C policy
surface. Add a Rust classifier that maps the shared numeric loader statuses
to diagnostic actions, including the distinct mmap failure classes. Keep
metadata lookup, platform handles, ownership, and the exact EXM_THROW text
in C, where the configured platform APIs still belong. The classifier also
rejects out-of-range type/status values; the valid malloc and mmap enums
intentionally share numeric values and therefore cannot be distinguished
beyond their family tag.

Test Plan:
- `ulimit -v 41943040; cargo +nightly fmt --manifest-path rust/Cargo.toml --all -- --check` -- passed
- `ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo clippy --manifest-path rust/cli/Cargo.toml --all-targets -- -D warnings` -- passed
- `ulimit -v 41943040; CARGO_BUILD_JOBS=1 cargo test --manifest-path rust/cli/Cargo.toml --all-targets` -- passed (192 tests)
- Broader native and original-test verification remains pending for the complete batch.
This commit is contained in:
2026-07-20 19:47:31 +02:00
parent d714aeac23
commit ee6953b1d7
2 changed files with 198 additions and 46 deletions
+64 -43
View File
@@ -378,6 +378,20 @@ int FIO_rust_setDictBufferMalloc(const char* fileName,
size_t maxSize,
void** buffer,
size_t* loadedSize);
/* Rust owns the dictionary-loader status classification. C keeps the
* metadata, ownership handles, and exact diagnostics around the existing
* narrow loader status ABI. */
enum {
FIO_RUST_DICT_DIAGNOSTIC_OK = 0,
FIO_RUST_DICT_DIAGNOSTIC_OPEN_FAILED = 1,
FIO_RUST_DICT_DIAGNOSTIC_TOO_LARGE = 2,
FIO_RUST_DICT_DIAGNOSTIC_ALLOCATION_FAILED = 3,
FIO_RUST_DICT_DIAGNOSTIC_READ_FAILED = 4,
FIO_RUST_DICT_DIAGNOSTIC_MAP_FAILED = 5,
FIO_RUST_DICT_DIAGNOSTIC_VIEW_FAILED = 6,
FIO_RUST_DICT_DIAGNOSTIC_INVALID = 7,
};
int FIO_rust_dictLoadDiagnostic(int dictBufferType, int status);
#if (PLATFORM_POSIX_VERSION > 0) || defined(_MSC_VER) || defined(_WIN32)
enum {
FIO_DICT_MMAP_SUCCESS = 0,
@@ -805,6 +819,7 @@ static size_t FIO_setDictBufferMalloc(FIO_Dict_t* dict, const char* fileName, FI
FIO_DICT_LOAD_READ_FAILED = 4,
};
int status;
int diagnostic;
assert(bufferPtr != NULL);
assert(dictFileStat != NULL);
@@ -824,23 +839,24 @@ static size_t FIO_setDictBufferMalloc(FIO_Dict_t* dict, const char* fileName, FI
dictSizeMax,
bufferPtr,
&loadedSize);
if (status == FIO_DICT_LOAD_SUCCESS) return loadedSize;
if (status == FIO_DICT_LOAD_OPEN_FAILED) {
EXM_THROW(33, "Couldn't open dictionary %s: %s", fileName, strerror(errno));
diagnostic = FIO_rust_dictLoadDiagnostic((int)FIO_mallocDict, status);
switch (diagnostic) {
case FIO_RUST_DICT_DIAGNOSTIC_OK:
return loadedSize;
case FIO_RUST_DICT_DIAGNOSTIC_OPEN_FAILED:
EXM_THROW(33, "Couldn't open dictionary %s: %s", fileName, strerror(errno));
case FIO_RUST_DICT_DIAGNOSTIC_TOO_LARGE:
EXM_THROW(34, "Dictionary file %s is too large (> %u bytes)",
fileName, (unsigned)dictSizeMax); /* avoid extreme cases */
case FIO_RUST_DICT_DIAGNOSTIC_ALLOCATION_FAILED:
EXM_THROW(34, "%s", strerror(errno));
case FIO_RUST_DICT_DIAGNOSTIC_READ_FAILED:
EXM_THROW(35, "Error reading dictionary file %s : %s",
fileName, strerror(errno));
default:
assert(0); /* unexpected Rust diagnostic */
return 0;
}
if (status == FIO_DICT_LOAD_TOO_LARGE) {
EXM_THROW(34, "Dictionary file %s is too large (> %u bytes)",
fileName, (unsigned)dictSizeMax); /* avoid extreme cases */
}
if (status == FIO_DICT_LOAD_ALLOCATION_FAILED) {
EXM_THROW(34, "%s", strerror(errno));
}
if (status == FIO_DICT_LOAD_READ_FAILED) {
EXM_THROW(35, "Error reading dictionary file %s : %s",
fileName, strerror(errno));
}
assert(0); /* unexpected Rust status */
return 0;
}
#if (PLATFORM_POSIX_VERSION > 0)
@@ -850,6 +866,7 @@ static size_t FIO_setDictBufferMMap(FIO_Dict_t* dict, const char* fileName, FIO_
size_t const dictSizeMax = prefs->patchFromMode ? prefs->memLimit : DICTSIZE_MAX;
void** bufferPtr = &dict->dictBuffer;
int status;
int diagnostic;
assert(bufferPtr != NULL);
assert(dictFileStat != NULL);
@@ -870,19 +887,21 @@ static size_t FIO_setDictBufferMMap(FIO_Dict_t* dict, const char* fileName, FIO_
bufferPtr,
&dict->dictBufferSize,
NULL);
if (status == FIO_DICT_MMAP_SUCCESS) return dict->dictBufferSize;
if (status == FIO_DICT_MMAP_OPEN_FAILED) {
EXM_THROW(33, "Couldn't open dictionary %s: %s", fileName, strerror(errno));
diagnostic = FIO_rust_dictLoadDiagnostic((int)FIO_mmapDict, status);
switch (diagnostic) {
case FIO_RUST_DICT_DIAGNOSTIC_OK:
return dict->dictBufferSize;
case FIO_RUST_DICT_DIAGNOSTIC_OPEN_FAILED:
EXM_THROW(33, "Couldn't open dictionary %s: %s", fileName, strerror(errno));
case FIO_RUST_DICT_DIAGNOSTIC_TOO_LARGE:
EXM_THROW(34, "Dictionary file %s is too large (> %u bytes)",
fileName, (unsigned)dictSizeMax); /* avoid extreme cases */
case FIO_RUST_DICT_DIAGNOSTIC_MAP_FAILED:
EXM_THROW(34, "%s", strerror(errno));
default:
assert(0); /* unexpected Rust diagnostic */
return 0;
}
if (status == FIO_DICT_MMAP_TOO_LARGE) {
EXM_THROW(34, "Dictionary file %s is too large (> %u bytes)",
fileName, (unsigned)dictSizeMax); /* avoid extreme cases */
}
if (status == FIO_DICT_MMAP_FAILED) {
EXM_THROW(34, "%s", strerror(errno));
}
assert(0); /* unexpected Rust status */
return 0;
}
#elif defined(_MSC_VER) || defined(_WIN32)
static size_t FIO_setDictBufferMMap(FIO_Dict_t* dict, const char* fileName, FIO_prefs_t* const prefs, stat_t* dictFileStat)
@@ -891,6 +910,7 @@ static size_t FIO_setDictBufferMMap(FIO_Dict_t* dict, const char* fileName, FIO_
size_t const dictSizeMax = prefs->patchFromMode ? prefs->memLimit : DICTSIZE_MAX;
void** bufferPtr = &dict->dictBuffer;
int status;
int diagnostic;
assert(bufferPtr != NULL);
assert(dictFileStat != NULL);
@@ -911,22 +931,23 @@ static size_t FIO_setDictBufferMMap(FIO_Dict_t* dict, const char* fileName, FIO_
bufferPtr,
&dict->dictBufferSize,
(void**)&dict->dictHandle);
if (status == FIO_DICT_MMAP_SUCCESS) return dict->dictBufferSize;
if (status == FIO_DICT_MMAP_OPEN_FAILED) {
EXM_THROW(33, "Couldn't open dictionary %s: %s", fileName, strerror(errno));
diagnostic = FIO_rust_dictLoadDiagnostic((int)FIO_mmapDict, status);
switch (diagnostic) {
case FIO_RUST_DICT_DIAGNOSTIC_OK:
return dict->dictBufferSize;
case FIO_RUST_DICT_DIAGNOSTIC_OPEN_FAILED:
EXM_THROW(33, "Couldn't open dictionary %s: %s", fileName, strerror(errno));
case FIO_RUST_DICT_DIAGNOSTIC_TOO_LARGE:
EXM_THROW(34, "Dictionary file %s is too large (> %u bytes)",
fileName, (unsigned)dictSizeMax); /* avoid extreme cases */
case FIO_RUST_DICT_DIAGNOSTIC_MAP_FAILED:
EXM_THROW(35, "Couldn't map dictionary %s: %s", fileName, strerror(errno));
case FIO_RUST_DICT_DIAGNOSTIC_VIEW_FAILED:
EXM_THROW(36, "%s", strerror(errno));
default:
assert(0); /* unexpected Rust diagnostic */
return 0;
}
if (status == FIO_DICT_MMAP_TOO_LARGE) {
EXM_THROW(34, "Dictionary file %s is too large (> %u bytes)",
fileName, (unsigned)dictSizeMax); /* avoid extreme cases */
}
if (status == FIO_DICT_MMAP_FAILED) {
EXM_THROW(35, "Couldn't map dictionary %s: %s", fileName, strerror(errno));
}
if (status == FIO_DICT_MMAP_VIEW_FAILED) {
EXM_THROW(36, "%s", strerror(errno));
}
assert(0); /* unexpected Rust status */
return 0;
}
#else
static size_t FIO_setDictBufferMMap(FIO_Dict_t* dict, const char* fileName, FIO_prefs_t* const prefs, stat_t* dictFileStat)