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.
37    CorruptSequences,
38    /// Raw or RLE block exceeds MAX_BLOCK_SIZE.
39    BlockTooLarge,
40    /// Sequence offset is invalid (zero or beyond available history).
41    InvalidOffset,
42    /// Decoded output size does not match the frame content size field.
43    FrameSizeMismatch,
44    /// FSE table description is invalid.
45    BadFseTable,
46    /// Huffman weight table is malformed.
47    BadHuffmanWeights,
48    /// Huffman bitstream decoding failed.
49    BadHuffmanStream,
50    /// Requested window size exceeds the implementation limit.
51    WindowTooLarge { requested: u64, max: u64 },
52    /// Decompressed output would exceed the configured size limit.
53    OutputTooSmall,
54    /// Content checksum does not match the decompressed data.
55    ChecksumMismatch { expected: u32, got: u32 },
56    /// Frame requires dictionary ID `expected`, but `got` was provided.
57    DictMismatch { expected: u32, got: u32 },
58    /// Frame requires a dictionary but none was provided.
59    DictRequired,
60    /// Dictionary bytes failed to parse.
61    InvalidDictionary,
62    /// Input ended before the frame was complete.
63    InputExhausted,
64    /// Unexpected trailing bytes after a valid frame.
65    ExtraBytes,
66}
67
68impl fmt::Display for ZstdError {
69    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70        match self {
71            ZstdError::Compress(e) => write!(f, "compress: {e}"),
72            ZstdError::Decompress(e) => write!(f, "decompress: {e}"),
73        }
74    }
75}
76
77impl fmt::Display for CompressError {
78    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
79        match self {
80            CompressError::OutputTooSmall => write!(f, "output buffer too small"),
81            CompressError::InvalidLevel(l) => write!(f, "invalid compression level: {l}"),
82            CompressError::InvalidDictionary => write!(f, "invalid dictionary"),
83        }
84    }
85}
86
87impl fmt::Display for DecompressError {
88    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89        match self {
90            DecompressError::BadMagic => write!(f, "invalid frame magic number"),
91            DecompressError::BadFrameHeader => write!(f, "malformed frame header"),
92            DecompressError::BadBlockHeader => write!(f, "malformed block header"),
93            DecompressError::BadBlockType => write!(f, "unknown block type"),
94            DecompressError::CorruptLiterals => write!(f, "corrupt literals section"),
95            DecompressError::CorruptSequences => write!(f, "corrupt sequences section"),
96            DecompressError::BlockTooLarge => write!(f, "block size exceeds maximum"),
97            DecompressError::InvalidOffset => write!(f, "invalid match offset"),
98            DecompressError::FrameSizeMismatch => {
99                write!(f, "decoded size does not match frame content size")
100            }
101            DecompressError::BadFseTable => write!(f, "invalid FSE table description"),
102            DecompressError::BadHuffmanWeights => write!(f, "invalid Huffman weights"),
103            DecompressError::BadHuffmanStream => write!(f, "corrupt Huffman stream"),
104            DecompressError::WindowTooLarge { requested, max } => {
105                write!(f, "window size {requested} exceeds max {max}")
106            }
107            DecompressError::OutputTooSmall => write!(f, "output buffer too small"),
108            DecompressError::ChecksumMismatch { expected, got } => {
109                write!(
110                    f,
111                    "checksum mismatch: expected {expected:#010x}, got {got:#010x}"
112                )
113            }
114            DecompressError::DictMismatch { expected, got } => {
115                write!(f, "dictionary ID mismatch: expected {expected}, got {got}")
116            }
117            DecompressError::DictRequired => write!(f, "dictionary required but not provided"),
118            DecompressError::InvalidDictionary => write!(f, "invalid dictionary format"),
119            DecompressError::InputExhausted => write!(f, "unexpected end of input"),
120            DecompressError::ExtraBytes => write!(f, "extra bytes after frame"),
121        }
122    }
123}
124
125#[cfg(feature = "std")]
126impl std::error::Error for ZstdError {}
127#[cfg(feature = "std")]
128impl std::error::Error for CompressError {}
129#[cfg(feature = "std")]
130impl std::error::Error for DecompressError {}
131
132impl From<CompressError> for ZstdError {
133    fn from(e: CompressError) -> Self {
134        ZstdError::Compress(e)
135    }
136}
137
138impl From<DecompressError> for ZstdError {
139    fn from(e: DecompressError) -> Self {
140        ZstdError::Decompress(e)
141    }
142}