diff --git a/Cargo.toml b/Cargo.toml index 334a2705..b9600585 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,6 @@ categories = ["compression"] [dependencies] byteorder = { version = "1.5", default-features = false } twox-hash = { version = "1.6", default-features = false, optional = true } -derive_more = { version = "0.99", default-features = false, features = ["display", "from"] } [dev-dependencies] criterion = "0.5" @@ -24,7 +23,7 @@ rand = { version = "0.8.5", features = ["small_rng"] } [features] default = ["hash", "std"] hash = ["dep:twox-hash"] -std = ["derive_more/error"] +std = [] [[bench]] name = "reversedbitreader_bench" diff --git a/src/blocks/literals_section.rs b/src/blocks/literals_section.rs index 50d821c1..7e7d4909 100644 --- a/src/blocks/literals_section.rs +++ b/src/blocks/literals_section.rs @@ -14,21 +14,51 @@ pub enum LiteralsSectionType { Treeless, } -#[derive(Debug, derive_more::Display, derive_more::From)] -#[cfg_attr(feature = "std", derive(derive_more::Error))] +#[derive(Debug)] #[non_exhaustive] pub enum LiteralsSectionParseError { - #[display(fmt = "Illegal literalssectiontype. Is: {got}, must be in: 0, 1, 2, 3")] IllegalLiteralSectionType { got: u8 }, - #[display(fmt = "{_0:?}")] - #[from] GetBitsError(GetBitsError), - #[display( - fmt = "Not enough byte to parse the literals section header. Have: {have}, Need: {need}" - )] NotEnoughBytes { have: usize, need: u8 }, } +#[cfg(feature = "std")] +impl std::error::Error for LiteralsSectionParseError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + LiteralsSectionParseError::GetBitsError(source) => Some(source), + _ => None, + } + } +} +impl core::fmt::Display for LiteralsSectionParseError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + LiteralsSectionParseError::IllegalLiteralSectionType { got } => { + write!( + f, + "Illegal literalssectiontype. Is: {}, must be in: 0, 1, 2, 3", + got + ) + } + LiteralsSectionParseError::GetBitsError(e) => write!(f, "{:?}", e), + LiteralsSectionParseError::NotEnoughBytes { have, need } => { + write!( + f, + "Not enough byte to parse the literals section header. Have: {}, Need: {}", + have, need, + ) + } + } + } +} + +impl From for LiteralsSectionParseError { + fn from(val: GetBitsError) -> Self { + Self::GetBitsError(val) + } +} + impl core::fmt::Display for LiteralsSectionType { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> { match self { diff --git a/src/blocks/sequence_section.rs b/src/blocks/sequence_section.rs index 47b18d72..bc28425e 100644 --- a/src/blocks/sequence_section.rs +++ b/src/blocks/sequence_section.rs @@ -55,16 +55,29 @@ impl Default for SequencesHeader { } } -#[derive(Debug, derive_more::Display)] -#[cfg_attr(feature = "std", derive(derive_more::Error))] +#[derive(Debug)] #[non_exhaustive] pub enum SequencesHeaderParseError { - #[display( - fmt = "source must have at least {need_at_least} bytes to parse header; got {got} bytes" - )] NotEnoughBytes { need_at_least: u8, got: usize }, } +#[cfg(feature = "std")] +impl std::error::Error for SequencesHeaderParseError {} + +impl core::fmt::Display for SequencesHeaderParseError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + SequencesHeaderParseError::NotEnoughBytes { need_at_least, got } => { + write!( + f, + "source must have at least {} bytes to parse header; got {} bytes", + need_at_least, got, + ) + } + } + } +} + impl SequencesHeader { pub fn new() -> SequencesHeader { SequencesHeader { diff --git a/src/decoding/bit_reader.rs b/src/decoding/bit_reader.rs index 55fb3064..26228aa6 100644 --- a/src/decoding/bit_reader.rs +++ b/src/decoding/bit_reader.rs @@ -3,19 +3,47 @@ pub struct BitReader<'s> { source: &'s [u8], } -#[derive(Debug, derive_more::Display)] -#[cfg_attr(feature = "std", derive(derive_more::Error))] +#[derive(Debug)] #[non_exhaustive] pub enum GetBitsError { - #[display( - fmt = "Cant serve this request. The reader is limited to {limit} bits, requested {num_requested_bits} bits" - )] TooManyBits { num_requested_bits: usize, limit: u8, }, - #[display(fmt = "Can't read {requested} bits, only have {remaining} bits left")] - NotEnoughRemainingBits { requested: usize, remaining: usize }, + NotEnoughRemainingBits { + requested: usize, + remaining: usize, + }, +} + +#[cfg(feature = "std")] +impl std::error::Error for GetBitsError {} + +impl core::fmt::Display for GetBitsError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + GetBitsError::TooManyBits { + num_requested_bits, + limit, + } => { + write!( + f, + "Cant serve this request. The reader is limited to {} bits, requested {} bits", + limit, num_requested_bits, + ) + } + GetBitsError::NotEnoughRemainingBits { + requested, + remaining, + } => { + write!( + f, + "Can\'t read {} bits, only have {} bits left", + requested, remaining, + ) + } + } + } } impl<'s> BitReader<'s> { diff --git a/src/decoding/block_decoder.rs b/src/decoding/block_decoder.rs index 18307b09..9d48b21e 100644 --- a/src/decoding/block_decoder.rs +++ b/src/decoding/block_decoder.rs @@ -25,91 +25,245 @@ enum DecoderState { Failed, //TODO put "self.internal_state = DecoderState::Failed;" everywhere an unresolvable error occurs } -#[derive(Debug, derive_more::Display, derive_more::From)] -#[cfg_attr(feature = "std", derive(derive_more::Error))] +#[derive(Debug)] #[non_exhaustive] pub enum BlockHeaderReadError { - #[display(fmt = "Error while reading the block header")] - #[from] ReadError(io::Error), - #[display(fmt = "Reserved block occured. This is considered corruption by the documentation")] FoundReservedBlock, - #[display(fmt = "Error getting block type: {_0}")] - #[from] BlockTypeError(BlockTypeError), - #[display(fmt = "Error getting block content size: {_0}")] - #[from] BlockSizeError(BlockSizeError), } -#[derive(Debug, derive_more::Display)] -#[cfg_attr(feature = "std", derive(derive_more::Error))] +#[cfg(feature = "std")] +impl std::error::Error for BlockHeaderReadError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + BlockHeaderReadError::ReadError(source) => Some(source), + BlockHeaderReadError::BlockTypeError(source) => Some(source), + BlockHeaderReadError::BlockSizeError(source) => Some(source), + BlockHeaderReadError::FoundReservedBlock => None, + } + } +} + +impl ::core::fmt::Display for BlockHeaderReadError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> ::core::fmt::Result { + match self { + BlockHeaderReadError::ReadError(_) => write!(f, "Error while reading the block header"), + BlockHeaderReadError::FoundReservedBlock => write!( + f, + "Reserved block occured. This is considered corruption by the documentation" + ), + BlockHeaderReadError::BlockTypeError(e) => write!(f, "Error getting block type: {}", e), + BlockHeaderReadError::BlockSizeError(e) => { + write!(f, "Error getting block content size: {}", e) + } + } + } +} + +impl From for BlockHeaderReadError { + fn from(val: io::Error) -> Self { + Self::ReadError(val) + } +} + +impl From for BlockHeaderReadError { + fn from(val: BlockTypeError) -> Self { + Self::BlockTypeError(val) + } +} + +impl From for BlockHeaderReadError { + fn from(val: BlockSizeError) -> Self { + Self::BlockSizeError(val) + } +} + +#[derive(Debug)] #[non_exhaustive] pub enum BlockTypeError { - #[display( - fmt = "Invalid Blocktype number. Is: {num} Should be one of: 0, 1, 2, 3 (3 is reserved though" - )] InvalidBlocktypeNumber { num: u8 }, } -#[derive(Debug, derive_more::Display)] -#[cfg_attr(feature = "std", derive(derive_more::Error))] +#[cfg(feature = "std")] +impl std::error::Error for BlockTypeError {} + +impl core::fmt::Display for BlockTypeError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + BlockTypeError::InvalidBlocktypeNumber { num } => { + write!(f, + "Invalid Blocktype number. Is: {} Should be one of: 0, 1, 2, 3 (3 is reserved though", + num, + ) + } + } + } +} + +#[derive(Debug)] #[non_exhaustive] pub enum BlockSizeError { - #[display( - fmt = "Blocksize was bigger than the absolute maximum {ABSOLUTE_MAXIMUM_BLOCK_SIZE} (128kb). Is: {size}" - )] BlockSizeTooLarge { size: u32 }, } -#[derive(Debug, derive_more::Display, derive_more::From)] -#[cfg_attr(feature = "std", derive(derive_more::Error))] +#[cfg(feature = "std")] +impl std::error::Error for BlockSizeError {} + +impl core::fmt::Display for BlockSizeError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + BlockSizeError::BlockSizeTooLarge { size } => { + write!( + f, + "Blocksize was bigger than the absolute maximum {} (128kb). Is: {}", + ABSOLUTE_MAXIMUM_BLOCK_SIZE, size, + ) + } + } + } +} + +#[derive(Debug)] #[non_exhaustive] pub enum DecompressBlockError { - #[display(fmt = "Error while reading the block content: {_0}")] - #[from] BlockContentReadError(io::Error), - #[display( - fmt = "Malformed section header. Says literals would be this long: {expected_len} but there are only {remaining_bytes} bytes left" - )] MalformedSectionHeader { expected_len: usize, remaining_bytes: usize, }, - #[display(fmt = "{_0:?}")] - #[from] DecompressLiteralsError(DecompressLiteralsError), - #[display(fmt = "{_0:?}")] - #[from] LiteralsSectionParseError(LiteralsSectionParseError), - #[display(fmt = "{_0:?}")] - #[from] SequencesHeaderParseError(SequencesHeaderParseError), - #[display(fmt = "{_0:?}")] - #[from] DecodeSequenceError(DecodeSequenceError), - #[display(fmt = "{_0:?}")] - #[from] ExecuteSequencesError(ExecuteSequencesError), } -#[derive(Debug, derive_more::Display, derive_more::From)] -#[cfg_attr(feature = "std", derive(derive_more::Error))] +#[cfg(feature = "std")] +impl std::error::Error for DecompressBlockError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + DecompressBlockError::BlockContentReadError(source) => Some(source), + DecompressBlockError::DecompressLiteralsError(source) => Some(source), + DecompressBlockError::LiteralsSectionParseError(source) => Some(source), + DecompressBlockError::SequencesHeaderParseError(source) => Some(source), + DecompressBlockError::DecodeSequenceError(source) => Some(source), + DecompressBlockError::ExecuteSequencesError(source) => Some(source), + _ => None, + } + } +} + +impl core::fmt::Display for DecompressBlockError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + DecompressBlockError::BlockContentReadError(e) => { + write!(f, "Error while reading the block content: {}", e) + } + DecompressBlockError::MalformedSectionHeader { + expected_len, + remaining_bytes, + } => { + write!(f, + "Malformed section header. Says literals would be this long: {} but there are only {} bytes left", + expected_len, + remaining_bytes, + ) + } + DecompressBlockError::DecompressLiteralsError(e) => write!(f, "{:?}", e), + DecompressBlockError::LiteralsSectionParseError(e) => write!(f, "{:?}", e), + DecompressBlockError::SequencesHeaderParseError(e) => write!(f, "{:?}", e), + DecompressBlockError::DecodeSequenceError(e) => write!(f, "{:?}", e), + DecompressBlockError::ExecuteSequencesError(e) => write!(f, "{:?}", e), + } + } +} + +impl From for DecompressBlockError { + fn from(val: io::Error) -> Self { + Self::BlockContentReadError(val) + } +} + +impl From for DecompressBlockError { + fn from(val: DecompressLiteralsError) -> Self { + Self::DecompressLiteralsError(val) + } +} + +impl From for DecompressBlockError { + fn from(val: LiteralsSectionParseError) -> Self { + Self::LiteralsSectionParseError(val) + } +} + +impl From for DecompressBlockError { + fn from(val: SequencesHeaderParseError) -> Self { + Self::SequencesHeaderParseError(val) + } +} + +impl From for DecompressBlockError { + fn from(val: DecodeSequenceError) -> Self { + Self::DecodeSequenceError(val) + } +} + +impl From for DecompressBlockError { + fn from(val: ExecuteSequencesError) -> Self { + Self::ExecuteSequencesError(val) + } +} + +#[derive(Debug)] #[non_exhaustive] pub enum DecodeBlockContentError { - #[display(fmt = "Can't decode next block if failed along the way. Results will be nonsense")] DecoderStateIsFailed, - #[display( - fmt = "Cant decode next block body, while expecting to decode the header of the previous block. Results will be nonsense" - )] ExpectedHeaderOfPreviousBlock, - #[display(fmt = "Error while reading bytes for {step}: {source}")] ReadError { step: BlockType, source: io::Error }, - #[display(fmt = "{_0:?}")] - #[from] DecompressBlockError(DecompressBlockError), } +#[cfg(feature = "std")] +impl std::error::Error for DecodeBlockContentError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + DecodeBlockContentError::ReadError { step: _, source } => Some(source), + DecodeBlockContentError::DecompressBlockError(source) => Some(source), + _ => None, + } + } +} + +impl core::fmt::Display for DecodeBlockContentError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + DecodeBlockContentError::DecoderStateIsFailed => { + write!( + f, + "Can't decode next block if failed along the way. Results will be nonsense", + ) + } + DecodeBlockContentError::ExpectedHeaderOfPreviousBlock => { + write!(f, + "Can't decode next block body, while expecting to decode the header of the previous block. Results will be nonsense", + ) + } + DecodeBlockContentError::ReadError { step, source } => { + write!(f, "Error while reading bytes for {}: {}", step, source,) + } + DecodeBlockContentError::DecompressBlockError(e) => write!(f, "{:?}", e), + } + } +} + +impl From for DecodeBlockContentError { + fn from(val: DecompressBlockError) -> Self { + Self::DecompressBlockError(val) + } +} + pub fn new() -> BlockDecoder { BlockDecoder { internal_state: DecoderState::ReadyToDecodeNextHeader, diff --git a/src/decoding/decodebuffer.rs b/src/decoding/decodebuffer.rs index 8fcb98c4..6e98d150 100644 --- a/src/decoding/decodebuffer.rs +++ b/src/decoding/decodebuffer.rs @@ -15,16 +15,33 @@ pub struct Decodebuffer { pub hash: twox_hash::XxHash64, } -#[derive(Debug, derive_more::Display)] -#[cfg_attr(feature = "std", derive(derive_more::Error))] +#[derive(Debug)] #[non_exhaustive] pub enum DecodebufferError { - #[display(fmt = "Need {need} bytes from the dictionary but it is only {got} bytes long")] NotEnoughBytesInDictionary { got: usize, need: usize }, - #[display(fmt = "offset: {offset} bigger than buffer: {buf_len}")] OffsetTooBig { offset: usize, buf_len: usize }, } +#[cfg(feature = "std")] +impl std::error::Error for DecodebufferError {} + +impl core::fmt::Display for DecodebufferError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + DecodebufferError::NotEnoughBytesInDictionary { got, need } => { + write!( + f, + "Need {} bytes from the dictionary but it is only {} bytes long", + need, got, + ) + } + DecodebufferError::OffsetTooBig { offset, buf_len } => { + write!(f, "offset: {} bigger than buffer: {}", offset, buf_len,) + } + } + } +} + impl Read for Decodebuffer { fn read(&mut self, target: &mut [u8]) -> Result { let max_amount = self.can_drain_to_window_size().unwrap_or(0); diff --git a/src/decoding/dictionary.rs b/src/decoding/dictionary.rs index b86678e1..35c05ffc 100644 --- a/src/decoding/dictionary.rs +++ b/src/decoding/dictionary.rs @@ -14,22 +14,53 @@ pub struct Dictionary { pub offset_hist: [u32; 3], } -#[derive(Debug, derive_more::Display, derive_more::From)] -#[cfg_attr(feature = "std", derive(derive_more::Error))] +#[derive(Debug)] #[non_exhaustive] pub enum DictionaryDecodeError { - #[display( - fmt = "Bad magic_num at start of the dictionary; Got: {got:#04X?}, Expected: {MAGIC_NUM:#04x?}" - )] BadMagicNum { got: [u8; 4] }, - #[display(fmt = "{_0:?}")] - #[from] FSETableError(FSETableError), - #[display(fmt = "{_0:?}")] - #[from] HuffmanTableError(HuffmanTableError), } +#[cfg(feature = "std")] +impl std::error::Error for DictionaryDecodeError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + DictionaryDecodeError::FSETableError(source) => Some(source), + DictionaryDecodeError::HuffmanTableError(source) => Some(source), + _ => None, + } + } +} + +impl core::fmt::Display for DictionaryDecodeError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + DictionaryDecodeError::BadMagicNum { got } => { + write!( + f, + "Bad magic_num at start of the dictionary; Got: {:#04X?}, Expected: {:#04x?}", + got, MAGIC_NUM, + ) + } + DictionaryDecodeError::FSETableError(e) => write!(f, "{:?}", e), + DictionaryDecodeError::HuffmanTableError(e) => write!(f, "{:?}", e), + } + } +} + +impl From for DictionaryDecodeError { + fn from(val: FSETableError) -> Self { + Self::FSETableError(val) + } +} + +impl From for DictionaryDecodeError { + fn from(val: HuffmanTableError) -> Self { + Self::HuffmanTableError(val) + } +} + pub const MAGIC_NUM: [u8; 4] = [0x37, 0xA4, 0x30, 0xEC]; impl Dictionary { diff --git a/src/decoding/literals_section_decoder.rs b/src/decoding/literals_section_decoder.rs index 50e0c941..dbb81ae3 100644 --- a/src/decoding/literals_section_decoder.rs +++ b/src/decoding/literals_section_decoder.rs @@ -4,43 +4,107 @@ use super::scratch::HuffmanScratch; use crate::huff0::{HuffmanDecoder, HuffmanDecoderError, HuffmanTableError}; use alloc::vec::Vec; -#[derive(Debug, derive_more::Display, derive_more::From)] -#[cfg_attr(feature = "std", derive(derive_more::Error))] +#[derive(Debug)] #[non_exhaustive] pub enum DecompressLiteralsError { - #[display( - fmt = "compressed size was none even though it must be set to something for compressed literals" - )] MissingCompressedSize, - #[display( - fmt = "num_streams was none even though it must be set to something (1 or 4) for compressed literals" - )] MissingNumStreams, - #[display(fmt = "{_0:?}")] - #[from] GetBitsError(GetBitsError), - #[display(fmt = "{_0:?}")] - #[from] HuffmanTableError(HuffmanTableError), - #[display(fmt = "{_0:?}")] - #[from] HuffmanDecoderError(HuffmanDecoderError), - #[display(fmt = "Tried to reuse huffman table but it was never initialized")] UninitializedHuffmanTable, - #[display(fmt = "Need 6 bytes to decode jump header, got {got} bytes")] MissingBytesForJumpHeader { got: usize }, - #[display(fmt = "Need at least {needed} bytes to decode literals. Have: {got} bytes")] MissingBytesForLiterals { got: usize, needed: usize }, - #[display( - fmt = "Padding at the end of the sequence_section was more than a byte long: {skipped_bits} bits. Probably caused by data corruption" - )] ExtraPadding { skipped_bits: i32 }, - #[display(fmt = "Bitstream was read till: {read_til}, should have been: {expected}")] BitstreamReadMismatch { read_til: isize, expected: isize }, - #[display(fmt = "Did not decode enough literals: {decoded}, Should have been: {expected}")] DecodedLiteralCountMismatch { decoded: usize, expected: usize }, } +#[cfg(feature = "std")] +impl std::error::Error for DecompressLiteralsError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + DecompressLiteralsError::GetBitsError(source) => Some(source), + DecompressLiteralsError::HuffmanTableError(source) => Some(source), + DecompressLiteralsError::HuffmanDecoderError(source) => Some(source), + _ => None, + } + } +} +impl core::fmt::Display for DecompressLiteralsError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + DecompressLiteralsError::MissingCompressedSize => { + write!(f, + "compressed size was none even though it must be set to something for compressed literals", + ) + } + DecompressLiteralsError::MissingNumStreams => { + write!(f, + "num_streams was none even though it must be set to something (1 or 4) for compressed literals", + ) + } + DecompressLiteralsError::GetBitsError(e) => write!(f, "{:?}", e), + DecompressLiteralsError::HuffmanTableError(e) => write!(f, "{:?}", e), + DecompressLiteralsError::HuffmanDecoderError(e) => write!(f, "{:?}", e), + DecompressLiteralsError::UninitializedHuffmanTable => { + write!( + f, + "Tried to reuse huffman table but it was never initialized", + ) + } + DecompressLiteralsError::MissingBytesForJumpHeader { got } => { + write!(f, "Need 6 bytes to decode jump header, got {} bytes", got,) + } + DecompressLiteralsError::MissingBytesForLiterals { got, needed } => { + write!( + f, + "Need at least {} bytes to decode literals. Have: {} bytes", + needed, got, + ) + } + DecompressLiteralsError::ExtraPadding { skipped_bits } => { + write!(f, + "Padding at the end of the sequence_section was more than a byte long: {} bits. Probably caused by data corruption", + skipped_bits, + ) + } + DecompressLiteralsError::BitstreamReadMismatch { read_til, expected } => { + write!( + f, + "Bitstream was read till: {}, should have been: {}", + read_til, expected, + ) + } + DecompressLiteralsError::DecodedLiteralCountMismatch { decoded, expected } => { + write!( + f, + "Did not decode enough literals: {}, Should have been: {}", + decoded, expected, + ) + } + } + } +} + +impl From for DecompressLiteralsError { + fn from(val: HuffmanDecoderError) -> Self { + Self::HuffmanDecoderError(val) + } +} + +impl From for DecompressLiteralsError { + fn from(val: GetBitsError) -> Self { + Self::GetBitsError(val) + } +} + +impl From for DecompressLiteralsError { + fn from(val: HuffmanTableError) -> Self { + Self::HuffmanTableError(val) + } +} + pub fn decode_literals( section: &LiteralsSection, scratch: &mut HuffmanScratch, diff --git a/src/decoding/sequence_execution.rs b/src/decoding/sequence_execution.rs index cc03c6ec..2e731216 100644 --- a/src/decoding/sequence_execution.rs +++ b/src/decoding/sequence_execution.rs @@ -1,18 +1,49 @@ use super::{decodebuffer::DecodebufferError, scratch::DecoderScratch}; -#[derive(Debug, derive_more::Display, derive_more::From)] -#[cfg_attr(feature = "std", derive(derive_more::Error))] +#[derive(Debug)] #[non_exhaustive] pub enum ExecuteSequencesError { - #[display(fmt = "{_0:?}")] - #[from] DecodebufferError(DecodebufferError), - #[display(fmt = "Sequence wants to copy up to byte {wanted}. Bytes in literalsbuffer: {have}")] NotEnoughBytesForSequence { wanted: usize, have: usize }, - #[display(fmt = "Illegal offset: 0 found")] ZeroOffset, } +impl core::fmt::Display for ExecuteSequencesError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + ExecuteSequencesError::DecodebufferError(e) => { + write!(f, "{:?}", e) + } + ExecuteSequencesError::NotEnoughBytesForSequence { wanted, have } => { + write!( + f, + "Sequence wants to copy up to byte {}. Bytes in literalsbuffer: {}", + wanted, have + ) + } + ExecuteSequencesError::ZeroOffset => { + write!(f, "Illegal offset: 0 found") + } + } + } +} + +#[cfg(feature = "std")] +impl std::error::Error for ExecuteSequencesError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + ExecuteSequencesError::DecodebufferError(source) => Some(source), + _ => None, + } + } +} + +impl From for ExecuteSequencesError { + fn from(val: DecodebufferError) -> Self { + Self::DecodebufferError(val) + } +} + pub fn execute_sequences(scratch: &mut DecoderScratch) -> Result<(), ExecuteSequencesError> { let mut literals_copy_counter = 0; let old_buffer_size = scratch.buffer.len(); diff --git a/src/decoding/sequence_section_decoder.rs b/src/decoding/sequence_section_decoder.rs index e95e9e60..e2b4fd39 100644 --- a/src/decoding/sequence_section_decoder.rs +++ b/src/decoding/sequence_section_decoder.rs @@ -6,41 +6,98 @@ use super::scratch::FSEScratch; use crate::fse::{FSEDecoder, FSEDecoderError, FSETableError}; use alloc::vec::Vec; -#[derive(Debug, derive_more::Display, derive_more::From)] -#[cfg_attr(feature = "std", derive(derive_more::Error))] +#[derive(Debug)] #[non_exhaustive] pub enum DecodeSequenceError { - #[display(fmt = "{_0:?}")] - #[from] GetBitsError(GetBitsError), - #[display(fmt = "{_0:?}")] - #[from] FSEDecoderError(FSEDecoderError), - #[display(fmt = "{_0:?}")] - #[from] FSETableError(FSETableError), - #[display( - fmt = "Padding at the end of the sequence_section was more than a byte long: {skipped_bits} bits. Probably caused by data corruption" - )] ExtraPadding { skipped_bits: i32 }, - #[display(fmt = "Do not support offsets bigger than 1<<32; got: {offset_code}")] UnsupportedOffset { offset_code: u8 }, - #[display(fmt = "Read an offset == 0. That is an illegal value for offsets")] ZeroOffset, - #[display(fmt = "Bytestream did not contain enough bytes to decode num_sequences")] NotEnoughBytesForNumSequences, - #[display(fmt = "Did not use full bitstream. Bits left: {bits_remaining} ({} bytes)", bits_remaining / 8)] ExtraBits { bits_remaining: isize }, - #[display(fmt = "compression modes are none but they must be set to something")] MissingCompressionMode, - #[display(fmt = "Need a byte to read for RLE ll table")] MissingByteForRleLlTable, - #[display(fmt = "Need a byte to read for RLE of table")] MissingByteForRleOfTable, - #[display(fmt = "Need a byte to read for RLE ml table")] MissingByteForRleMlTable, } +#[cfg(feature = "std")] +impl std::error::Error for DecodeSequenceError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + DecodeSequenceError::GetBitsError(source) => Some(source), + DecodeSequenceError::FSEDecoderError(source) => Some(source), + DecodeSequenceError::FSETableError(source) => Some(source), + _ => None, + } + } +} + +impl core::fmt::Display for DecodeSequenceError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + DecodeSequenceError::GetBitsError(e) => write!(f, "{:?}", e), + DecodeSequenceError::FSEDecoderError(e) => write!(f, "{:?}", e), + DecodeSequenceError::FSETableError(e) => write!(f, "{:?}", e), + DecodeSequenceError::ExtraPadding { skipped_bits } => { + write!(f, + "Padding at the end of the sequence_section was more than a byte long: {} bits. Probably caused by data corruption", + skipped_bits, + ) + } + DecodeSequenceError::UnsupportedOffset { offset_code } => { + write!( + f, + "Do not support offsets bigger than 1<<32; got: {}", + offset_code, + ) + } + DecodeSequenceError::ZeroOffset => write!( + f, + "Read an offset == 0. That is an illegal value for offsets" + ), + DecodeSequenceError::NotEnoughBytesForNumSequences => write!( + f, + "Bytestream did not contain enough bytes to decode num_sequences" + ), + DecodeSequenceError::ExtraBits { bits_remaining } => write!(f, "{}", bits_remaining), + DecodeSequenceError::MissingCompressionMode => write!( + f, + "compression modes are none but they must be set to something" + ), + DecodeSequenceError::MissingByteForRleLlTable => { + write!(f, "Need a byte to read for RLE ll table") + } + DecodeSequenceError::MissingByteForRleOfTable => { + write!(f, "Need a byte to read for RLE of table") + } + DecodeSequenceError::MissingByteForRleMlTable => { + write!(f, "Need a byte to read for RLE ml table") + } + } + } +} + +impl From for DecodeSequenceError { + fn from(val: GetBitsError) -> Self { + Self::GetBitsError(val) + } +} + +impl From for DecodeSequenceError { + fn from(val: FSETableError) -> Self { + Self::FSETableError(val) + } +} + +impl From for DecodeSequenceError { + fn from(val: FSEDecoderError) -> Self { + Self::FSEDecoderError(val) + } +} + pub fn decode_sequences( section: &SequencesHeader, source: &[u8], diff --git a/src/frame.rs b/src/frame.rs index eabfca5d..5870e1bc 100644 --- a/src/frame.rs +++ b/src/frame.rs @@ -1,4 +1,8 @@ use crate::io::{Error, Read}; +use core::fmt; +#[cfg(feature = "std")] +use std::error::Error as StdError; + pub const MAGIC_NUM: u32 = 0xFD2F_B528; pub const MIN_WINDOW_SIZE: u64 = 1024; pub const MAX_WINDOW_SIZE: u64 = (1 << 41) + 7 * (1 << 38); @@ -16,14 +20,27 @@ pub struct FrameHeader { pub struct FrameDescriptor(u8); -#[derive(Debug, derive_more::Display)] -#[cfg_attr(feature = "std", derive(derive_more::Error))] +#[derive(Debug)] #[non_exhaustive] pub enum FrameDescriptorError { - #[display(fmt = "Invalid Frame_Content_Size_Flag; Is: {got}, Should be one of: 0, 1, 2, 3")] InvalidFrameContentSizeFlag { got: u8 }, } +impl fmt::Display for FrameDescriptorError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::InvalidFrameContentSizeFlag { got } => write!( + f, + "Invalid Frame_Content_Size_Flag; Is: {}, Should be one of: 0, 1, 2, 3", + got + ), + } + } +} + +#[cfg(feature = "std")] +impl StdError for FrameDescriptorError {} + impl FrameDescriptor { pub fn frame_content_size_flag(&self) -> u8 { self.0 >> 6 @@ -73,33 +90,68 @@ impl FrameDescriptor { } } -#[derive(Debug, derive_more::Display, derive_more::From)] -#[cfg_attr(feature = "std", derive(derive_more::Error))] +#[derive(Debug)] #[non_exhaustive] pub enum FrameHeaderError { - #[display( - fmt = "window_size bigger than allowed maximum. Is: {got}, Should be lower than: {MAX_WINDOW_SIZE}" - )] WindowTooBig { got: u64 }, - #[display( - fmt = "window_size smaller than allowed minimum. Is: {got}, Should be greater than: {MIN_WINDOW_SIZE}" - )] WindowTooSmall { got: u64 }, - #[display(fmt = "{_0:?}")] - #[from] FrameDescriptorError(FrameDescriptorError), - #[display(fmt = "Not enough bytes in dict_id. Is: {got}, Should be: {expected}")] DictIdTooSmall { got: usize, expected: usize }, - #[display( - fmt = "frame_content_size does not have the right length. Is: {got}, Should be: {expected}" - )] MismatchedFrameSize { got: usize, expected: u8 }, - #[display(fmt = "frame_content_size was zero")] FrameSizeIsZero, - #[display(fmt = "Invalid frame_content_size. Is: {got}, Should be one of 1, 2, 4, 8 bytes")] InvalidFrameSize { got: u8 }, } +impl fmt::Display for FrameHeaderError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::WindowTooBig { got } => write!( + f, + "window_size bigger than allowed maximum. Is: {}, Should be lower than: {}", + got, MAX_WINDOW_SIZE + ), + Self::WindowTooSmall { got } => write!( + f, + "window_size smaller than allowed minimum. Is: {}, Should be greater than: {}", + got, MIN_WINDOW_SIZE + ), + Self::FrameDescriptorError(e) => write!(f, "{:?}", e), + Self::DictIdTooSmall { got, expected } => write!( + f, + "Not enough bytes in dict_id. Is: {}, Should be: {}", + got, expected + ), + Self::MismatchedFrameSize { got, expected } => write!( + f, + "frame_content_size does not have the right length. Is: {}, Should be: {}", + got, expected + ), + Self::FrameSizeIsZero => write!(f, "frame_content_size was zero"), + Self::InvalidFrameSize { got } => write!( + f, + "Invalid frame_content_size. Is: {}, Should be one of 1, 2, 4, 8 bytes", + got + ), + } + } +} + +#[cfg(feature = "std")] +impl StdError for FrameHeaderError { + fn source(&self) -> Option<&(dyn StdError + 'static)> { + match self { + FrameHeaderError::FrameDescriptorError(source) => Some(source), + _ => None, + } + } +} + +impl From for FrameHeaderError { + fn from(error: FrameDescriptorError) -> Self { + Self::FrameDescriptorError(error) + } +} + impl FrameHeader { pub fn window_size(&self) -> Result { if self.descriptor.single_segment_flag() { @@ -135,31 +187,68 @@ impl FrameHeader { } } -#[derive(Debug, derive_more::Display, derive_more::From)] -#[cfg_attr(feature = "std", derive(derive_more::Error))] +#[derive(Debug)] #[non_exhaustive] pub enum ReadFrameHeaderError { - #[display(fmt = "Error while reading magic number: {_0}")] MagicNumberReadError(Error), - #[display(fmt = "Read wrong magic number: 0x{_0:X}")] - BadMagicNumber(#[cfg_attr(feature = "std", error(ignore))] u32), - #[display(fmt = "Error while reading frame descriptor: {_0}")] + BadMagicNumber(u32), FrameDescriptorReadError(Error), - #[display(fmt = "{_0:?}")] - #[from] InvalidFrameDescriptor(FrameDescriptorError), - #[display(fmt = "Error while reading window descriptor: {_0}")] WindowDescriptorReadError(Error), - #[display(fmt = "Error while reading dictionary id: {_0}")] DictionaryIdReadError(Error), - #[display(fmt = "Error while reading frame content size: {_0}")] FrameContentSizeReadError(Error), - #[display( - fmt = "SkippableFrame encountered with MagicNumber 0x{magic_number:X} and length {length} bytes" - )] SkipFrame { magic_number: u32, length: u32 }, } +impl fmt::Display for ReadFrameHeaderError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::MagicNumberReadError(e) => write!(f, "Error while reading magic number: {}", e), + Self::BadMagicNumber(e) => write!(f, "Read wrong magic number: 0x{:X}", e), + Self::FrameDescriptorReadError(e) => { + write!(f, "Error while reading frame descriptor: {}", e) + } + Self::InvalidFrameDescriptor(e) => write!(f, "{:?}", e), + Self::WindowDescriptorReadError(e) => { + write!(f, "Error while reading window descriptor: {}", e) + } + Self::DictionaryIdReadError(e) => write!(f, "Error while reading dictionary id: {}", e), + Self::FrameContentSizeReadError(e) => { + write!(f, "Error while reading frame content size: {}", e) + } + Self::SkipFrame { + magic_number, + length, + } => write!( + f, + "SkippableFrame encountered with MagicNumber 0x{:X} and length {} bytes", + magic_number, length + ), + } + } +} + +#[cfg(feature = "std")] +impl StdError for ReadFrameHeaderError { + fn source(&self) -> Option<&(dyn StdError + 'static)> { + match self { + ReadFrameHeaderError::MagicNumberReadError(source) => Some(source), + ReadFrameHeaderError::FrameDescriptorReadError(source) => Some(source), + ReadFrameHeaderError::InvalidFrameDescriptor(source) => Some(source), + ReadFrameHeaderError::WindowDescriptorReadError(source) => Some(source), + ReadFrameHeaderError::DictionaryIdReadError(source) => Some(source), + ReadFrameHeaderError::FrameContentSizeReadError(source) => Some(source), + _ => None, + } + } +} + +impl From for ReadFrameHeaderError { + fn from(error: FrameDescriptorError) -> Self { + Self::InvalidFrameDescriptor(error) + } +} + pub fn read_frame_header(mut r: impl Read) -> Result<(Frame, u8), ReadFrameHeaderError> { use ReadFrameHeaderError as err; let mut buf = [0u8; 4]; diff --git a/src/frame_decoder.rs b/src/frame_decoder.rs index 072ebc8a..a0be962e 100644 --- a/src/frame_decoder.rs +++ b/src/frame_decoder.rs @@ -6,6 +6,8 @@ use crate::io::{Error, Read, Write}; use alloc::collections::BTreeMap; use alloc::vec::Vec; use core::convert::TryInto; +#[cfg(feature = "std")] +use std::error::Error as StdError; /// This implements a decoder for zstd frames. This decoder is able to decode frames only partially and gives control /// over how many bytes/blocks will be decoded at a time (so you don't have to decode a 10GB file into memory all at once). @@ -79,46 +81,115 @@ pub enum BlockDecodingStrategy { UptoBytes(usize), } -#[derive(Debug, derive_more::Display, derive_more::From)] -#[cfg_attr(feature = "std", derive(derive_more::Error))] +#[derive(Debug)] #[non_exhaustive] pub enum FrameDecoderError { - #[display(fmt = "{_0:?}")] - #[from] ReadFrameHeaderError(frame::ReadFrameHeaderError), - #[display(fmt = "{_0:?}")] - #[from] FrameHeaderError(frame::FrameHeaderError), - #[display( - fmt = "Specified window_size is too big; Requested: {requested}, Max: {MAX_WINDOW_SIZE}" - )] WindowSizeTooBig { requested: u64 }, - #[display(fmt = "{_0:?}")] - #[from] DictionaryDecodeError(dictionary::DictionaryDecodeError), - #[display(fmt = "Failed to parse/decode block body: {_0}")] - #[from] FailedToReadBlockHeader(decoding::block_decoder::BlockHeaderReadError), - #[display(fmt = "Failed to parse block header: {_0}")] FailedToReadBlockBody(decoding::block_decoder::DecodeBlockContentError), - #[display(fmt = "Failed to read checksum: {_0}")] FailedToReadChecksum(Error), - #[display(fmt = "Decoder must initialized or reset before using it")] NotYetInitialized, - #[display(fmt = "Decoder encountered error while initializing: {_0}")] FailedToInitialize(frame::FrameHeaderError), - #[display(fmt = "Decoder encountered error while draining the decodebuffer: {_0}")] FailedToDrainDecodebuffer(Error), - #[display( - fmt = "Target must have at least as many bytes as the contentsize of the frame reports" - )] TargetTooSmall, - #[display( - fmt = "Frame header specified dictionary id 0x{dict_id:X} that wasnt provided by add_dict() or reset_with_dict()" - )] DictNotProvided { dict_id: u32 }, } +#[cfg(feature = "std")] +impl StdError for FrameDecoderError { + fn source(&self) -> Option<&(dyn StdError + 'static)> { + match self { + FrameDecoderError::ReadFrameHeaderError(source) => Some(source), + FrameDecoderError::FrameHeaderError(source) => Some(source), + FrameDecoderError::DictionaryDecodeError(source) => Some(source), + FrameDecoderError::FailedToReadBlockHeader(source) => Some(source), + FrameDecoderError::FailedToReadBlockBody(source) => Some(source), + FrameDecoderError::FailedToReadChecksum(source) => Some(source), + FrameDecoderError::FailedToInitialize(source) => Some(source), + FrameDecoderError::FailedToDrainDecodebuffer(source) => Some(source), + _ => None, + } + } +} + +impl core::fmt::Display for FrameDecoderError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> ::core::fmt::Result { + match self { + FrameDecoderError::ReadFrameHeaderError(e) => { + write!(f, "{:?}", e) + } + FrameDecoderError::FrameHeaderError(e) => { + write!(f, "{:?}", e) + } + FrameDecoderError::WindowSizeTooBig { requested } => { + write!( + f, + "Specified window_size is too big; Requested: {}, Max: {}", + requested, MAX_WINDOW_SIZE, + ) + } + FrameDecoderError::DictionaryDecodeError(e) => { + write!(f, "{:?}", e) + } + FrameDecoderError::FailedToReadBlockHeader(e) => { + write!(f, "Failed to parse/decode block body: {}", e) + } + FrameDecoderError::FailedToReadBlockBody(e) => { + write!(f, "Failed to parse block header: {}", e) + } + FrameDecoderError::FailedToReadChecksum(e) => { + write!(f, "Failed to read checksum: {}", e) + } + FrameDecoderError::NotYetInitialized => { + write!(f, "Decoder must initialized or reset before using it",) + } + FrameDecoderError::FailedToInitialize(e) => { + write!(f, "Decoder encountered error while initializing: {}", e) + } + FrameDecoderError::FailedToDrainDecodebuffer(e) => { + write!( + f, + "Decoder encountered error while draining the decodebuffer: {}", + e, + ) + } + FrameDecoderError::TargetTooSmall => { + write!(f, "Target must have at least as many bytes as the contentsize of the frame reports") + } + FrameDecoderError::DictNotProvided { dict_id } => { + write!(f, "Frame header specified dictionary id 0x{:X} that wasnt provided by add_dict() or reset_with_dict()", dict_id) + } + } + } +} + +impl From for FrameDecoderError { + fn from(val: dictionary::DictionaryDecodeError) -> Self { + Self::DictionaryDecodeError(val) + } +} + +impl From for FrameDecoderError { + fn from(val: decoding::block_decoder::BlockHeaderReadError) -> Self { + Self::FailedToReadBlockHeader(val) + } +} + +impl From for FrameDecoderError { + fn from(val: frame::FrameHeaderError) -> Self { + Self::FrameHeaderError(val) + } +} + +impl From for FrameDecoderError { + fn from(val: frame::ReadFrameHeaderError) -> Self { + Self::ReadFrameHeaderError(val) + } +} + const MAX_WINDOW_SIZE: u64 = 1024 * 1024 * 100; impl FrameDecoderState { diff --git a/src/fse/fse_decoder.rs b/src/fse/fse_decoder.rs index 969768f1..eb1de877 100644 --- a/src/fse/fse_decoder.rs +++ b/src/fse/fse_decoder.rs @@ -16,27 +16,74 @@ impl Default for FSETable { } } -#[derive(Debug, derive_more::Display, derive_more::From)] -#[cfg_attr(feature = "std", derive(derive_more::Error))] +#[derive(Debug)] #[non_exhaustive] pub enum FSETableError { - #[display(fmt = "Acclog must be at least 1")] AccLogIsZero, - #[display(fmt = "Found FSE acc_log: {got} bigger than allowed maximum in this case: {max}")] - AccLogTooBig { got: u8, max: u8 }, - #[display(fmt = "{_0:?}")] - #[from] + AccLogTooBig { + got: u8, + max: u8, + }, GetBitsError(GetBitsError), - #[display( - fmt = "The counter ({got}) exceeded the expected sum: {expected_sum}. This means an error or corrupted data \n {symbol_probabilities:?}" - )] ProbabilityCounterMismatch { got: u32, expected_sum: u32, symbol_probabilities: Vec, }, - #[display(fmt = "There are too many symbols in this distribution: {got}. Max: 256")] - TooManySymbols { got: usize }, + TooManySymbols { + got: usize, + }, +} + +#[cfg(feature = "std")] +impl std::error::Error for FSETableError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + FSETableError::GetBitsError(source) => Some(source), + _ => None, + } + } +} + +impl core::fmt::Display for FSETableError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + FSETableError::AccLogIsZero => write!(f, "Acclog must be at least 1"), + FSETableError::AccLogTooBig { got, max } => { + write!( + f, + "Found FSE acc_log: {0} bigger than allowed maximum in this case: {1}", + got, max + ) + } + FSETableError::GetBitsError(e) => write!(f, "{:?}", e), + FSETableError::ProbabilityCounterMismatch { + got, + expected_sum, + symbol_probabilities, + } => { + write!(f, + "The counter ({}) exceeded the expected sum: {}. This means an error or corrupted data \n {:?}", + got, + expected_sum, + symbol_probabilities, + ) + } + FSETableError::TooManySymbols { got } => { + write!( + f, + "There are too many symbols in this distribution: {}. Max: 256", + got, + ) + } + } + } +} + +impl From for FSETableError { + fn from(val: GetBitsError) -> Self { + Self::GetBitsError(val) + } } pub struct FSEDecoder<'table> { @@ -44,17 +91,40 @@ pub struct FSEDecoder<'table> { table: &'table FSETable, } -#[derive(Debug, derive_more::Display, derive_more::From)] -#[cfg_attr(feature = "std", derive(derive_more::Error))] +#[derive(Debug)] #[non_exhaustive] pub enum FSEDecoderError { - #[display(fmt = "{_0:?}")] - #[from] GetBitsError(GetBitsError), - #[display(fmt = "Tried to use an uninitialized table!")] TableIsUninitialized, } +#[cfg(feature = "std")] +impl std::error::Error for FSEDecoderError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + FSEDecoderError::GetBitsError(source) => Some(source), + _ => None, + } + } +} + +impl core::fmt::Display for FSEDecoderError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + FSEDecoderError::GetBitsError(e) => write!(f, "{:?}", e), + FSEDecoderError::TableIsUninitialized => { + write!(f, "Tried to use an uninitialized table!") + } + } + } +} + +impl From for FSEDecoderError { + fn from(val: GetBitsError) -> Self { + Self::GetBitsError(val) + } +} + #[derive(Copy, Clone)] pub struct Entry { pub base_line: u32, diff --git a/src/huff0/huff0_decoder.rs b/src/huff0/huff0_decoder.rs index cc12476a..49f40622 100644 --- a/src/huff0/huff0_decoder.rs +++ b/src/huff0/huff0_decoder.rs @@ -1,6 +1,8 @@ use crate::decoding::bit_reader_reverse::{BitReaderReversed, GetBitsError}; use crate::fse::{FSEDecoder, FSEDecoderError, FSETable, FSETableError}; use alloc::vec::Vec; +#[cfg(feature = "std")] +use std::error::Error as StdError; pub struct HuffmanTable { decode: Vec, @@ -14,56 +16,151 @@ pub struct HuffmanTable { fse_table: FSETable, } -#[derive(Debug, derive_more::Display, derive_more::From)] -#[cfg_attr(feature = "std", derive(derive_more::Error))] +#[derive(Debug)] #[non_exhaustive] pub enum HuffmanTableError { - #[display(fmt = "{_0:?}")] - #[from] GetBitsError(GetBitsError), - #[display(fmt = "{_0:?}")] - #[from] FSEDecoderError(FSEDecoderError), - #[display(fmt = "{_0:?}")] - #[from] FSETableError(FSETableError), - #[display(fmt = "Source needs to have at least one byte")] SourceIsEmpty, - #[display( - fmt = "Header says there should be {expected_bytes} bytes for the weights but there are only {got_bytes} bytes in the stream" - )] NotEnoughBytesForWeights { got_bytes: usize, expected_bytes: u8, }, - #[display( - fmt = "Padding at the end of the sequence_section was more than a byte long: {skipped_bits} bits. Probably caused by data corruption" - )] - ExtraPadding { skipped_bits: i32 }, - #[display( - fmt = "More than 255 weights decoded (got {got} weights). Stream is probably corrupted" - )] - TooManyWeights { got: usize }, - #[display(fmt = "Can't build huffman table without any weights")] + ExtraPadding { + skipped_bits: i32, + }, + TooManyWeights { + got: usize, + }, MissingWeights, - #[display(fmt = "Leftover must be power of two but is: {got}")] - LeftoverIsNotAPowerOf2 { got: u32 }, - #[display( - fmt = "Not enough bytes in stream to decompress weights. Is: {have}, Should be: {need}" - )] - NotEnoughBytesToDecompressWeights { have: usize, need: usize }, - #[display( - fmt = "FSE table used more bytes: {used} than were meant to be used for the whole stream of huffman weights ({available_bytes})" - )] - FSETableUsedTooManyBytes { used: usize, available_bytes: u8 }, - #[display(fmt = "Source needs to have at least {need} bytes, got: {got}")] - NotEnoughBytesInSource { got: usize, need: usize }, - #[display(fmt = "Cant have weight: {got} bigger than max_num_bits: {MAX_MAX_NUM_BITS}")] - WeightBiggerThanMaxNumBits { got: u8 }, - #[display( - fmt = "max_bits derived from weights is: {got} should be lower than: {MAX_MAX_NUM_BITS}" - )] - MaxBitsTooHigh { got: u8 }, + LeftoverIsNotAPowerOf2 { + got: u32, + }, + NotEnoughBytesToDecompressWeights { + have: usize, + need: usize, + }, + FSETableUsedTooManyBytes { + used: usize, + available_bytes: u8, + }, + NotEnoughBytesInSource { + got: usize, + need: usize, + }, + WeightBiggerThanMaxNumBits { + got: u8, + }, + MaxBitsTooHigh { + got: u8, + }, +} + +#[cfg(feature = "std")] +impl StdError for HuffmanTableError { + fn source(&self) -> Option<&(dyn StdError + 'static)> { + match self { + HuffmanTableError::GetBitsError(source) => Some(source), + HuffmanTableError::FSEDecoderError(source) => Some(source), + HuffmanTableError::FSETableError(source) => Some(source), + _ => None, + } + } +} + +impl core::fmt::Display for HuffmanTableError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> ::core::fmt::Result { + match self { + HuffmanTableError::GetBitsError(e) => write!(f, "{:?}", e), + HuffmanTableError::FSEDecoderError(e) => write!(f, "{:?}", e), + HuffmanTableError::FSETableError(e) => write!(f, "{:?}", e), + HuffmanTableError::SourceIsEmpty => write!(f, "Source needs to have at least one byte"), + HuffmanTableError::NotEnoughBytesForWeights { + got_bytes, + expected_bytes, + } => { + write!(f, "Header says there should be {} bytes for the weights but there are only {} bytes in the stream", + expected_bytes, + got_bytes) + } + HuffmanTableError::ExtraPadding { skipped_bits } => { + write!(f, + "Padding at the end of the sequence_section was more than a byte long: {} bits. Probably caused by data corruption", + skipped_bits, + ) + } + HuffmanTableError::TooManyWeights { got } => { + write!( + f, + "More than 255 weights decoded (got {} weights). Stream is probably corrupted", + got, + ) + } + HuffmanTableError::MissingWeights => { + write!(f, "Can\'t build huffman table without any weights") + } + HuffmanTableError::LeftoverIsNotAPowerOf2 { got } => { + write!(f, "Leftover must be power of two but is: {}", got) + } + HuffmanTableError::NotEnoughBytesToDecompressWeights { have, need } => { + write!( + f, + "Not enough bytes in stream to decompress weights. Is: {}, Should be: {}", + have, need, + ) + } + HuffmanTableError::FSETableUsedTooManyBytes { + used, + available_bytes, + } => { + write!(f, + "FSE table used more bytes: {} than were meant to be used for the whole stream of huffman weights ({})", + used, + available_bytes, + ) + } + HuffmanTableError::NotEnoughBytesInSource { got, need } => { + write!( + f, + "Source needs to have at least {} bytes, got: {}", + need, got, + ) + } + HuffmanTableError::WeightBiggerThanMaxNumBits { got } => { + write!( + f, + "Cant have weight: {} bigger than max_num_bits: {}", + got, MAX_MAX_NUM_BITS, + ) + } + HuffmanTableError::MaxBitsTooHigh { got } => { + write!( + f, + "max_bits derived from weights is: {} should be lower than: {}", + got, MAX_MAX_NUM_BITS, + ) + } + } + } +} + +impl From for HuffmanTableError { + fn from(val: GetBitsError) -> Self { + Self::GetBitsError(val) + } +} + +impl From for HuffmanTableError { + fn from(val: FSEDecoderError) -> Self { + Self::FSEDecoderError(val) + } +} + +impl From for HuffmanTableError { + fn from(val: FSETableError) -> Self { + Self::FSETableError(val) + } } pub struct HuffmanDecoder<'table> { @@ -71,15 +168,35 @@ pub struct HuffmanDecoder<'table> { pub state: u64, } -#[derive(Debug, derive_more::Display, derive_more::From)] -#[cfg_attr(feature = "std", derive(derive_more::Error))] +#[derive(Debug)] #[non_exhaustive] pub enum HuffmanDecoderError { - #[display(fmt = "{_0:?}")] - #[from] GetBitsError(GetBitsError), } +impl core::fmt::Display for HuffmanDecoderError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + HuffmanDecoderError::GetBitsError(e) => write!(f, "{:?}", e), + } + } +} + +#[cfg(feature = "std")] +impl StdError for HuffmanDecoderError { + fn source(&self) -> Option<&(dyn StdError + 'static)> { + match self { + HuffmanDecoderError::GetBitsError(source) => Some(source), + } + } +} + +impl From for HuffmanDecoderError { + fn from(val: GetBitsError) -> Self { + Self::GetBitsError(val) + } +} + #[derive(Copy, Clone)] pub struct Entry { symbol: u8,