jpegli/
error.rs

1//! Error types for jpegli.
2
3use std::fmt;
4
5/// Result type for jpegli operations.
6pub type Result<T> = std::result::Result<T, Error>;
7
8/// Errors that can occur during JPEG encoding/decoding.
9#[derive(Debug, Clone, PartialEq)]
10#[non_exhaustive]
11pub enum Error {
12    /// Invalid input dimensions (zero or too large).
13    InvalidDimensions {
14        /// Width provided
15        width: u32,
16        /// Height provided
17        height: u32,
18        /// Reason for invalidity
19        reason: &'static str,
20    },
21    /// Invalid quality parameter.
22    InvalidQuality {
23        /// Value provided
24        value: f32,
25        /// Valid range description
26        valid_range: &'static str,
27    },
28    /// Invalid color space or pixel format combination.
29    InvalidColorFormat {
30        /// Description of the issue
31        reason: &'static str,
32    },
33    /// Input buffer has wrong size.
34    InvalidBufferSize {
35        /// Expected size in bytes
36        expected: usize,
37        /// Actual size in bytes
38        actual: usize,
39    },
40    /// Invalid JPEG data (corrupted or not a JPEG).
41    InvalidJpegData {
42        /// Description of the issue
43        reason: &'static str,
44    },
45    /// Unexpected end of input data.
46    UnexpectedEof {
47        /// Context where EOF occurred
48        context: &'static str,
49    },
50    /// Invalid marker or segment in JPEG stream.
51    InvalidMarker {
52        /// The marker byte encountered
53        marker: u8,
54        /// Context
55        context: &'static str,
56    },
57    /// Invalid Huffman table.
58    InvalidHuffmanTable {
59        /// Table index
60        table_idx: u8,
61        /// Description of the issue
62        reason: &'static str,
63    },
64    /// Invalid quantization table.
65    InvalidQuantTable {
66        /// Table index
67        table_idx: u8,
68        /// Description of the issue
69        reason: &'static str,
70    },
71    /// Unsupported JPEG feature.
72    UnsupportedFeature {
73        /// Description of unsupported feature
74        feature: &'static str,
75    },
76    /// Internal error (should not happen in correct usage).
77    InternalError {
78        /// Description
79        reason: &'static str,
80    },
81    /// I/O error during encoding/decoding.
82    IoError {
83        /// Description
84        reason: String,
85    },
86    /// ICC color management error.
87    IccError(String),
88    /// Decode error from JPEG decoder.
89    DecodeError(String),
90    /// Invalid scan script for progressive encoding.
91    InvalidScanScript(String),
92    /// Memory allocation failed (OOM or limit exceeded).
93    AllocationFailed {
94        /// Number of bytes requested
95        bytes: usize,
96        /// Context where allocation failed
97        context: &'static str,
98    },
99    /// Size calculation overflowed.
100    SizeOverflow {
101        /// Context where overflow occurred
102        context: &'static str,
103    },
104    /// Image exceeds maximum pixel limit.
105    ImageTooLarge {
106        /// Total pixels in image
107        pixels: u64,
108        /// Maximum allowed pixels
109        limit: u64,
110    },
111    /// Too many progressive scans.
112    TooManyScans {
113        /// Number of scans encountered
114        count: usize,
115        /// Maximum allowed
116        limit: usize,
117    },
118}
119
120impl fmt::Display for Error {
121    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
122        match self {
123            Self::InvalidDimensions {
124                width,
125                height,
126                reason,
127            } => {
128                write!(f, "invalid dimensions {}x{}: {}", width, height, reason)
129            }
130            Self::InvalidQuality { value, valid_range } => {
131                write!(f, "invalid quality {}: must be in {}", value, valid_range)
132            }
133            Self::InvalidColorFormat { reason } => {
134                write!(f, "invalid color format: {}", reason)
135            }
136            Self::InvalidBufferSize { expected, actual } => {
137                write!(
138                    f,
139                    "invalid buffer size: expected {} bytes, got {}",
140                    expected, actual
141                )
142            }
143            Self::InvalidJpegData { reason } => {
144                write!(f, "invalid JPEG data: {}", reason)
145            }
146            Self::UnexpectedEof { context } => {
147                write!(f, "unexpected end of data while {}", context)
148            }
149            Self::InvalidMarker { marker, context } => {
150                write!(f, "invalid marker 0x{:02X} while {}", marker, context)
151            }
152            Self::InvalidHuffmanTable { table_idx, reason } => {
153                write!(f, "invalid Huffman table {}: {}", table_idx, reason)
154            }
155            Self::InvalidQuantTable { table_idx, reason } => {
156                write!(f, "invalid quantization table {}: {}", table_idx, reason)
157            }
158            Self::UnsupportedFeature { feature } => {
159                write!(f, "unsupported feature: {}", feature)
160            }
161            Self::InternalError { reason } => {
162                write!(f, "internal error: {}", reason)
163            }
164            Self::IoError { reason } => {
165                write!(f, "I/O error: {}", reason)
166            }
167            Self::IccError(reason) => {
168                write!(f, "ICC error: {}", reason)
169            }
170            Self::DecodeError(reason) => {
171                write!(f, "decode error: {}", reason)
172            }
173            Self::InvalidScanScript(reason) => {
174                write!(f, "invalid scan script: {}", reason)
175            }
176            Self::AllocationFailed { bytes, context } => {
177                write!(f, "allocation of {} bytes failed while {}", bytes, context)
178            }
179            Self::SizeOverflow { context } => {
180                write!(f, "size calculation overflow while {}", context)
181            }
182            Self::ImageTooLarge { pixels, limit } => {
183                write!(
184                    f,
185                    "image too large: {} pixels exceeds limit of {}",
186                    pixels, limit
187                )
188            }
189            Self::TooManyScans { count, limit } => {
190                write!(f, "too many scans: {} exceeds limit of {}", count, limit)
191            }
192        }
193    }
194}
195
196impl std::error::Error for Error {}
197
198impl From<std::io::Error> for Error {
199    fn from(err: std::io::Error) -> Self {
200        Self::IoError {
201            reason: err.to_string(),
202        }
203    }
204}
205
206#[cfg(test)]
207mod tests {
208    use super::*;
209
210    #[test]
211    fn test_error_display() {
212        let err = Error::InvalidDimensions {
213            width: 0,
214            height: 100,
215            reason: "width cannot be zero",
216        };
217        assert!(err.to_string().contains("width cannot be zero"));
218    }
219
220    #[test]
221    fn test_io_error_conversion() {
222        let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "file not found");
223        let err: Error = io_err.into();
224        assert!(matches!(err, Error::IoError { .. }));
225    }
226}