Files
zstd-rs/rust/src/errors.rs
T
ddidderr 089f8e5b4d feat(rust): add common primitive compatibility layer
Introduce the Rust static library and move the shared byte, bitstream, CPU,
error, xxHash, debug, and public-common implementations into it. Thin C shims
preserve the existing header-driven C build while original tests link the Rust
archive.

This establishes the ABI-safe foundation for later codec and CLI ports;
entropy coding, runtime support, codecs, dictionaries, and the CLI remain C.
The top-down migration map documents that boundary and its validation path.

Test Plan:
- cargo fmt --check
- cargo test --all-targets
- cargo clippy --all-targets -- -D warnings
- cargo build --release

Refs: rust/README.md
2026-07-10 20:02:17 +02:00

150 lines
5.5 KiB
Rust

#![allow(non_snake_case)]
use std::os::raw::c_char;
/// Matches `ZSTD_ErrorCode` / `ERR_enum` from the C API.
#[repr(i32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum ZstdErrorCode {
NoError = 0,
Generic = 1,
PrefixUnknown = 10,
VersionUnsupported = 12,
FrameParameterUnsupported = 14,
FrameParameterWindowTooLarge = 16,
CorruptionDetected = 20,
ChecksumWrong = 22,
LiteralsHeaderWrong = 24,
DictionaryCorrupted = 30,
DictionaryWrong = 32,
DictionaryCreationFailed = 34,
ParameterUnsupported = 40,
ParameterCombinationUnsupported = 41,
ParameterOutOfBound = 42,
TableLogTooLarge = 44,
MaxSymbolValueTooLarge = 46,
MaxSymbolValueTooSmall = 48,
CannotProduceUncompressedBlock = 49,
StabilityConditionNotRespected = 50,
StageWrong = 60,
InitMissing = 62,
MemoryAllocation = 64,
WorkSpaceTooSmall = 66,
DstSizeTooSmall = 70,
SrcSizeWrong = 72,
DstBufferNull = 74,
NoForwardProgressDestFull = 80,
NoForwardProgressInputEmpty = 82,
FrameIndexTooLarge = 100,
SeekableIO = 102,
DstBufferWrong = 104,
SrcBufferWrong = 105,
SequenceProducerFailed = 106,
ExternalSequencesInvalid = 107,
MaxCode = 120,
}
/// Encode an error as a size_t-style error code: `(size_t)-(code)`.
#[inline]
pub fn ERROR(code: ZstdErrorCode) -> usize {
(-(code as i32)) as usize
}
/// Returns true if `code` is an error (same as C `ERR_isError`).
#[inline]
pub fn ERR_isError(code: usize) -> bool {
code > ERROR(ZstdErrorCode::MaxCode)
}
/// Extract the numeric `ZSTD_ErrorCode` from a size_t error value.
///
/// C permits error-shaped values which aren't named enum variants, and
/// `ERR_getErrorCode()` preserves those numeric values. Returning the ABI's
/// integer representation avoids constructing an invalid Rust enum.
#[inline]
pub fn ERR_getErrorCode(code: usize) -> i32 {
if !ERR_isError(code) {
return ZstdErrorCode::NoError as i32;
}
0usize.wrapping_sub(code) as i32
}
#[inline]
pub fn ERR_getErrorName(code: usize) -> *const c_char {
ERR_getErrorString(ERR_getErrorCode(code))
}
/// C ABI: `ERR_getErrorString` (error_private.c).
#[no_mangle]
pub extern "C" fn ERR_getErrorString(code: i32) -> *const c_char {
match code {
0 => c"No error detected".as_ptr(),
1 => c"Error (generic)".as_ptr(),
10 => c"Unknown frame descriptor".as_ptr(),
12 => c"Version not supported".as_ptr(),
14 => c"Unsupported frame parameter".as_ptr(),
16 => c"Frame requires too much memory for decoding".as_ptr(),
20 => c"Data corruption detected".as_ptr(),
22 => c"Restored data doesn't match checksum".as_ptr(),
24 => c"Header of Literals' block doesn't respect format specification".as_ptr(),
30 => c"Dictionary is corrupted".as_ptr(),
32 => c"Dictionary mismatch".as_ptr(),
34 => c"Cannot create Dictionary from provided samples".as_ptr(),
40 => c"Unsupported parameter".as_ptr(),
41 => c"Unsupported combination of parameters".as_ptr(),
42 => c"Parameter is out of bound".as_ptr(),
44 => c"tableLog requires too much memory : unsupported".as_ptr(),
46 => c"Unsupported max Symbol Value : too large".as_ptr(),
48 => c"Specified maxSymbolValue is too small".as_ptr(),
49 => c"This mode cannot generate an uncompressed block".as_ptr(),
50 => c"pledged buffer stability condition is not respected".as_ptr(),
60 => c"Operation not authorized at current processing stage".as_ptr(),
62 => c"Context should be init first".as_ptr(),
64 => c"Allocation error : not enough memory".as_ptr(),
66 => c"workSpace buffer is not large enough".as_ptr(),
70 => c"Destination buffer is too small".as_ptr(),
72 => c"Src size is incorrect".as_ptr(),
74 => c"Operation on NULL destination buffer".as_ptr(),
80 => c"Operation made no progress over multiple calls, due to output buffer being full"
.as_ptr(),
82 => c"Operation made no progress over multiple calls, due to input being empty".as_ptr(),
100 => c"Frame index is too large".as_ptr(),
102 => c"An I/O error occurred when reading/seeking".as_ptr(),
104 => c"Destination buffer is wrong".as_ptr(),
105 => c"Source buffer is wrong".as_ptr(),
106 => c"Block-level external sequence producer returned an error code".as_ptr(),
107 => c"External sequences are not valid".as_ptr(),
_ => c"Unspecified error code".as_ptr(),
}
}
/// C ABI: public `ZSTD_getErrorString` from zstd_errors.h.
#[no_mangle]
pub extern "C" fn ZSTD_getErrorString(code: i32) -> *const c_char {
ERR_getErrorString(code)
}
#[cfg(test)]
mod tests {
use super::*;
use std::ffi::CStr;
#[test]
fn size_t_error_encoding_matches_c() {
let error = ERROR(ZstdErrorCode::DstSizeTooSmall);
assert!(ERR_isError(error));
assert_eq!(ERR_getErrorCode(error), 70);
assert!(!ERR_isError(0));
assert_eq!(ERR_getErrorCode(usize::MAX - 1), 2);
assert_eq!(ERR_getErrorCode(ERROR(ZstdErrorCode::MaxCode)), 0);
}
#[test]
fn error_names_match_the_public_api() {
let name = unsafe { CStr::from_ptr(ERR_getErrorName(ERROR(ZstdErrorCode::ChecksumWrong))) };
assert_eq!(name.to_bytes(), b"Restored data doesn't match checksum");
let unknown = unsafe { CStr::from_ptr(ERR_getErrorString(2)) };
assert_eq!(unknown.to_bytes(), b"Unspecified error code");
}
}