Coverage Report

Created: 2025-12-20 06:48

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/image/src/error.rs
Line
Count
Source
1
//! Contains detailed error representation.
2
//!
3
//! See the main [`ImageError`] which contains a variant for each specialized error type. The
4
//! subtypes used in each variant are opaque by design. They can be roughly inspected through their
5
//! respective `kind` methods which work similar to `std::io::Error::kind`.
6
//!
7
//! The error interface makes it possible to inspect the error of an underlying decoder or encoder,
8
//! through the `Error::source` method. Note that this is not part of the stable interface and you
9
//! may not rely on a particular error value for a particular operation. This means mainly that
10
//! `image` does not promise to remain on a particular version of its underlying decoders but if
11
//! you ensure to use the same version of the dependency (or at least of the error type) through
12
//! external means then you could inspect the error type in slightly more detail.
13
//!
14
//! [`ImageError`]: enum.ImageError.html
15
16
use std::collections::TryReserveError;
17
use std::error::Error;
18
use std::{fmt, io};
19
20
use crate::color::ExtendedColorType;
21
use crate::{metadata::Cicp, ImageFormat};
22
23
/// The generic error type for image operations.
24
///
25
/// This high level enum allows, by variant matching, a rough separation of concerns between
26
/// underlying IO, the caller, format specifications, and the `image` implementation.
27
#[derive(Debug)]
28
pub enum ImageError {
29
    /// An error was encountered while decoding.
30
    ///
31
    /// This means that the input data did not conform to the specification of some image format,
32
    /// or that no format could be determined, or that it did not match format specific
33
    /// requirements set by the caller.
34
    Decoding(DecodingError),
35
36
    /// An error was encountered while encoding.
37
    ///
38
    /// The input image can not be encoded with the chosen format, for example because the
39
    /// specification has no representation for its color space or because a necessary conversion
40
    /// is ambiguous. In some cases it might also happen that the dimensions can not be used with
41
    /// the format.
42
    Encoding(EncodingError),
43
44
    /// An error was encountered in input arguments.
45
    ///
46
    /// This is a catch-all case for strictly internal operations such as scaling, conversions,
47
    /// etc. that involve no external format specifications.
48
    Parameter(ParameterError),
49
50
    /// Completing the operation would have required more resources than allowed.
51
    ///
52
    /// Errors of this type are limits set by the user or environment, *not* inherent in a specific
53
    /// format or operation that was executed.
54
    Limits(LimitError),
55
56
    /// An operation can not be completed by the chosen abstraction.
57
    ///
58
    /// This means that it might be possible for the operation to succeed in general but
59
    /// * it requires a disabled feature,
60
    /// * the implementation does not yet exist, or
61
    /// * no abstraction for a lower level could be found.
62
    Unsupported(UnsupportedError),
63
64
    /// An error occurred while interacting with the environment.
65
    IoError(io::Error),
66
}
67
68
/// The implementation for an operation was not provided.
69
///
70
/// See the variant [`Unsupported`] for more documentation.
71
///
72
/// [`Unsupported`]: enum.ImageError.html#variant.Unsupported
73
#[derive(Debug)]
74
pub struct UnsupportedError {
75
    format: ImageFormatHint,
76
    kind: UnsupportedErrorKind,
77
}
78
79
/// Details what feature is not supported.
80
#[derive(Clone, Debug, Hash, PartialEq)]
81
#[non_exhaustive]
82
pub enum UnsupportedErrorKind {
83
    /// The required color type can not be handled.
84
    Color(ExtendedColorType),
85
    /// Dealing with an intricate layout is not implemented for an algorithm.
86
    ColorLayout(ExtendedColorType),
87
    /// The colors or transfer function of the CICP are not supported.
88
    ColorspaceCicp(Cicp),
89
    /// An image format is not supported.
90
    Format(ImageFormatHint),
91
    /// Some feature specified by string.
92
    /// This is discouraged and is likely to get deprecated (but not removed).
93
    GenericFeature(String),
94
}
95
96
/// An error was encountered while encoding an image.
97
///
98
/// This is used as an opaque representation for the [`ImageError::Encoding`] variant. See its
99
/// documentation for more information.
100
///
101
/// [`ImageError::Encoding`]: enum.ImageError.html#variant.Encoding
102
#[derive(Debug)]
103
pub struct EncodingError {
104
    format: ImageFormatHint,
105
    underlying: Option<Box<dyn Error + Send + Sync>>,
106
}
107
108
/// An error was encountered in inputs arguments.
109
///
110
/// This is used as an opaque representation for the [`ImageError::Parameter`] variant. See its
111
/// documentation for more information.
112
///
113
/// [`ImageError::Parameter`]: enum.ImageError.html#variant.Parameter
114
#[derive(Debug)]
115
pub struct ParameterError {
116
    kind: ParameterErrorKind,
117
    underlying: Option<Box<dyn Error + Send + Sync>>,
118
}
119
120
/// Details how a parameter is malformed.
121
#[derive(Clone, Debug, Hash, PartialEq)]
122
#[non_exhaustive]
123
pub enum ParameterErrorKind {
124
    /// The dimensions passed are wrong.
125
    DimensionMismatch,
126
    /// Repeated an operation for which error that could not be cloned was emitted already.
127
    FailedAlready,
128
    /// The cicp is required to be RGB-like but had other matrix transforms or narrow range.
129
    RgbCicpRequired(Cicp),
130
    /// A string describing the parameter.
131
    /// This is discouraged and is likely to get deprecated (but not removed).
132
    Generic(String),
133
    /// The end of the image has been reached.
134
    NoMoreData,
135
    /// An operation expected a concrete color space but another was found.
136
    CicpMismatch {
137
        /// The cicp that was expected.
138
        expected: Cicp,
139
        /// The cicp that was found.
140
        found: Cicp,
141
    },
142
}
143
144
/// An error was encountered while decoding an image.
145
///
146
/// This is used as an opaque representation for the [`ImageError::Decoding`] variant. See its
147
/// documentation for more information.
148
///
149
/// [`ImageError::Decoding`]: enum.ImageError.html#variant.Decoding
150
#[derive(Debug)]
151
pub struct DecodingError {
152
    format: ImageFormatHint,
153
    underlying: Option<Box<dyn Error + Send + Sync>>,
154
}
155
156
/// Completing the operation would have required more resources than allowed.
157
///
158
/// This is used as an opaque representation for the [`ImageError::Limits`] variant. See its
159
/// documentation for more information.
160
///
161
/// [`ImageError::Limits`]: enum.ImageError.html#variant.Limits
162
#[derive(Debug)]
163
pub struct LimitError {
164
    kind: LimitErrorKind,
165
    // do we need an underlying error?
166
}
167
168
/// Indicates the limit that prevented an operation from completing.
169
///
170
/// Note that this enumeration is not exhaustive and may in the future be extended to provide more
171
/// detailed information or to incorporate other resources types.
172
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
173
#[non_exhaustive]
174
#[allow(missing_copy_implementations)] // Might be non-Copy in the future.
175
pub enum LimitErrorKind {
176
    /// The resulting image exceed dimension limits in either direction.
177
    DimensionError,
178
    /// The operation would have performed an allocation larger than allowed.
179
    InsufficientMemory,
180
    /// The specified strict limits are not supported for this operation
181
    Unsupported {
182
        /// The given limits
183
        limits: crate::Limits,
184
        /// The supported strict limits
185
        supported: crate::LimitSupport,
186
    },
187
}
188
189
/// A best effort representation for image formats.
190
#[derive(Clone, Debug, Hash, PartialEq)]
191
#[non_exhaustive]
192
pub enum ImageFormatHint {
193
    /// The format is known exactly.
194
    Exact(ImageFormat),
195
196
    /// The format can be identified by a name.
197
    Name(String),
198
199
    /// A common path extension for the format is known.
200
    PathExtension(std::path::PathBuf),
201
202
    /// The format is not known or could not be determined.
203
    Unknown,
204
}
205
206
impl UnsupportedError {
207
    /// Create an `UnsupportedError` for an image with details on the unsupported feature.
208
    ///
209
    /// If the operation was not connected to a particular image format then the hint may be
210
    /// `Unknown`.
211
    #[must_use]
212
987
    pub fn from_format_and_kind(format: ImageFormatHint, kind: UnsupportedErrorKind) -> Self {
213
987
        UnsupportedError { format, kind }
214
987
    }
215
216
    /// Returns the corresponding `UnsupportedErrorKind` of the error.
217
    #[must_use]
218
0
    pub fn kind(&self) -> UnsupportedErrorKind {
219
0
        self.kind.clone()
220
0
    }
221
222
    /// Returns the image format associated with this error.
223
    #[must_use]
224
0
    pub fn format_hint(&self) -> ImageFormatHint {
225
0
        self.format.clone()
226
0
    }
227
}
228
229
impl DecodingError {
230
    /// Create a `DecodingError` that stems from an arbitrary error of an underlying decoder.
231
37.2k
    pub fn new(format: ImageFormatHint, err: impl Into<Box<dyn Error + Send + Sync>>) -> Self {
232
37.2k
        DecodingError {
233
37.2k
            format,
234
37.2k
            underlying: Some(err.into()),
235
37.2k
        }
236
37.2k
    }
<image::error::DecodingError>::new::<qoi::error::Error>
Line
Count
Source
231
25
    pub fn new(format: ImageFormatHint, err: impl Into<Box<dyn Error + Send + Sync>>) -> Self {
232
25
        DecodingError {
233
25
            format,
234
25
            underlying: Some(err.into()),
235
25
        }
236
25
    }
<image::error::DecodingError>::new::<image_webp::decoder::DecodingError>
Line
Count
Source
231
1.89k
    pub fn new(format: ImageFormatHint, err: impl Into<Box<dyn Error + Send + Sync>>) -> Self {
232
1.89k
        DecodingError {
233
1.89k
            format,
234
1.89k
            underlying: Some(err.into()),
235
1.89k
        }
236
1.89k
    }
<image::error::DecodingError>::new::<tiff::error::TiffError>
Line
Count
Source
231
5.61k
    pub fn new(format: ImageFormatHint, err: impl Into<Box<dyn Error + Send + Sync>>) -> Self {
232
5.61k
        DecodingError {
233
5.61k
            format,
234
5.61k
            underlying: Some(err.into()),
235
5.61k
        }
236
5.61k
    }
<image::error::DecodingError>::new::<alloc::string::FromUtf8Error>
Line
Count
Source
231
30
    pub fn new(format: ImageFormatHint, err: impl Into<Box<dyn Error + Send + Sync>>) -> Self {
232
30
        DecodingError {
233
30
            format,
234
30
            underlying: Some(err.into()),
235
30
        }
236
30
    }
<image::error::DecodingError>::new::<alloc::string::String>
Line
Count
Source
231
5.95k
    pub fn new(format: ImageFormatHint, err: impl Into<Box<dyn Error + Send + Sync>>) -> Self {
232
5.95k
        DecodingError {
233
5.95k
            format,
234
5.95k
            underlying: Some(err.into()),
235
5.95k
        }
236
5.95k
    }
<image::error::DecodingError>::new::<zune_jpeg::errors::DecodeErrors>
Line
Count
Source
231
5.13k
    pub fn new(format: ImageFormatHint, err: impl Into<Box<dyn Error + Send + Sync>>) -> Self {
232
5.13k
        DecodingError {
233
5.13k
            format,
234
5.13k
            underlying: Some(err.into()),
235
5.13k
        }
236
5.13k
    }
<image::error::DecodingError>::new::<image::codecs::dds::DecoderError>
Line
Count
Source
231
18
    pub fn new(format: ImageFormatHint, err: impl Into<Box<dyn Error + Send + Sync>>) -> Self {
232
18
        DecodingError {
233
18
            format,
234
18
            underlying: Some(err.into()),
235
18
        }
236
18
    }
<image::error::DecodingError>::new::<png::decoder::stream::DecodingError>
Line
Count
Source
231
3.16k
    pub fn new(format: ImageFormatHint, err: impl Into<Box<dyn Error + Send + Sync>>) -> Self {
232
3.16k
        DecodingError {
233
3.16k
            format,
234
3.16k
            underlying: Some(err.into()),
235
3.16k
        }
236
3.16k
    }
<image::error::DecodingError>::new::<gif::reader::decoder::DecodingError>
Line
Count
Source
231
3.04k
    pub fn new(format: ImageFormatHint, err: impl Into<Box<dyn Error + Send + Sync>>) -> Self {
232
3.04k
        DecodingError {
233
3.04k
            format,
234
3.04k
            underlying: Some(err.into()),
235
3.04k
        }
236
3.04k
    }
Unexecuted instantiation: <image::error::DecodingError>::new::<std::io::error::Error>
<image::error::DecodingError>::new::<image::codecs::bmp::decoder::DecoderError>
Line
Count
Source
231
968
    pub fn new(format: ImageFormatHint, err: impl Into<Box<dyn Error + Send + Sync>>) -> Self {
232
968
        DecodingError {
233
968
            format,
234
968
            underlying: Some(err.into()),
235
968
        }
236
968
    }
<image::error::DecodingError>::new::<image::codecs::hdr::decoder::DecoderError>
Line
Count
Source
231
1.86k
    pub fn new(format: ImageFormatHint, err: impl Into<Box<dyn Error + Send + Sync>>) -> Self {
232
1.86k
        DecodingError {
233
1.86k
            format,
234
1.86k
            underlying: Some(err.into()),
235
1.86k
        }
236
1.86k
    }
<image::error::DecodingError>::new::<image::codecs::ico::decoder::DecoderError>
Line
Count
Source
231
7.15k
    pub fn new(format: ImageFormatHint, err: impl Into<Box<dyn Error + Send + Sync>>) -> Self {
232
7.15k
        DecodingError {
233
7.15k
            format,
234
7.15k
            underlying: Some(err.into()),
235
7.15k
        }
236
7.15k
    }
<image::error::DecodingError>::new::<image::codecs::pnm::decoder::DecoderError>
Line
Count
Source
231
2.09k
    pub fn new(format: ImageFormatHint, err: impl Into<Box<dyn Error + Send + Sync>>) -> Self {
232
2.09k
        DecodingError {
233
2.09k
            format,
234
2.09k
            underlying: Some(err.into()),
235
2.09k
        }
236
2.09k
    }
Unexecuted instantiation: <image::error::DecodingError>::new::<<image::error::ImageError as core::convert::From<image::images::flat::Error>>::from::NormalFormRequiredError>
<image::error::DecodingError>::new::<&str>
Line
Count
Source
231
312
    pub fn new(format: ImageFormatHint, err: impl Into<Box<dyn Error + Send + Sync>>) -> Self {
232
312
        DecodingError {
233
312
            format,
234
312
            underlying: Some(err.into()),
235
312
        }
236
312
    }
237
238
    /// Create a `DecodingError` for an image format.
239
    ///
240
    /// The error will not contain any further information but is very easy to create.
241
    #[must_use]
242
0
    pub fn from_format_hint(format: ImageFormatHint) -> Self {
243
0
        DecodingError {
244
0
            format,
245
0
            underlying: None,
246
0
        }
247
0
    }
248
249
    /// Returns the image format associated with this error.
250
    #[must_use]
251
0
    pub fn format_hint(&self) -> ImageFormatHint {
252
0
        self.format.clone()
253
0
    }
254
}
255
256
impl EncodingError {
257
    /// Create an `EncodingError` that stems from an arbitrary error of an underlying encoder.
258
0
    pub fn new(format: ImageFormatHint, err: impl Into<Box<dyn Error + Send + Sync>>) -> Self {
259
0
        EncodingError {
260
0
            format,
261
0
            underlying: Some(err.into()),
262
0
        }
263
0
    }
Unexecuted instantiation: <image::error::EncodingError>::new::<qoi::error::Error>
Unexecuted instantiation: <image::error::EncodingError>::new::<image_webp::encoder::EncodingError>
Unexecuted instantiation: <image::error::EncodingError>::new::<tiff::error::TiffError>
Unexecuted instantiation: <image::error::EncodingError>::new::<gif::encoder::EncodingError>
Unexecuted instantiation: <image::error::EncodingError>::new::<image::codecs::tga::encoder::EncoderError>
Unexecuted instantiation: <image::error::EncodingError>::new::<image::codecs::jpeg::encoder::EncoderError>
Unexecuted instantiation: <image::error::EncodingError>::new::<&str>
Unexecuted instantiation: <image::error::EncodingError>::new::<ravif::error::Error>
Unexecuted instantiation: <image::error::EncodingError>::new::<jpeg_encoder::error::EncodingError>
264
265
    /// Create an `EncodingError` for an image format.
266
    ///
267
    /// The error will not contain any further information but is very easy to create.
268
    #[must_use]
269
0
    pub fn from_format_hint(format: ImageFormatHint) -> Self {
270
0
        EncodingError {
271
0
            format,
272
0
            underlying: None,
273
0
        }
274
0
    }
275
276
    /// Return the image format associated with this error.
277
    #[must_use]
278
0
    pub fn format_hint(&self) -> ImageFormatHint {
279
0
        self.format.clone()
280
0
    }
281
}
282
283
impl ParameterError {
284
    /// Construct a `ParameterError` directly from a corresponding kind.
285
    #[must_use]
286
6
    pub fn from_kind(kind: ParameterErrorKind) -> Self {
287
6
        ParameterError {
288
6
            kind,
289
6
            underlying: None,
290
6
        }
291
6
    }
292
293
    /// Returns the corresponding `ParameterErrorKind` of the error.
294
    #[must_use]
295
0
    pub fn kind(&self) -> ParameterErrorKind {
296
0
        self.kind.clone()
297
0
    }
298
}
299
300
impl LimitError {
301
    /// Construct a generic `LimitError` directly from a corresponding kind.
302
    #[must_use]
303
2.35k
    pub fn from_kind(kind: LimitErrorKind) -> Self {
304
2.35k
        LimitError { kind }
305
2.35k
    }
306
307
    /// Returns the corresponding `LimitErrorKind` of the error.
308
    #[must_use]
309
0
    pub fn kind(&self) -> LimitErrorKind {
310
0
        self.kind.clone()
311
0
    }
312
}
313
314
impl From<LimitErrorKind> for LimitError {
315
0
    fn from(kind: LimitErrorKind) -> Self {
316
0
        Self { kind }
317
0
    }
318
}
319
320
impl From<io::Error> for ImageError {
321
5.26k
    fn from(err: io::Error) -> ImageError {
322
5.26k
        ImageError::IoError(err)
323
5.26k
    }
324
}
325
326
impl From<TryReserveError> for ImageError {
327
0
    fn from(_: TryReserveError) -> ImageError {
328
0
        ImageError::Limits(LimitErrorKind::InsufficientMemory.into())
329
0
    }
330
}
331
332
impl From<ImageFormat> for ImageFormatHint {
333
32.2k
    fn from(format: ImageFormat) -> Self {
334
32.2k
        ImageFormatHint::Exact(format)
335
32.2k
    }
336
}
337
338
impl From<&'_ std::path::Path> for ImageFormatHint {
339
0
    fn from(path: &'_ std::path::Path) -> Self {
340
0
        match path.extension() {
341
0
            Some(ext) => ImageFormatHint::PathExtension(ext.into()),
342
0
            None => ImageFormatHint::Unknown,
343
        }
344
0
    }
345
}
346
347
impl From<ImageFormatHint> for UnsupportedError {
348
0
    fn from(hint: ImageFormatHint) -> Self {
349
0
        UnsupportedError {
350
0
            format: hint.clone(),
351
0
            kind: UnsupportedErrorKind::Format(hint),
352
0
        }
353
0
    }
354
}
355
356
/// Result of an image decoding/encoding process
357
pub type ImageResult<T> = Result<T, ImageError>;
358
359
impl fmt::Display for ImageError {
360
0
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
361
0
        match self {
362
0
            ImageError::IoError(err) => err.fmt(fmt),
363
0
            ImageError::Decoding(err) => err.fmt(fmt),
364
0
            ImageError::Encoding(err) => err.fmt(fmt),
365
0
            ImageError::Parameter(err) => err.fmt(fmt),
366
0
            ImageError::Limits(err) => err.fmt(fmt),
367
0
            ImageError::Unsupported(err) => err.fmt(fmt),
368
        }
369
0
    }
370
}
371
372
impl Error for ImageError {
373
0
    fn source(&self) -> Option<&(dyn Error + 'static)> {
374
0
        match self {
375
0
            ImageError::IoError(err) => err.source(),
376
0
            ImageError::Decoding(err) => err.source(),
377
0
            ImageError::Encoding(err) => err.source(),
378
0
            ImageError::Parameter(err) => err.source(),
379
0
            ImageError::Limits(err) => err.source(),
380
0
            ImageError::Unsupported(err) => err.source(),
381
        }
382
0
    }
383
}
384
385
impl fmt::Display for UnsupportedError {
386
0
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
387
0
        match &self.kind {
388
            UnsupportedErrorKind::Format(ImageFormatHint::Unknown) => {
389
0
                write!(fmt, "The image format could not be determined",)
390
            }
391
0
            UnsupportedErrorKind::Format(format @ ImageFormatHint::PathExtension(_)) => write!(
392
0
                fmt,
393
0
                "The file extension {format} was not recognized as an image format",
394
            ),
395
0
            UnsupportedErrorKind::Format(format) => {
396
0
                write!(fmt, "The image format {format} is not supported",)
397
            }
398
0
            UnsupportedErrorKind::Color(color) => write!(
399
0
                fmt,
400
0
                "The encoder or decoder for {} does not support the color type `{:?}`",
401
                self.format, color,
402
            ),
403
0
            UnsupportedErrorKind::ColorLayout(layout) => write!(
404
0
                fmt,
405
0
                "Converting with the texel memory layout {layout:?} is not supported",
406
            ),
407
0
            UnsupportedErrorKind::ColorspaceCicp(color) => write!(
408
0
                fmt,
409
0
                "The colorimetric interpretation of a CICP color space is not supported for `{color:?}`",
410
            ),
411
0
            UnsupportedErrorKind::GenericFeature(message) => match &self.format {
412
0
                ImageFormatHint::Unknown => write!(
413
0
                    fmt,
414
0
                    "The decoder does not support the format feature {message}",
415
                ),
416
0
                other => write!(
417
0
                    fmt,
418
0
                    "The decoder for {other} does not support the format features {message}",
419
                ),
420
            },
421
        }
422
0
    }
423
}
424
425
impl Error for UnsupportedError {}
426
427
impl fmt::Display for ParameterError {
428
0
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
429
0
        match &self.kind {
430
0
            ParameterErrorKind::DimensionMismatch => write!(
431
0
                fmt,
432
0
                "The Image's dimensions are either too \
433
0
                 small or too large"
434
            ),
435
0
            ParameterErrorKind::FailedAlready => write!(
436
0
                fmt,
437
0
                "The end the image stream has been reached due to a previous error"
438
            ),
439
0
            ParameterErrorKind::RgbCicpRequired(cicp) => {
440
0
                write!(fmt, "The CICP {cicp:?} can not be used for RGB images",)
441
            }
442
443
0
            ParameterErrorKind::Generic(message) => {
444
0
                write!(fmt, "The parameter is malformed: {message}",)
445
            }
446
0
            ParameterErrorKind::NoMoreData => write!(fmt, "The end of the image has been reached",),
447
0
            ParameterErrorKind::CicpMismatch { expected, found } => {
448
0
                write!(
449
0
                    fmt,
450
0
                    "The color space {found:?} does not match the expected {expected:?}",
451
                )
452
            }
453
0
        }?;
454
455
0
        if let Some(underlying) = &self.underlying {
456
0
            write!(fmt, "\n{underlying}")?;
457
0
        }
458
459
0
        Ok(())
460
0
    }
461
}
462
463
impl Error for ParameterError {
464
0
    fn source(&self) -> Option<&(dyn Error + 'static)> {
465
0
        match &self.underlying {
466
0
            None => None,
467
0
            Some(source) => Some(&**source),
468
        }
469
0
    }
470
}
471
472
impl fmt::Display for EncodingError {
473
0
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
474
0
        match &self.underlying {
475
0
            Some(underlying) => write!(
476
0
                fmt,
477
0
                "Format error encoding {}:\n{}",
478
                self.format, underlying,
479
            ),
480
0
            None => write!(fmt, "Format error encoding {}", self.format,),
481
        }
482
0
    }
483
}
484
485
impl Error for EncodingError {
486
0
    fn source(&self) -> Option<&(dyn Error + 'static)> {
487
0
        match &self.underlying {
488
0
            None => None,
489
0
            Some(source) => Some(&**source),
490
        }
491
0
    }
492
}
493
494
impl fmt::Display for DecodingError {
495
0
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
496
0
        match &self.underlying {
497
0
            None => match self.format {
498
0
                ImageFormatHint::Unknown => write!(fmt, "Format error"),
499
0
                _ => write!(fmt, "Format error decoding {}", self.format),
500
            },
501
0
            Some(underlying) => {
502
0
                write!(fmt, "Format error decoding {}: {}", self.format, underlying)
503
            }
504
        }
505
0
    }
506
}
507
508
impl Error for DecodingError {
509
0
    fn source(&self) -> Option<&(dyn Error + 'static)> {
510
0
        match &self.underlying {
511
0
            None => None,
512
0
            Some(source) => Some(&**source),
513
        }
514
0
    }
515
}
516
517
impl fmt::Display for LimitError {
518
0
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
519
0
        match self.kind {
520
0
            LimitErrorKind::InsufficientMemory => write!(fmt, "Memory limit exceeded"),
521
0
            LimitErrorKind::DimensionError => write!(fmt, "Image size exceeds limit"),
522
            LimitErrorKind::Unsupported { .. } => {
523
0
                write!(fmt, "The following strict limits are specified but not supported by the opertation: ")?;
524
0
                Ok(())
525
            }
526
        }
527
0
    }
528
}
529
530
impl Error for LimitError {}
531
532
impl fmt::Display for ImageFormatHint {
533
0
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
534
0
        match self {
535
0
            ImageFormatHint::Exact(format) => write!(fmt, "{format:?}"),
536
0
            ImageFormatHint::Name(name) => write!(fmt, "`{name}`"),
537
0
            ImageFormatHint::PathExtension(ext) => write!(fmt, "`.{ext:?}`"),
538
0
            ImageFormatHint::Unknown => write!(fmt, "`Unknown`"),
539
        }
540
0
    }
541
}
542
543
/// Converting [`ExtendedColorType`] to [`ColorType`][`crate::ColorType`] failed.
544
///
545
/// This type is convertible to [`ImageError`] as [`ImageError::Unsupported`].
546
#[derive(Clone)]
547
#[allow(missing_copy_implementations)]
548
pub struct TryFromExtendedColorError {
549
    pub(crate) was: ExtendedColorType,
550
}
551
552
impl fmt::Debug for TryFromExtendedColorError {
553
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
554
0
        write!(f, "{}", self)
555
0
    }
556
}
557
558
impl fmt::Display for TryFromExtendedColorError {
559
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
560
0
        write!(
561
0
            f,
562
0
            "The pixel layout {:?} is not supported as a buffer ColorType",
563
            self.was
564
        )
565
0
    }
566
}
567
568
impl Error for TryFromExtendedColorError {}
569
570
impl From<TryFromExtendedColorError> for ImageError {
571
0
    fn from(err: TryFromExtendedColorError) -> ImageError {
572
0
        ImageError::Unsupported(UnsupportedError::from_format_and_kind(
573
0
            ImageFormatHint::Unknown,
574
0
            UnsupportedErrorKind::Color(err.was),
575
0
        ))
576
0
    }
577
}
578
579
#[cfg(test)]
580
mod tests {
581
    use super::*;
582
    use std::mem::size_of;
583
584
    #[allow(dead_code)]
585
    // This will fail to compile if the size of this type is large.
586
    const ASSERT_SMALLISH: usize = [0][(size_of::<ImageError>() >= 200) as usize];
587
588
    #[test]
589
    fn test_send_sync_stability() {
590
        fn assert_send_sync<T: Send + Sync>() {}
591
592
        assert_send_sync::<ImageError>();
593
    }
594
}