1use std::error::Error;
17use std::{fmt, io};
18
19use crate::color::ExtendedColorType;
20use crate::image::ImageFormat;
21
22#[derive(Debug)]
27pub enum ImageError {
28 Decoding(DecodingError),
34
35 Encoding(EncodingError),
42
43 Parameter(ParameterError),
48
49 Limits(LimitError),
54
55 Unsupported(UnsupportedError),
62
63 IoError(io::Error),
65}
66
67#[derive(Debug)]
73pub struct UnsupportedError {
74 format: ImageFormatHint,
75 kind: UnsupportedErrorKind,
76}
77
78#[derive(Clone, Debug, Hash, PartialEq)]
80#[non_exhaustive]
81pub enum UnsupportedErrorKind {
82 Color(ExtendedColorType),
84 Format(ImageFormatHint),
86 GenericFeature(String),
89}
90
91#[derive(Debug)]
98pub struct EncodingError {
99 format: ImageFormatHint,
100 underlying: Option<Box<dyn Error + Send + Sync>>,
101}
102
103#[derive(Debug)]
110pub struct ParameterError {
111 kind: ParameterErrorKind,
112 underlying: Option<Box<dyn Error + Send + Sync>>,
113}
114
115#[derive(Clone, Debug, Hash, PartialEq)]
117#[non_exhaustive]
118pub enum ParameterErrorKind {
119 DimensionMismatch,
121 FailedAlready,
123 Generic(String),
126 NoMoreData,
128}
129
130#[derive(Debug)]
137pub struct DecodingError {
138 format: ImageFormatHint,
139 underlying: Option<Box<dyn Error + Send + Sync>>,
140}
141
142#[derive(Debug)]
149pub struct LimitError {
150 kind: LimitErrorKind,
151 }
153
154#[derive(Clone, Debug, Hash, PartialEq, Eq)]
159#[non_exhaustive]
160#[allow(missing_copy_implementations)] pub enum LimitErrorKind {
162 DimensionError,
164 InsufficientMemory,
166 Unsupported {
168 limits: crate::Limits,
170 supported: crate::LimitSupport,
172 },
173}
174
175#[derive(Clone, Debug, Hash, PartialEq)]
177#[non_exhaustive]
178pub enum ImageFormatHint {
179 Exact(ImageFormat),
181
182 Name(String),
184
185 PathExtension(std::path::PathBuf),
187
188 Unknown,
190}
191
192impl UnsupportedError {
193 #[must_use]
198 pub fn from_format_and_kind(format: ImageFormatHint, kind: UnsupportedErrorKind) -> Self {
199 UnsupportedError { format, kind }
200 }
201
202 #[must_use]
204 pub fn kind(&self) -> UnsupportedErrorKind {
205 self.kind.clone()
206 }
207
208 #[must_use]
210 pub fn format_hint(&self) -> ImageFormatHint {
211 self.format.clone()
212 }
213}
214
215impl DecodingError {
216 pub fn new(format: ImageFormatHint, err: impl Into<Box<dyn Error + Send + Sync>>) -> Self {
218 DecodingError {
219 format,
220 underlying: Some(err.into()),
221 }
222 }
223
224 #[must_use]
228 pub fn from_format_hint(format: ImageFormatHint) -> Self {
229 DecodingError {
230 format,
231 underlying: None,
232 }
233 }
234
235 #[must_use]
237 pub fn format_hint(&self) -> ImageFormatHint {
238 self.format.clone()
239 }
240}
241
242impl EncodingError {
243 pub fn new(format: ImageFormatHint, err: impl Into<Box<dyn Error + Send + Sync>>) -> Self {
245 EncodingError {
246 format,
247 underlying: Some(err.into()),
248 }
249 }
250
251 #[must_use]
255 pub fn from_format_hint(format: ImageFormatHint) -> Self {
256 EncodingError {
257 format,
258 underlying: None,
259 }
260 }
261
262 #[must_use]
264 pub fn format_hint(&self) -> ImageFormatHint {
265 self.format.clone()
266 }
267}
268
269impl ParameterError {
270 #[must_use]
272 pub fn from_kind(kind: ParameterErrorKind) -> Self {
273 ParameterError {
274 kind,
275 underlying: None,
276 }
277 }
278
279 #[must_use]
281 pub fn kind(&self) -> ParameterErrorKind {
282 self.kind.clone()
283 }
284}
285
286impl LimitError {
287 #[must_use]
289 pub fn from_kind(kind: LimitErrorKind) -> Self {
290 LimitError { kind }
291 }
292
293 #[must_use]
295 pub fn kind(&self) -> LimitErrorKind {
296 self.kind.clone()
297 }
298}
299
300impl From<io::Error> for ImageError {
301 fn from(err: io::Error) -> ImageError {
302 ImageError::IoError(err)
303 }
304}
305
306impl From<ImageFormat> for ImageFormatHint {
307 fn from(format: ImageFormat) -> Self {
308 ImageFormatHint::Exact(format)
309 }
310}
311
312impl From<&'_ std::path::Path> for ImageFormatHint {
313 fn from(path: &'_ std::path::Path) -> Self {
314 match path.extension() {
315 Some(ext) => ImageFormatHint::PathExtension(ext.into()),
316 None => ImageFormatHint::Unknown,
317 }
318 }
319}
320
321impl From<ImageFormatHint> for UnsupportedError {
322 fn from(hint: ImageFormatHint) -> Self {
323 UnsupportedError {
324 format: hint.clone(),
325 kind: UnsupportedErrorKind::Format(hint),
326 }
327 }
328}
329
330pub type ImageResult<T> = Result<T, ImageError>;
332
333impl fmt::Display for ImageError {
334 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
335 match self {
336 ImageError::IoError(err) => err.fmt(fmt),
337 ImageError::Decoding(err) => err.fmt(fmt),
338 ImageError::Encoding(err) => err.fmt(fmt),
339 ImageError::Parameter(err) => err.fmt(fmt),
340 ImageError::Limits(err) => err.fmt(fmt),
341 ImageError::Unsupported(err) => err.fmt(fmt),
342 }
343 }
344}
345
346impl Error for ImageError {
347 fn source(&self) -> Option<&(dyn Error + 'static)> {
348 match self {
349 ImageError::IoError(err) => err.source(),
350 ImageError::Decoding(err) => err.source(),
351 ImageError::Encoding(err) => err.source(),
352 ImageError::Parameter(err) => err.source(),
353 ImageError::Limits(err) => err.source(),
354 ImageError::Unsupported(err) => err.source(),
355 }
356 }
357}
358
359impl fmt::Display for UnsupportedError {
360 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
361 match &self.kind {
362 UnsupportedErrorKind::Format(ImageFormatHint::Unknown) => {
363 write!(fmt, "The image format could not be determined",)
364 }
365 UnsupportedErrorKind::Format(format @ ImageFormatHint::PathExtension(_)) => write!(
366 fmt,
367 "The file extension {format} was not recognized as an image format",
368 ),
369 UnsupportedErrorKind::Format(format) => {
370 write!(fmt, "The image format {format} is not supported",)
371 }
372 UnsupportedErrorKind::Color(color) => write!(
373 fmt,
374 "The encoder or decoder for {} does not support the color type `{:?}`",
375 self.format, color,
376 ),
377 UnsupportedErrorKind::GenericFeature(message) => match &self.format {
378 ImageFormatHint::Unknown => write!(
379 fmt,
380 "The decoder does not support the format feature {message}",
381 ),
382 other => write!(
383 fmt,
384 "The decoder for {other} does not support the format features {message}",
385 ),
386 },
387 }
388 }
389}
390
391impl Error for UnsupportedError {}
392
393impl fmt::Display for ParameterError {
394 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
395 match &self.kind {
396 ParameterErrorKind::DimensionMismatch => write!(
397 fmt,
398 "The Image's dimensions are either too \
399 small or too large"
400 ),
401 ParameterErrorKind::FailedAlready => write!(
402 fmt,
403 "The end the image stream has been reached due to a previous error"
404 ),
405 ParameterErrorKind::Generic(message) => {
406 write!(fmt, "The parameter is malformed: {message}",)
407 }
408 ParameterErrorKind::NoMoreData => write!(fmt, "The end of the image has been reached",),
409 }?;
410
411 if let Some(underlying) = &self.underlying {
412 write!(fmt, "\n{underlying}")?;
413 }
414
415 Ok(())
416 }
417}
418
419impl Error for ParameterError {
420 fn source(&self) -> Option<&(dyn Error + 'static)> {
421 match &self.underlying {
422 None => None,
423 Some(source) => Some(&**source),
424 }
425 }
426}
427
428impl fmt::Display for EncodingError {
429 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
430 match &self.underlying {
431 Some(underlying) => write!(
432 fmt,
433 "Format error encoding {}:\n{}",
434 self.format, underlying,
435 ),
436 None => write!(fmt, "Format error encoding {}", self.format,),
437 }
438 }
439}
440
441impl Error for EncodingError {
442 fn source(&self) -> Option<&(dyn Error + 'static)> {
443 match &self.underlying {
444 None => None,
445 Some(source) => Some(&**source),
446 }
447 }
448}
449
450impl fmt::Display for DecodingError {
451 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
452 match &self.underlying {
453 None => match self.format {
454 ImageFormatHint::Unknown => write!(fmt, "Format error"),
455 _ => write!(fmt, "Format error decoding {}", self.format),
456 },
457 Some(underlying) => {
458 write!(fmt, "Format error decoding {}: {}", self.format, underlying)
459 }
460 }
461 }
462}
463
464impl Error for DecodingError {
465 fn source(&self) -> Option<&(dyn Error + 'static)> {
466 match &self.underlying {
467 None => None,
468 Some(source) => Some(&**source),
469 }
470 }
471}
472
473impl fmt::Display for LimitError {
474 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
475 match self.kind {
476 LimitErrorKind::InsufficientMemory => write!(fmt, "Memory limit exceeded"),
477 LimitErrorKind::DimensionError => write!(fmt, "Image size exceeds limit"),
478 LimitErrorKind::Unsupported { .. } => {
479 write!(fmt, "The following strict limits are specified but not supported by the opertation: ")?;
480 Ok(())
481 }
482 }
483 }
484}
485
486impl Error for LimitError {}
487
488impl fmt::Display for ImageFormatHint {
489 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
490 match self {
491 ImageFormatHint::Exact(format) => write!(fmt, "{format:?}"),
492 ImageFormatHint::Name(name) => write!(fmt, "`{name}`"),
493 ImageFormatHint::PathExtension(ext) => write!(fmt, "`.{ext:?}`"),
494 ImageFormatHint::Unknown => write!(fmt, "`Unknown`"),
495 }
496 }
497}
498
499#[cfg(test)]
500mod tests {
501 use super::*;
502 use std::mem::size_of;
503
504 #[allow(dead_code)]
505 const ASSERT_SMALLISH: usize = [0][(size_of::<ImageError>() >= 200) as usize];
507
508 #[test]
509 fn test_send_sync_stability() {
510 fn assert_send_sync<T: Send + Sync>() {}
511
512 assert_send_sync::<ImageError>();
513 }
514}