Skip to main content

structured_zstd/decoding/
errors.rs

1//! Errors that might occur while decoding zstd formatted data
2
3use crate::bit_io::GetBitsError;
4use crate::blocks::block::BlockType;
5use crate::blocks::literals_section::LiteralsSectionType;
6use crate::io::Error;
7use alloc::vec::Vec;
8use core::fmt;
9#[cfg(feature = "std")]
10use std::error::Error as StdError;
11
12#[derive(Debug)]
13#[non_exhaustive]
14pub enum FrameDescriptorError {
15    InvalidFrameContentSizeFlag { got: u8 },
16}
17
18impl fmt::Display for FrameDescriptorError {
19    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
20        match self {
21            Self::InvalidFrameContentSizeFlag { got } => write!(
22                f,
23                "Invalid Frame_Content_Size_Flag; Is: {got}, Should be one of: 0, 1, 2, 3"
24            ),
25        }
26    }
27}
28
29#[cfg(feature = "std")]
30impl StdError for FrameDescriptorError {}
31
32#[derive(Debug)]
33#[non_exhaustive]
34pub enum FrameHeaderError {
35    WindowTooBig { got: u64 },
36    WindowTooSmall { got: u64 },
37    FrameDescriptorError(FrameDescriptorError),
38    DictIdTooSmall { got: usize, expected: usize },
39    MismatchedFrameSize { got: usize, expected: u8 },
40    FrameSizeIsZero,
41    InvalidFrameSize { got: u8 },
42}
43
44impl fmt::Display for FrameHeaderError {
45    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
46        match self {
47            Self::WindowTooBig { got } => write!(
48                f,
49                "window_size bigger than allowed maximum. Is: {}, Should be lower than: {}",
50                got,
51                crate::common::MAX_WINDOW_SIZE
52            ),
53            Self::WindowTooSmall { got } => write!(
54                f,
55                "window_size smaller than allowed minimum. Is: {}, Should be greater than: {}",
56                got,
57                crate::common::MIN_WINDOW_SIZE
58            ),
59            Self::FrameDescriptorError(e) => write!(f, "{e:?}"),
60            Self::DictIdTooSmall { got, expected } => write!(
61                f,
62                "Not enough bytes in dict_id. Is: {got}, Should be: {expected}"
63            ),
64            Self::MismatchedFrameSize { got, expected } => write!(
65                f,
66                "frame_content_size does not have the right length. Is: {got}, Should be: {expected}"
67            ),
68            Self::FrameSizeIsZero => write!(f, "frame_content_size was zero"),
69            Self::InvalidFrameSize { got } => write!(
70                f,
71                "Invalid frame_content_size. Is: {got}, Should be one of 1, 2, 4, 8 bytes"
72            ),
73        }
74    }
75}
76
77#[cfg(feature = "std")]
78impl StdError for FrameHeaderError {
79    fn source(&self) -> Option<&(dyn StdError + 'static)> {
80        match self {
81            FrameHeaderError::FrameDescriptorError(source) => Some(source),
82            _ => None,
83        }
84    }
85}
86
87impl From<FrameDescriptorError> for FrameHeaderError {
88    fn from(error: FrameDescriptorError) -> Self {
89        Self::FrameDescriptorError(error)
90    }
91}
92
93#[derive(Debug)]
94#[non_exhaustive]
95pub enum ReadFrameHeaderError {
96    MagicNumberReadError(Error),
97    BadMagicNumber(u32),
98    FrameDescriptorReadError(Error),
99    InvalidFrameDescriptor(FrameDescriptorError),
100    WindowDescriptorReadError(Error),
101    DictionaryIdReadError(Error),
102    FrameContentSizeReadError(Error),
103    SkipFrame { magic_number: u32, length: u32 },
104}
105
106impl fmt::Display for ReadFrameHeaderError {
107    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
108        match self {
109            Self::MagicNumberReadError(e) => write!(f, "Error while reading magic number: {e}"),
110            Self::BadMagicNumber(e) => write!(f, "Read wrong magic number: 0x{e:X}"),
111            Self::FrameDescriptorReadError(e) => {
112                write!(f, "Error while reading frame descriptor: {e}")
113            }
114            Self::InvalidFrameDescriptor(e) => write!(f, "{e:?}"),
115            Self::WindowDescriptorReadError(e) => {
116                write!(f, "Error while reading window descriptor: {e}")
117            }
118            Self::DictionaryIdReadError(e) => write!(f, "Error while reading dictionary id: {e}"),
119            Self::FrameContentSizeReadError(e) => {
120                write!(f, "Error while reading frame content size: {e}")
121            }
122            Self::SkipFrame {
123                magic_number,
124                length,
125            } => write!(
126                f,
127                "SkippableFrame encountered with MagicNumber 0x{magic_number:X} and length {length} bytes"
128            ),
129        }
130    }
131}
132
133#[cfg(feature = "std")]
134impl StdError for ReadFrameHeaderError {
135    fn source(&self) -> Option<&(dyn StdError + 'static)> {
136        match self {
137            ReadFrameHeaderError::MagicNumberReadError(source) => Some(source),
138            ReadFrameHeaderError::FrameDescriptorReadError(source) => Some(source),
139            ReadFrameHeaderError::InvalidFrameDescriptor(source) => Some(source),
140            ReadFrameHeaderError::WindowDescriptorReadError(source) => Some(source),
141            ReadFrameHeaderError::DictionaryIdReadError(source) => Some(source),
142            ReadFrameHeaderError::FrameContentSizeReadError(source) => Some(source),
143            _ => None,
144        }
145    }
146}
147
148impl From<FrameDescriptorError> for ReadFrameHeaderError {
149    fn from(error: FrameDescriptorError) -> Self {
150        Self::InvalidFrameDescriptor(error)
151    }
152}
153
154#[derive(Debug)]
155#[non_exhaustive]
156pub enum BlockHeaderReadError {
157    ReadError(Error),
158    FoundReservedBlock,
159    BlockTypeError(BlockTypeError),
160    BlockSizeError(BlockSizeError),
161}
162
163#[cfg(feature = "std")]
164impl std::error::Error for BlockHeaderReadError {
165    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
166        match self {
167            BlockHeaderReadError::ReadError(source) => Some(source),
168            BlockHeaderReadError::BlockTypeError(source) => Some(source),
169            BlockHeaderReadError::BlockSizeError(source) => Some(source),
170            BlockHeaderReadError::FoundReservedBlock => None,
171        }
172    }
173}
174
175impl ::core::fmt::Display for BlockHeaderReadError {
176    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> ::core::fmt::Result {
177        match self {
178            BlockHeaderReadError::ReadError(_) => write!(f, "Error while reading the block header"),
179            BlockHeaderReadError::FoundReservedBlock => write!(
180                f,
181                "Reserved block occured. This is considered corruption by the documentation"
182            ),
183            BlockHeaderReadError::BlockTypeError(e) => write!(f, "Error getting block type: {e}"),
184            BlockHeaderReadError::BlockSizeError(e) => {
185                write!(f, "Error getting block content size: {e}")
186            }
187        }
188    }
189}
190
191impl From<Error> for BlockHeaderReadError {
192    fn from(val: Error) -> Self {
193        Self::ReadError(val)
194    }
195}
196
197impl From<BlockTypeError> for BlockHeaderReadError {
198    fn from(val: BlockTypeError) -> Self {
199        Self::BlockTypeError(val)
200    }
201}
202
203impl From<BlockSizeError> for BlockHeaderReadError {
204    fn from(val: BlockSizeError) -> Self {
205        Self::BlockSizeError(val)
206    }
207}
208
209#[derive(Debug)]
210#[non_exhaustive]
211pub enum BlockTypeError {
212    InvalidBlocktypeNumber { num: u8 },
213}
214
215#[cfg(feature = "std")]
216impl std::error::Error for BlockTypeError {}
217
218impl core::fmt::Display for BlockTypeError {
219    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
220        match self {
221            BlockTypeError::InvalidBlocktypeNumber { num } => {
222                write!(
223                    f,
224                    "Invalid Blocktype number. Is: {num}. Should be one of: 0, 1, 2, 3 (3 is reserved).",
225                )
226            }
227        }
228    }
229}
230
231#[derive(Debug)]
232#[non_exhaustive]
233pub enum BlockSizeError {
234    BlockSizeTooLarge { size: u32 },
235}
236
237#[cfg(feature = "std")]
238impl std::error::Error for BlockSizeError {}
239
240impl core::fmt::Display for BlockSizeError {
241    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
242        match self {
243            BlockSizeError::BlockSizeTooLarge { size } => {
244                write!(
245                    f,
246                    "Blocksize was bigger than the absolute maximum {} (128kb). Is: {}",
247                    crate::common::MAX_BLOCK_SIZE,
248                    size,
249                )
250            }
251        }
252    }
253}
254
255#[derive(Debug)]
256#[non_exhaustive]
257pub enum DecompressBlockError {
258    BlockContentReadError(Error),
259    MalformedSectionHeader {
260        expected_len: usize,
261        remaining_bytes: usize,
262    },
263    DecompressLiteralsError(DecompressLiteralsError),
264    LiteralsSectionParseError(LiteralsSectionParseError),
265    SequencesHeaderParseError(SequencesHeaderParseError),
266    DecodeSequenceError(DecodeSequenceError),
267    ExecuteSequencesError(ExecuteSequencesError),
268}
269
270#[cfg(feature = "std")]
271impl std::error::Error for DecompressBlockError {
272    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
273        match self {
274            DecompressBlockError::BlockContentReadError(source) => Some(source),
275            DecompressBlockError::DecompressLiteralsError(source) => Some(source),
276            DecompressBlockError::LiteralsSectionParseError(source) => Some(source),
277            DecompressBlockError::SequencesHeaderParseError(source) => Some(source),
278            DecompressBlockError::DecodeSequenceError(source) => Some(source),
279            DecompressBlockError::ExecuteSequencesError(source) => Some(source),
280            _ => None,
281        }
282    }
283}
284
285impl core::fmt::Display for DecompressBlockError {
286    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
287        match self {
288            DecompressBlockError::BlockContentReadError(e) => {
289                write!(f, "Error while reading the block content: {e}")
290            }
291            DecompressBlockError::MalformedSectionHeader {
292                expected_len,
293                remaining_bytes,
294            } => {
295                write!(
296                    f,
297                    "Malformed section header. Says literals would be this long: {expected_len} but there are only {remaining_bytes} bytes left",
298                )
299            }
300            DecompressBlockError::DecompressLiteralsError(e) => write!(f, "{e:?}"),
301            DecompressBlockError::LiteralsSectionParseError(e) => write!(f, "{e:?}"),
302            DecompressBlockError::SequencesHeaderParseError(e) => write!(f, "{e:?}"),
303            DecompressBlockError::DecodeSequenceError(e) => write!(f, "{e:?}"),
304            DecompressBlockError::ExecuteSequencesError(e) => write!(f, "{e:?}"),
305        }
306    }
307}
308
309impl From<Error> for DecompressBlockError {
310    fn from(val: Error) -> Self {
311        Self::BlockContentReadError(val)
312    }
313}
314
315impl From<DecompressLiteralsError> for DecompressBlockError {
316    fn from(val: DecompressLiteralsError) -> Self {
317        Self::DecompressLiteralsError(val)
318    }
319}
320
321impl From<LiteralsSectionParseError> for DecompressBlockError {
322    fn from(val: LiteralsSectionParseError) -> Self {
323        Self::LiteralsSectionParseError(val)
324    }
325}
326
327impl From<SequencesHeaderParseError> for DecompressBlockError {
328    fn from(val: SequencesHeaderParseError) -> Self {
329        Self::SequencesHeaderParseError(val)
330    }
331}
332
333impl From<DecodeSequenceError> for DecompressBlockError {
334    fn from(val: DecodeSequenceError) -> Self {
335        Self::DecodeSequenceError(val)
336    }
337}
338
339impl From<ExecuteSequencesError> for DecompressBlockError {
340    fn from(val: ExecuteSequencesError) -> Self {
341        Self::ExecuteSequencesError(val)
342    }
343}
344
345#[derive(Debug)]
346#[non_exhaustive]
347pub enum DecodeBlockContentError {
348    DecoderStateIsFailed,
349    ExpectedHeaderOfPreviousBlock,
350    ReadError { step: BlockType, source: Error },
351    DecompressBlockError(DecompressBlockError),
352}
353
354#[cfg(feature = "std")]
355impl std::error::Error for DecodeBlockContentError {
356    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
357        match self {
358            DecodeBlockContentError::ReadError { step: _, source } => Some(source),
359            DecodeBlockContentError::DecompressBlockError(source) => Some(source),
360            _ => None,
361        }
362    }
363}
364
365impl core::fmt::Display for DecodeBlockContentError {
366    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
367        match self {
368            DecodeBlockContentError::DecoderStateIsFailed => {
369                write!(
370                    f,
371                    "Can't decode next block if failed along the way. Results will be nonsense",
372                )
373            }
374            DecodeBlockContentError::ExpectedHeaderOfPreviousBlock => {
375                write!(
376                    f,
377                    "Can't decode next block body, while expecting to decode the header of the previous block. Results will be nonsense",
378                )
379            }
380            DecodeBlockContentError::ReadError { step, source } => {
381                write!(f, "Error while reading bytes for {step}: {source}",)
382            }
383            DecodeBlockContentError::DecompressBlockError(e) => write!(f, "{e:?}"),
384        }
385    }
386}
387
388impl From<DecompressBlockError> for DecodeBlockContentError {
389    fn from(val: DecompressBlockError) -> Self {
390        Self::DecompressBlockError(val)
391    }
392}
393
394#[derive(Debug)]
395#[non_exhaustive]
396pub enum DecodeBufferError {
397    NotEnoughBytesInDictionary { got: usize, need: usize },
398    OffsetTooBig { offset: usize, buf_len: usize },
399    ZeroOffset,
400}
401
402#[cfg(feature = "std")]
403impl std::error::Error for DecodeBufferError {}
404
405impl core::fmt::Display for DecodeBufferError {
406    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
407        match self {
408            DecodeBufferError::NotEnoughBytesInDictionary { got, need } => {
409                write!(
410                    f,
411                    "Need {need} bytes from the dictionary but it is only {got} bytes long",
412                )
413            }
414            DecodeBufferError::OffsetTooBig { offset, buf_len } => {
415                write!(f, "offset: {offset} bigger than buffer: {buf_len}",)
416            }
417            DecodeBufferError::ZeroOffset => {
418                write!(f, "Illegal offset: 0 found")
419            }
420        }
421    }
422}
423
424#[derive(Debug)]
425#[non_exhaustive]
426pub enum DictionaryDecodeError {
427    BadMagicNum { got: [u8; 4] },
428    DictionaryTooSmall { got: usize, need: usize },
429    ZeroDictionaryId,
430    ZeroRepeatOffsetInDictionary { index: u8 },
431    FSETableError(FSETableError),
432    HuffmanTableError(HuffmanTableError),
433}
434
435#[cfg(feature = "std")]
436impl std::error::Error for DictionaryDecodeError {
437    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
438        match self {
439            DictionaryDecodeError::FSETableError(source) => Some(source),
440            DictionaryDecodeError::HuffmanTableError(source) => Some(source),
441            _ => None,
442        }
443    }
444}
445
446impl core::fmt::Display for DictionaryDecodeError {
447    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
448        match self {
449            DictionaryDecodeError::BadMagicNum { got } => {
450                write!(
451                    f,
452                    "Bad magic_num at start of the dictionary; Got: {:#04X?}, Expected: {:#04x?}",
453                    got,
454                    crate::decoding::dictionary::MAGIC_NUM,
455                )
456            }
457            DictionaryDecodeError::DictionaryTooSmall { got, need } => {
458                write!(
459                    f,
460                    "Dictionary is too small: got {got} bytes, need at least {need} bytes",
461                )
462            }
463            DictionaryDecodeError::ZeroDictionaryId => {
464                write!(f, "Dictionary id must be non-zero")
465            }
466            DictionaryDecodeError::ZeroRepeatOffsetInDictionary { index } => {
467                write!(f, "Dictionary repeat offset rep{index} must be non-zero")
468            }
469            DictionaryDecodeError::FSETableError(e) => write!(f, "{e:?}"),
470            DictionaryDecodeError::HuffmanTableError(e) => write!(f, "{e:?}"),
471        }
472    }
473}
474
475impl From<FSETableError> for DictionaryDecodeError {
476    fn from(val: FSETableError) -> Self {
477        Self::FSETableError(val)
478    }
479}
480
481impl From<HuffmanTableError> for DictionaryDecodeError {
482    fn from(val: HuffmanTableError) -> Self {
483        Self::HuffmanTableError(val)
484    }
485}
486
487#[derive(Debug)]
488#[non_exhaustive]
489pub enum FrameDecoderError {
490    ReadFrameHeaderError(ReadFrameHeaderError),
491    FrameHeaderError(FrameHeaderError),
492    WindowSizeTooBig {
493        requested: u64,
494    },
495    DictionaryDecodeError(DictionaryDecodeError),
496    FailedToReadBlockHeader(BlockHeaderReadError),
497    FailedToReadBlockBody(DecodeBlockContentError),
498    FailedToReadChecksum(Error),
499    NotYetInitialized,
500    FailedToInitialize(FrameHeaderError),
501    FailedToDrainDecodebuffer(Error),
502    FailedToSkipFrame,
503    TargetTooSmall,
504    /// Decoded block sizes don't sum to the frame's declared
505    /// `frame_content_size` (either a block claims to expand past
506    /// FCS, or the stream ends before reaching FCS). Indicates a
507    /// malformed or corrupt frame — distinct from
508    /// [`Self::TargetTooSmall`] (which is the caller's
509    /// responsibility) so callers can tell decoder-side issues
510    /// apart from their own buffer sizing mistakes.
511    FrameContentSizeMismatch {
512        declared: u64,
513        produced: u64,
514    },
515    DictNotProvided {
516        dict_id: u32,
517    },
518    DictIdMismatch {
519        expected: u32,
520        provided: u32,
521    },
522    DictAlreadyRegistered {
523        dict_id: u32,
524    },
525    /// Frame header's `dict_id` did not match the value pinned via
526    /// `FrameDecoder::expect_dict_id`. Returned BEFORE any block
527    /// decode and BEFORE any output is produced — no XXH64 init,
528    /// no partial output. Scratch buffer allocation / reservation
529    /// for the decode pipeline happens during frame-header parsing,
530    /// which is already complete when this validation fires, so
531    /// the cost of scratch sizing is paid even on a mismatched
532    /// header. `expected` is the pinned value (`Some(0)` is
533    /// treated as "no dictionary expected", matching a frame whose
534    /// header omits the optional `Dictionary_ID` field); `found`
535    /// reports what the frame actually carried (`None` when the
536    /// header omits the field, `Some(id)` when it does not).
537    #[cfg(feature = "lsm")]
538    UnexpectedDictId {
539        expected: Option<u32>,
540        found: Option<u32>,
541    },
542    /// Frame header's raw `Window_Descriptor` byte did not match
543    /// the value pinned via `FrameDecoder::expect_window_descriptor`.
544    /// Returned BEFORE any block decode work. Single-segment frames
545    /// (which omit the `Window_Descriptor` byte from the wire) are
546    /// reported via `found: None` so callers can distinguish
547    /// "wrong descriptor" from "no descriptor on the wire".
548    #[cfg(feature = "lsm")]
549    UnexpectedWindowDescriptor {
550        expected: u8,
551        found: Option<u8>,
552    },
553}
554
555#[cfg(feature = "std")]
556impl StdError for FrameDecoderError {
557    fn source(&self) -> Option<&(dyn StdError + 'static)> {
558        match self {
559            FrameDecoderError::ReadFrameHeaderError(source) => Some(source),
560            FrameDecoderError::FrameHeaderError(source) => Some(source),
561            FrameDecoderError::DictionaryDecodeError(source) => Some(source),
562            FrameDecoderError::FailedToReadBlockHeader(source) => Some(source),
563            FrameDecoderError::FailedToReadBlockBody(source) => Some(source),
564            FrameDecoderError::FailedToReadChecksum(source) => Some(source),
565            FrameDecoderError::FailedToInitialize(source) => Some(source),
566            FrameDecoderError::FailedToDrainDecodebuffer(source) => Some(source),
567            _ => None,
568        }
569    }
570}
571
572impl core::fmt::Display for FrameDecoderError {
573    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> ::core::fmt::Result {
574        match self {
575            FrameDecoderError::ReadFrameHeaderError(e) => {
576                write!(f, "{e:?}")
577            }
578            FrameDecoderError::FrameHeaderError(e) => {
579                write!(f, "{e:?}")
580            }
581            FrameDecoderError::WindowSizeTooBig { requested } => {
582                write!(
583                    f,
584                    "Specified window_size is too big; Requested: {}, Allowed: {}",
585                    requested,
586                    crate::common::MAXIMUM_ALLOWED_WINDOW_SIZE,
587                )
588            }
589            FrameDecoderError::DictionaryDecodeError(e) => {
590                write!(f, "{e:?}")
591            }
592            FrameDecoderError::FailedToReadBlockHeader(e) => {
593                write!(f, "Failed to parse/decode block body: {e}")
594            }
595            FrameDecoderError::FailedToReadBlockBody(e) => {
596                write!(f, "Failed to parse block header: {e}")
597            }
598            FrameDecoderError::FailedToReadChecksum(e) => {
599                write!(f, "Failed to read checksum: {e}")
600            }
601            FrameDecoderError::NotYetInitialized => {
602                write!(f, "Decoder must initialized or reset before using it",)
603            }
604            FrameDecoderError::FailedToInitialize(e) => {
605                write!(f, "Decoder encountered error while initializing: {e}")
606            }
607            FrameDecoderError::FailedToDrainDecodebuffer(e) => {
608                write!(
609                    f,
610                    "Decoder encountered error while draining the decodebuffer: {e}",
611                )
612            }
613            FrameDecoderError::FailedToSkipFrame => {
614                write!(
615                    f,
616                    "Failed to skip bytes for the length given in the frame header"
617                )
618            }
619            FrameDecoderError::TargetTooSmall => {
620                write!(
621                    f,
622                    "Target must have at least as many bytes as the content size reported by the frame"
623                )
624            }
625            FrameDecoderError::FrameContentSizeMismatch { declared, produced } => {
626                write!(
627                    f,
628                    "Frame content size mismatch (corrupt frame): declared {declared} bytes, blocks summed to {produced} bytes"
629                )
630            }
631            FrameDecoderError::DictNotProvided { dict_id } => {
632                write!(
633                    f,
634                    "Frame header specified dictionary id 0x{dict_id:X} that wasn't provided via add_dict()/add_dict_from_bytes() (or add_dict_handle() on atomic targets) or reset_with_dict_handle()/decode_all_with_dict_handle()/decode_all_with_dict_bytes()"
635                )
636            }
637            FrameDecoderError::DictIdMismatch { expected, provided } => {
638                write!(
639                    f,
640                    "Frame header dictionary id 0x{expected:X} does not match provided dictionary id 0x{provided:X}"
641                )
642            }
643            FrameDecoderError::DictAlreadyRegistered { dict_id } => {
644                write!(
645                    f,
646                    "Dictionary id 0x{dict_id:X} already registered in decoder"
647                )
648            }
649            #[cfg(feature = "lsm")]
650            FrameDecoderError::UnexpectedDictId { expected, found } => {
651                write!(f, "Frame header dict_id mismatch: expected ")?;
652                match expected {
653                    Some(id) => write!(f, "0x{id:X}")?,
654                    None => write!(f, "<none>")?,
655                }
656                write!(f, ", found ")?;
657                match found {
658                    Some(id) => write!(f, "0x{id:X}"),
659                    None => write!(f, "<none>"),
660                }
661            }
662            #[cfg(feature = "lsm")]
663            FrameDecoderError::UnexpectedWindowDescriptor { expected, found } => {
664                write!(
665                    f,
666                    "Frame header window_descriptor mismatch: expected 0x{expected:02X}, found "
667                )?;
668                match found {
669                    Some(byte) => write!(f, "0x{byte:02X}"),
670                    None => write!(f, "<none> (single-segment frame omits window_descriptor)"),
671                }
672            }
673        }
674    }
675}
676
677impl From<DictionaryDecodeError> for FrameDecoderError {
678    fn from(val: DictionaryDecodeError) -> Self {
679        Self::DictionaryDecodeError(val)
680    }
681}
682
683impl From<BlockHeaderReadError> for FrameDecoderError {
684    fn from(val: BlockHeaderReadError) -> Self {
685        Self::FailedToReadBlockHeader(val)
686    }
687}
688
689impl From<FrameHeaderError> for FrameDecoderError {
690    fn from(val: FrameHeaderError) -> Self {
691        Self::FrameHeaderError(val)
692    }
693}
694
695impl From<ReadFrameHeaderError> for FrameDecoderError {
696    fn from(val: ReadFrameHeaderError) -> Self {
697        Self::ReadFrameHeaderError(val)
698    }
699}
700
701#[derive(Debug)]
702#[non_exhaustive]
703pub enum DecompressLiteralsError {
704    MissingCompressedSize,
705    MissingNumStreams,
706    GetBitsError(GetBitsError),
707    HuffmanTableError(HuffmanTableError),
708    HuffmanDecoderError(HuffmanDecoderError),
709    UninitializedHuffmanTable,
710    MissingBytesForJumpHeader { got: usize },
711    MissingBytesForLiterals { got: usize, needed: usize },
712    ExtraPadding { skipped_bits: i32 },
713    BitstreamReadMismatch { read_til: isize, expected: isize },
714    DecodedLiteralCountMismatch { decoded: usize, expected: usize },
715}
716
717#[cfg(feature = "std")]
718impl std::error::Error for DecompressLiteralsError {
719    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
720        match self {
721            DecompressLiteralsError::GetBitsError(source) => Some(source),
722            DecompressLiteralsError::HuffmanTableError(source) => Some(source),
723            DecompressLiteralsError::HuffmanDecoderError(source) => Some(source),
724            _ => None,
725        }
726    }
727}
728impl core::fmt::Display for DecompressLiteralsError {
729    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
730        match self {
731            DecompressLiteralsError::MissingCompressedSize => {
732                write!(
733                    f,
734                    "compressed size was none even though it must be set to something for compressed literals",
735                )
736            }
737            DecompressLiteralsError::MissingNumStreams => {
738                write!(
739                    f,
740                    "num_streams was none even though it must be set to something (1 or 4) for compressed literals",
741                )
742            }
743            DecompressLiteralsError::GetBitsError(e) => write!(f, "{e:?}"),
744            DecompressLiteralsError::HuffmanTableError(e) => write!(f, "{e:?}"),
745            DecompressLiteralsError::HuffmanDecoderError(e) => write!(f, "{e:?}"),
746            DecompressLiteralsError::UninitializedHuffmanTable => {
747                write!(
748                    f,
749                    "Tried to reuse huffman table but it was never initialized",
750                )
751            }
752            DecompressLiteralsError::MissingBytesForJumpHeader { got } => {
753                write!(f, "Need 6 bytes to decode jump header, got {got} bytes",)
754            }
755            DecompressLiteralsError::MissingBytesForLiterals { got, needed } => {
756                write!(
757                    f,
758                    "Need at least {needed} bytes to decode literals. Have: {got} bytes",
759                )
760            }
761            DecompressLiteralsError::ExtraPadding { skipped_bits } => {
762                write!(
763                    f,
764                    "Padding at the end of the sequence_section was more than a byte long: {skipped_bits} bits. Probably caused by data corruption",
765                )
766            }
767            DecompressLiteralsError::BitstreamReadMismatch { read_til, expected } => {
768                write!(
769                    f,
770                    "Bitstream was read till: {read_til}, should have been: {expected}",
771                )
772            }
773            DecompressLiteralsError::DecodedLiteralCountMismatch { decoded, expected } => {
774                write!(
775                    f,
776                    "Did not decode enough literals: {decoded}, Should have been: {expected}",
777                )
778            }
779        }
780    }
781}
782
783impl From<HuffmanDecoderError> for DecompressLiteralsError {
784    fn from(val: HuffmanDecoderError) -> Self {
785        Self::HuffmanDecoderError(val)
786    }
787}
788
789impl From<GetBitsError> for DecompressLiteralsError {
790    fn from(val: GetBitsError) -> Self {
791        Self::GetBitsError(val)
792    }
793}
794
795impl From<HuffmanTableError> for DecompressLiteralsError {
796    fn from(val: HuffmanTableError) -> Self {
797        Self::HuffmanTableError(val)
798    }
799}
800
801#[derive(Debug)]
802#[non_exhaustive]
803pub enum ExecuteSequencesError {
804    DecodebufferError(DecodeBufferError),
805    NotEnoughBytesForSequence { wanted: usize, have: usize },
806    ZeroOffset,
807}
808
809impl core::fmt::Display for ExecuteSequencesError {
810    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
811        match self {
812            ExecuteSequencesError::DecodebufferError(e) => {
813                write!(f, "{e:?}")
814            }
815            ExecuteSequencesError::NotEnoughBytesForSequence { wanted, have } => {
816                write!(
817                    f,
818                    "Sequence wants to copy up to byte {wanted}. Bytes in literalsbuffer: {have}"
819                )
820            }
821            ExecuteSequencesError::ZeroOffset => {
822                write!(f, "Illegal offset: 0 found")
823            }
824        }
825    }
826}
827
828#[cfg(feature = "std")]
829impl std::error::Error for ExecuteSequencesError {
830    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
831        match self {
832            ExecuteSequencesError::DecodebufferError(source) => Some(source),
833            _ => None,
834        }
835    }
836}
837
838impl From<DecodeBufferError> for ExecuteSequencesError {
839    fn from(val: DecodeBufferError) -> Self {
840        Self::DecodebufferError(val)
841    }
842}
843
844#[derive(Debug)]
845#[non_exhaustive]
846pub enum DecodeSequenceError {
847    GetBitsError(GetBitsError),
848    FSEDecoderError(FSEDecoderError),
849    FSETableError(FSETableError),
850    ExtraPadding { skipped_bits: i32 },
851    UnsupportedOffset { offset_code: u8 },
852    ZeroOffset,
853    NotEnoughBytesForNumSequences,
854    ExtraBits { bits_remaining: isize },
855    MissingCompressionMode,
856    MissingByteForRleLlTable,
857    MissingByteForRleOfTable,
858    MissingByteForRleMlTable,
859}
860
861#[cfg(feature = "std")]
862impl std::error::Error for DecodeSequenceError {
863    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
864        match self {
865            DecodeSequenceError::GetBitsError(source) => Some(source),
866            DecodeSequenceError::FSEDecoderError(source) => Some(source),
867            DecodeSequenceError::FSETableError(source) => Some(source),
868            _ => None,
869        }
870    }
871}
872
873impl core::fmt::Display for DecodeSequenceError {
874    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
875        match self {
876            DecodeSequenceError::GetBitsError(e) => write!(f, "{e:?}"),
877            DecodeSequenceError::FSEDecoderError(e) => write!(f, "{e:?}"),
878            DecodeSequenceError::FSETableError(e) => write!(f, "{e:?}"),
879            DecodeSequenceError::ExtraPadding { skipped_bits } => {
880                write!(
881                    f,
882                    "Padding at the end of the sequence_section was more than a byte long: {skipped_bits} bits. Probably caused by data corruption",
883                )
884            }
885            DecodeSequenceError::UnsupportedOffset { offset_code } => {
886                write!(
887                    f,
888                    "Do not support offsets bigger than 1<<32; got: {offset_code}",
889                )
890            }
891            DecodeSequenceError::ZeroOffset => write!(
892                f,
893                "Read an offset == 0. That is an illegal value for offsets"
894            ),
895            DecodeSequenceError::NotEnoughBytesForNumSequences => write!(
896                f,
897                "Bytestream did not contain enough bytes to decode num_sequences"
898            ),
899            DecodeSequenceError::ExtraBits { bits_remaining } => write!(f, "{bits_remaining}"),
900            DecodeSequenceError::MissingCompressionMode => write!(
901                f,
902                "compression modes are none but they must be set to something"
903            ),
904            DecodeSequenceError::MissingByteForRleLlTable => {
905                write!(f, "Need a byte to read for RLE ll table")
906            }
907            DecodeSequenceError::MissingByteForRleOfTable => {
908                write!(f, "Need a byte to read for RLE of table")
909            }
910            DecodeSequenceError::MissingByteForRleMlTable => {
911                write!(f, "Need a byte to read for RLE ml table")
912            }
913        }
914    }
915}
916
917impl From<GetBitsError> for DecodeSequenceError {
918    fn from(val: GetBitsError) -> Self {
919        Self::GetBitsError(val)
920    }
921}
922
923impl From<FSETableError> for DecodeSequenceError {
924    fn from(val: FSETableError) -> Self {
925        Self::FSETableError(val)
926    }
927}
928
929impl From<FSEDecoderError> for DecodeSequenceError {
930    fn from(val: FSEDecoderError) -> Self {
931        Self::FSEDecoderError(val)
932    }
933}
934
935#[derive(Debug)]
936#[non_exhaustive]
937pub enum LiteralsSectionParseError {
938    IllegalLiteralSectionType { got: u8 },
939    GetBitsError(GetBitsError),
940    NotEnoughBytes { have: usize, need: u8 },
941}
942
943#[cfg(feature = "std")]
944impl std::error::Error for LiteralsSectionParseError {
945    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
946        match self {
947            LiteralsSectionParseError::GetBitsError(source) => Some(source),
948            _ => None,
949        }
950    }
951}
952impl core::fmt::Display for LiteralsSectionParseError {
953    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
954        match self {
955            LiteralsSectionParseError::IllegalLiteralSectionType { got } => {
956                write!(
957                    f,
958                    "Illegal literalssectiontype. Is: {got}, must be in: 0, 1, 2, 3"
959                )
960            }
961            LiteralsSectionParseError::GetBitsError(e) => write!(f, "{e:?}"),
962            LiteralsSectionParseError::NotEnoughBytes { have, need } => {
963                write!(
964                    f,
965                    "Not enough byte to parse the literals section header. Have: {have}, Need: {need}",
966                )
967            }
968        }
969    }
970}
971
972impl From<GetBitsError> for LiteralsSectionParseError {
973    fn from(val: GetBitsError) -> Self {
974        Self::GetBitsError(val)
975    }
976}
977
978impl core::fmt::Display for LiteralsSectionType {
979    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
980        match self {
981            LiteralsSectionType::Compressed => write!(f, "Compressed"),
982            LiteralsSectionType::Raw => write!(f, "Raw"),
983            LiteralsSectionType::RLE => write!(f, "RLE"),
984            LiteralsSectionType::Treeless => write!(f, "Treeless"),
985        }
986    }
987}
988
989#[derive(Debug)]
990#[non_exhaustive]
991pub enum SequencesHeaderParseError {
992    NotEnoughBytes { need_at_least: u8, got: usize },
993}
994
995#[cfg(feature = "std")]
996impl std::error::Error for SequencesHeaderParseError {}
997
998impl core::fmt::Display for SequencesHeaderParseError {
999    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1000        match self {
1001            SequencesHeaderParseError::NotEnoughBytes { need_at_least, got } => {
1002                write!(
1003                    f,
1004                    "source must have at least {need_at_least} bytes to parse header; got {got} bytes",
1005                )
1006            }
1007        }
1008    }
1009}
1010
1011#[derive(Debug)]
1012#[non_exhaustive]
1013pub enum FSETableError {
1014    AccLogIsZero,
1015    AccLogTooBig {
1016        got: u8,
1017        max: u8,
1018    },
1019    GetBitsError(GetBitsError),
1020    ProbabilityCounterMismatch {
1021        got: u32,
1022        expected_sum: u32,
1023        symbol_probabilities: Vec<i32>,
1024    },
1025    TooManySymbols {
1026        got: usize,
1027    },
1028}
1029
1030#[cfg(feature = "std")]
1031impl std::error::Error for FSETableError {
1032    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
1033        match self {
1034            FSETableError::GetBitsError(source) => Some(source),
1035            _ => None,
1036        }
1037    }
1038}
1039
1040impl core::fmt::Display for FSETableError {
1041    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1042        match self {
1043            FSETableError::AccLogIsZero => write!(f, "Acclog must be at least 1"),
1044            FSETableError::AccLogTooBig { got, max } => {
1045                write!(
1046                    f,
1047                    "Found FSE acc_log: {got} bigger than allowed maximum in this case: {max}"
1048                )
1049            }
1050            FSETableError::GetBitsError(e) => write!(f, "{e:?}"),
1051            FSETableError::ProbabilityCounterMismatch {
1052                got,
1053                expected_sum,
1054                symbol_probabilities,
1055            } => {
1056                write!(
1057                    f,
1058                    "The counter ({got}) exceeded the expected sum: {expected_sum}. This means an error or corrupted data \n {symbol_probabilities:?}",
1059                )
1060            }
1061            FSETableError::TooManySymbols { got } => {
1062                write!(
1063                    f,
1064                    "There are too many symbols in this distribution: {got}. Max: 256",
1065                )
1066            }
1067        }
1068    }
1069}
1070
1071impl From<GetBitsError> for FSETableError {
1072    fn from(val: GetBitsError) -> Self {
1073        Self::GetBitsError(val)
1074    }
1075}
1076
1077#[derive(Debug)]
1078#[non_exhaustive]
1079pub enum FSEDecoderError {
1080    GetBitsError(GetBitsError),
1081    TableIsUninitialized,
1082    /// Externally constructed `FSETable` violates the
1083    /// `decode.len() == 1 << accuracy_log` shape invariant. Only
1084    /// reachable under `feature = "fuzz_exports"`, where fuzz
1085    /// harnesses can set the `FSETable.decode` / `accuracy_log`
1086    /// fields directly and skip `build_decoding_table`.
1087    InvalidTableShape {
1088        decode_len: usize,
1089        accuracy_log: u8,
1090    },
1091}
1092
1093#[cfg(feature = "std")]
1094impl std::error::Error for FSEDecoderError {
1095    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
1096        match self {
1097            FSEDecoderError::GetBitsError(source) => Some(source),
1098            _ => None,
1099        }
1100    }
1101}
1102
1103impl core::fmt::Display for FSEDecoderError {
1104    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1105        match self {
1106            FSEDecoderError::GetBitsError(e) => write!(f, "{e:?}"),
1107            FSEDecoderError::TableIsUninitialized => {
1108                write!(f, "Tried to use an uninitialized table!")
1109            }
1110            FSEDecoderError::InvalidTableShape {
1111                decode_len,
1112                accuracy_log,
1113            } => match 1usize.checked_shl((*accuracy_log).into()) {
1114                Some(expected) => write!(
1115                    f,
1116                    "FSETable shape invariant violated: decode.len() = {decode_len}, expected 1 << accuracy_log = {expected} (accuracy_log = {accuracy_log})",
1117                ),
1118                None => write!(
1119                    f,
1120                    "FSETable shape invariant violated: decode.len() = {decode_len}, accuracy_log = {accuracy_log} overflows 1 << accuracy_log for usize",
1121                ),
1122            },
1123        }
1124    }
1125}
1126
1127impl From<GetBitsError> for FSEDecoderError {
1128    fn from(val: GetBitsError) -> Self {
1129        Self::GetBitsError(val)
1130    }
1131}
1132
1133#[derive(Debug)]
1134#[non_exhaustive]
1135pub enum HuffmanTableError {
1136    GetBitsError(GetBitsError),
1137    FSEDecoderError(FSEDecoderError),
1138    FSETableError(FSETableError),
1139    SourceIsEmpty,
1140    NotEnoughBytesForWeights {
1141        got_bytes: usize,
1142        expected_bytes: u8,
1143    },
1144    ExtraPadding {
1145        skipped_bits: i32,
1146    },
1147    TooManyWeights {
1148        got: usize,
1149    },
1150    MissingWeights,
1151    LeftoverIsNotAPowerOf2 {
1152        got: u32,
1153    },
1154    NotEnoughBytesToDecompressWeights {
1155        have: usize,
1156        need: usize,
1157    },
1158    FSETableUsedTooManyBytes {
1159        used: usize,
1160        available_bytes: u8,
1161    },
1162    NotEnoughBytesInSource {
1163        got: usize,
1164        need: usize,
1165    },
1166    WeightBiggerThanMaxNumBits {
1167        got: u8,
1168    },
1169    MaxBitsTooHigh {
1170        got: u8,
1171    },
1172}
1173
1174#[cfg(feature = "std")]
1175impl StdError for HuffmanTableError {
1176    fn source(&self) -> Option<&(dyn StdError + 'static)> {
1177        match self {
1178            HuffmanTableError::GetBitsError(source) => Some(source),
1179            HuffmanTableError::FSEDecoderError(source) => Some(source),
1180            HuffmanTableError::FSETableError(source) => Some(source),
1181            _ => None,
1182        }
1183    }
1184}
1185
1186impl core::fmt::Display for HuffmanTableError {
1187    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> ::core::fmt::Result {
1188        match self {
1189            HuffmanTableError::GetBitsError(e) => write!(f, "{e:?}"),
1190            HuffmanTableError::FSEDecoderError(e) => write!(f, "{e:?}"),
1191            HuffmanTableError::FSETableError(e) => write!(f, "{e:?}"),
1192            HuffmanTableError::SourceIsEmpty => write!(f, "Source needs to have at least one byte"),
1193            HuffmanTableError::NotEnoughBytesForWeights {
1194                got_bytes,
1195                expected_bytes,
1196            } => {
1197                write!(
1198                    f,
1199                    "Header says there should be {expected_bytes} bytes for the weights but there are only {got_bytes} bytes in the stream"
1200                )
1201            }
1202            HuffmanTableError::ExtraPadding { skipped_bits } => {
1203                write!(
1204                    f,
1205                    "Padding at the end of the sequence_section was more than a byte long: {skipped_bits} bits. Probably caused by data corruption",
1206                )
1207            }
1208            HuffmanTableError::TooManyWeights { got } => {
1209                write!(
1210                    f,
1211                    "More than 255 weights decoded (got {got} weights). Stream is probably corrupted",
1212                )
1213            }
1214            HuffmanTableError::MissingWeights => {
1215                write!(f, "Can\'t build huffman table without any weights")
1216            }
1217            HuffmanTableError::LeftoverIsNotAPowerOf2 { got } => {
1218                write!(f, "Leftover must be power of two but is: {got}")
1219            }
1220            HuffmanTableError::NotEnoughBytesToDecompressWeights { have, need } => {
1221                write!(
1222                    f,
1223                    "Not enough bytes in stream to decompress weights. Is: {have}, Should be: {need}",
1224                )
1225            }
1226            HuffmanTableError::FSETableUsedTooManyBytes {
1227                used,
1228                available_bytes,
1229            } => {
1230                write!(
1231                    f,
1232                    "FSE table used more bytes: {used} than were meant to be used for the whole stream of huffman weights ({available_bytes})",
1233                )
1234            }
1235            HuffmanTableError::NotEnoughBytesInSource { got, need } => {
1236                write!(f, "Source needs to have at least {need} bytes, got: {got}",)
1237            }
1238            HuffmanTableError::WeightBiggerThanMaxNumBits { got } => {
1239                write!(
1240                    f,
1241                    "Cant have weight: {} bigger than max_num_bits: {}",
1242                    got,
1243                    crate::huff0::MAX_MAX_NUM_BITS,
1244                )
1245            }
1246            HuffmanTableError::MaxBitsTooHigh { got } => {
1247                write!(
1248                    f,
1249                    "max_bits derived from weights is: {} should be lower than: {}",
1250                    got,
1251                    crate::huff0::MAX_MAX_NUM_BITS,
1252                )
1253            }
1254        }
1255    }
1256}
1257
1258impl From<GetBitsError> for HuffmanTableError {
1259    fn from(val: GetBitsError) -> Self {
1260        Self::GetBitsError(val)
1261    }
1262}
1263
1264impl From<FSEDecoderError> for HuffmanTableError {
1265    fn from(val: FSEDecoderError) -> Self {
1266        Self::FSEDecoderError(val)
1267    }
1268}
1269
1270impl From<FSETableError> for HuffmanTableError {
1271    fn from(val: FSETableError) -> Self {
1272        Self::FSETableError(val)
1273    }
1274}
1275
1276#[derive(Debug)]
1277#[non_exhaustive]
1278pub enum HuffmanDecoderError {
1279    GetBitsError(GetBitsError),
1280}
1281
1282impl core::fmt::Display for HuffmanDecoderError {
1283    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1284        match self {
1285            HuffmanDecoderError::GetBitsError(e) => write!(f, "{e:?}"),
1286        }
1287    }
1288}
1289
1290#[cfg(feature = "std")]
1291impl StdError for HuffmanDecoderError {
1292    fn source(&self) -> Option<&(dyn StdError + 'static)> {
1293        match self {
1294            HuffmanDecoderError::GetBitsError(source) => Some(source),
1295        }
1296    }
1297}
1298
1299impl From<GetBitsError> for HuffmanDecoderError {
1300    fn from(val: GetBitsError) -> Self {
1301        Self::GetBitsError(val)
1302    }
1303}
1304
1305#[cfg(test)]
1306mod tests {
1307    use alloc::{string::ToString, vec};
1308
1309    use super::{
1310        BlockTypeError, DecodeBlockContentError, DecodeSequenceError, DecompressBlockError,
1311        DecompressLiteralsError, FSETableError, FrameDecoderError, HuffmanTableError,
1312    };
1313
1314    #[test]
1315    fn block_and_sequence_display_messages_are_specific() {
1316        assert_eq!(
1317            BlockTypeError::InvalidBlocktypeNumber { num: 7 }.to_string(),
1318            "Invalid Blocktype number. Is: 7. Should be one of: 0, 1, 2, 3 (3 is reserved)."
1319        );
1320        assert_eq!(
1321            DecompressBlockError::MalformedSectionHeader {
1322                expected_len: 12,
1323                remaining_bytes: 3,
1324            }
1325            .to_string(),
1326            "Malformed section header. Says literals would be this long: 12 but there are only 3 bytes left"
1327        );
1328        assert_eq!(
1329            DecodeBlockContentError::ExpectedHeaderOfPreviousBlock.to_string(),
1330            "Can't decode next block body, while expecting to decode the header of the previous block. Results will be nonsense"
1331        );
1332        assert_eq!(
1333            DecodeSequenceError::ExtraPadding { skipped_bits: 11 }.to_string(),
1334            "Padding at the end of the sequence_section was more than a byte long: 11 bits. Probably caused by data corruption"
1335        );
1336    }
1337
1338    #[test]
1339    fn frame_decoder_display_messages_are_specific() {
1340        assert_eq!(
1341            FrameDecoderError::TargetTooSmall.to_string(),
1342            "Target must have at least as many bytes as the content size reported by the frame"
1343        );
1344        assert_eq!(
1345            FrameDecoderError::DictNotProvided { dict_id: 0xABCD }.to_string(),
1346            "Frame header specified dictionary id 0xABCD that wasn't provided via add_dict()/add_dict_from_bytes() (or add_dict_handle() on atomic targets) or reset_with_dict_handle()/decode_all_with_dict_handle()/decode_all_with_dict_bytes()"
1347        );
1348        assert_eq!(
1349            FrameDecoderError::DictIdMismatch {
1350                expected: 0xABCD,
1351                provided: 0x1234
1352            }
1353            .to_string(),
1354            "Frame header dictionary id 0xABCD does not match provided dictionary id 0x1234"
1355        );
1356        assert_eq!(
1357            FrameDecoderError::DictAlreadyRegistered { dict_id: 0xABCD }.to_string(),
1358            "Dictionary id 0xABCD already registered in decoder"
1359        );
1360        assert_eq!(
1361            FrameDecoderError::FrameContentSizeMismatch {
1362                declared: 100,
1363                produced: 87,
1364            }
1365            .to_string(),
1366            "Frame content size mismatch (corrupt frame): declared 100 bytes, blocks summed to 87 bytes"
1367        );
1368    }
1369
1370    #[test]
1371    fn literal_display_messages_are_specific() {
1372        assert_eq!(
1373            DecompressLiteralsError::MissingCompressedSize.to_string(),
1374            "compressed size was none even though it must be set to something for compressed literals"
1375        );
1376        assert_eq!(
1377            DecompressLiteralsError::MissingNumStreams.to_string(),
1378            "num_streams was none even though it must be set to something (1 or 4) for compressed literals"
1379        );
1380        assert_eq!(
1381            DecompressLiteralsError::ExtraPadding { skipped_bits: 9 }.to_string(),
1382            "Padding at the end of the sequence_section was more than a byte long: 9 bits. Probably caused by data corruption"
1383        );
1384    }
1385
1386    #[test]
1387    fn fse_and_huffman_display_messages_are_specific() {
1388        assert_eq!(
1389            FSETableError::ProbabilityCounterMismatch {
1390                got: 4,
1391                expected_sum: 3,
1392                symbol_probabilities: vec![1, -1],
1393            }
1394            .to_string(),
1395            "The counter (4) exceeded the expected sum: 3. This means an error or corrupted data \n [1, -1]"
1396        );
1397        assert_eq!(
1398            HuffmanTableError::NotEnoughBytesForWeights {
1399                got_bytes: 2,
1400                expected_bytes: 5,
1401            }
1402            .to_string(),
1403            "Header says there should be 5 bytes for the weights but there are only 2 bytes in the stream"
1404        );
1405        assert_eq!(
1406            HuffmanTableError::ExtraPadding { skipped_bits: 13 }.to_string(),
1407            "Padding at the end of the sequence_section was more than a byte long: 13 bits. Probably caused by data corruption"
1408        );
1409        assert_eq!(
1410            HuffmanTableError::FSETableUsedTooManyBytes {
1411                used: 7,
1412                available_bytes: 6,
1413            }
1414            .to_string(),
1415            "FSE table used more bytes: 7 than were meant to be used for the whole stream of huffman weights (6)"
1416        );
1417    }
1418}