Skip to main content

zrip_core/
error.rs

1#![forbid(unsafe_code)]
2
3use core::fmt;
4
5/// Unified error type wrapping both compression and decompression errors.
6#[derive(Debug, Clone, PartialEq, Eq)]
7pub enum ZstdError {
8    Compress(CompressError),
9    Decompress(DecompressError),
10}
11
12/// Error returned by compression functions.
13#[derive(Debug, Clone, PartialEq, Eq)]
14pub enum CompressError {
15    /// Output buffer passed to [`compress_into`](crate::compress_into) is too small.
16    OutputTooSmall,
17    /// Compression level is outside the supported range (-7..=4).
18    InvalidLevel(i32),
19    /// Dictionary bytes failed to parse.
20    InvalidDictionary,
21}
22
23/// Error returned by decompression functions.
24#[derive(Debug, Clone, PartialEq, Eq)]
25pub enum DecompressError {
26    /// Frame magic number is not `0xFD2F_B528`.
27    BadMagic,
28    /// Frame descriptor or field sizes are invalid.
29    BadFrameHeader,
30    /// Block header contains invalid values.
31    BadBlockHeader,
32    /// Block type field is reserved/unknown.
33    BadBlockType,
34    /// Literals section is malformed or truncated.
35    CorruptLiterals,
36    /// Sequences section is malformed, or decoded output exceeds block size.
37    CorruptSequences,
38    /// FSE table description is invalid.
39    BadFseTable,
40    /// Huffman weight table is malformed.
41    BadHuffmanWeights,
42    /// Huffman bitstream decoding failed.
43    BadHuffmanStream,
44    /// Requested window size exceeds the implementation limit.
45    WindowTooLarge { requested: u64, max: u64 },
46    /// Decompressed output would exceed the configured size limit.
47    OutputTooSmall,
48    /// Content checksum does not match the decompressed data.
49    ChecksumMismatch { expected: u32, got: u32 },
50    /// Frame requires dictionary ID `expected`, but `got` was provided.
51    DictMismatch { expected: u32, got: u32 },
52    /// Frame requires a dictionary but none was provided.
53    DictRequired,
54    /// Dictionary bytes failed to parse.
55    InvalidDictionary,
56    /// Input ended before the frame was complete.
57    InputExhausted,
58    /// Unexpected trailing bytes after a valid frame.
59    ExtraBytes,
60}
61
62impl fmt::Display for ZstdError {
63    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64        match self {
65            ZstdError::Compress(e) => write!(f, "compress: {e}"),
66            ZstdError::Decompress(e) => write!(f, "decompress: {e}"),
67        }
68    }
69}
70
71impl fmt::Display for CompressError {
72    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
73        match self {
74            CompressError::OutputTooSmall => write!(f, "output buffer too small"),
75            CompressError::InvalidLevel(l) => write!(f, "invalid compression level: {l}"),
76            CompressError::InvalidDictionary => write!(f, "invalid dictionary"),
77        }
78    }
79}
80
81impl fmt::Display for DecompressError {
82    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
83        match self {
84            DecompressError::BadMagic => write!(f, "invalid frame magic number"),
85            DecompressError::BadFrameHeader => write!(f, "malformed frame header"),
86            DecompressError::BadBlockHeader => write!(f, "malformed block header"),
87            DecompressError::BadBlockType => write!(f, "unknown block type"),
88            DecompressError::CorruptLiterals => write!(f, "corrupt literals section"),
89            DecompressError::CorruptSequences => write!(f, "corrupt sequences section"),
90            DecompressError::BadFseTable => write!(f, "invalid FSE table description"),
91            DecompressError::BadHuffmanWeights => write!(f, "invalid Huffman weights"),
92            DecompressError::BadHuffmanStream => write!(f, "corrupt Huffman stream"),
93            DecompressError::WindowTooLarge { requested, max } => {
94                write!(f, "window size {requested} exceeds max {max}")
95            }
96            DecompressError::OutputTooSmall => write!(f, "output buffer too small"),
97            DecompressError::ChecksumMismatch { expected, got } => {
98                write!(
99                    f,
100                    "checksum mismatch: expected {expected:#010x}, got {got:#010x}"
101                )
102            }
103            DecompressError::DictMismatch { expected, got } => {
104                write!(f, "dictionary ID mismatch: expected {expected}, got {got}")
105            }
106            DecompressError::DictRequired => write!(f, "dictionary required but not provided"),
107            DecompressError::InvalidDictionary => write!(f, "invalid dictionary format"),
108            DecompressError::InputExhausted => write!(f, "unexpected end of input"),
109            DecompressError::ExtraBytes => write!(f, "extra bytes after frame"),
110        }
111    }
112}
113
114#[cfg(feature = "std")]
115impl std::error::Error for ZstdError {}
116#[cfg(feature = "std")]
117impl std::error::Error for CompressError {}
118#[cfg(feature = "std")]
119impl std::error::Error for DecompressError {}
120
121impl From<CompressError> for ZstdError {
122    fn from(e: CompressError) -> Self {
123        ZstdError::Compress(e)
124    }
125}
126
127impl From<DecompressError> for ZstdError {
128    fn from(e: DecompressError) -> Self {
129        ZstdError::Decompress(e)
130    }
131}