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
150 lines
5.5 KiB
Rust
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");
|
|
}
|
|
}
|