Coverage Report

Created: 2026-06-18 07:57

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