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::io::Limits,
170 supported: crate::io::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 pub fn from_format_and_kind(format: ImageFormatHint, kind: UnsupportedErrorKind) -> Self {
198 UnsupportedError { format, kind }
199 }
200
201 pub fn kind(&self) -> UnsupportedErrorKind {
203 self.kind.clone()
204 }
205
206 pub fn format_hint(&self) -> ImageFormatHint {
208 self.format.clone()
209 }
210}
211
212impl DecodingError {
213 pub fn new(format: ImageFormatHint, err: impl Into<Box<dyn Error + Send + Sync>>) -> Self {
215 DecodingError {
216 format,
217 underlying: Some(err.into()),
218 }
219 }
220
221 pub fn from_format_hint(format: ImageFormatHint) -> Self {
225 DecodingError {
226 format,
227 underlying: None,
228 }
229 }
230
231 pub fn format_hint(&self) -> ImageFormatHint {
233 self.format.clone()
234 }
235}
236
237impl EncodingError {
238 pub fn new(format: ImageFormatHint, err: impl Into<Box<dyn Error + Send + Sync>>) -> Self {
240 EncodingError {
241 format,
242 underlying: Some(err.into()),
243 }
244 }
245
246 pub fn from_format_hint(format: ImageFormatHint) -> Self {
250 EncodingError {
251 format,
252 underlying: None,
253 }
254 }
255
256 pub fn format_hint(&self) -> ImageFormatHint {
258 self.format.clone()
259 }
260}
261
262impl ParameterError {
263 pub fn from_kind(kind: ParameterErrorKind) -> Self {
265 ParameterError {
266 kind,
267 underlying: None,
268 }
269 }
270
271 pub fn kind(&self) -> ParameterErrorKind {
273 self.kind.clone()
274 }
275}
276
277impl LimitError {
278 pub fn from_kind(kind: LimitErrorKind) -> Self {
280 LimitError { kind }
281 }
282
283 pub fn kind(&self) -> LimitErrorKind {
285 self.kind.clone()
286 }
287}
288
289impl From<io::Error> for ImageError {
290 fn from(err: io::Error) -> ImageError {
291 ImageError::IoError(err)
292 }
293}
294
295impl From<ImageFormat> for ImageFormatHint {
296 fn from(format: ImageFormat) -> Self {
297 ImageFormatHint::Exact(format)
298 }
299}
300
301impl From<&'_ std::path::Path> for ImageFormatHint {
302 fn from(path: &'_ std::path::Path) -> Self {
303 match path.extension() {
304 Some(ext) => ImageFormatHint::PathExtension(ext.into()),
305 None => ImageFormatHint::Unknown,
306 }
307 }
308}
309
310impl From<ImageFormatHint> for UnsupportedError {
311 fn from(hint: ImageFormatHint) -> Self {
312 UnsupportedError {
313 format: hint.clone(),
314 kind: UnsupportedErrorKind::Format(hint),
315 }
316 }
317}
318
319pub type ImageResult<T> = Result<T, ImageError>;
321
322impl fmt::Display for ImageError {
323 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
324 match self {
325 ImageError::IoError(err) => err.fmt(fmt),
326 ImageError::Decoding(err) => err.fmt(fmt),
327 ImageError::Encoding(err) => err.fmt(fmt),
328 ImageError::Parameter(err) => err.fmt(fmt),
329 ImageError::Limits(err) => err.fmt(fmt),
330 ImageError::Unsupported(err) => err.fmt(fmt),
331 }
332 }
333}
334
335impl Error for ImageError {
336 fn source(&self) -> Option<&(dyn Error + 'static)> {
337 match self {
338 ImageError::IoError(err) => err.source(),
339 ImageError::Decoding(err) => err.source(),
340 ImageError::Encoding(err) => err.source(),
341 ImageError::Parameter(err) => err.source(),
342 ImageError::Limits(err) => err.source(),
343 ImageError::Unsupported(err) => err.source(),
344 }
345 }
346}
347
348impl fmt::Display for UnsupportedError {
349 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
350 match &self.kind {
351 UnsupportedErrorKind::Format(ImageFormatHint::Unknown) => {
352 write!(fmt, "The image format could not be determined",)
353 }
354 UnsupportedErrorKind::Format(format @ ImageFormatHint::PathExtension(_)) => write!(
355 fmt,
356 "The file extension {} was not recognized as an image format",
357 format,
358 ),
359 UnsupportedErrorKind::Format(format) => {
360 write!(fmt, "The image format {} is not supported", format,)
361 }
362 UnsupportedErrorKind::Color(color) => write!(
363 fmt,
364 "The decoder for {} does not support the color type `{:?}`",
365 self.format, color,
366 ),
367 UnsupportedErrorKind::GenericFeature(message) => match &self.format {
368 ImageFormatHint::Unknown => write!(
369 fmt,
370 "The decoder does not support the format feature {}",
371 message,
372 ),
373 other => write!(
374 fmt,
375 "The decoder for {} does not support the format features {}",
376 other, message,
377 ),
378 },
379 }
380 }
381}
382
383impl Error for UnsupportedError {}
384
385impl fmt::Display for ParameterError {
386 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
387 match &self.kind {
388 ParameterErrorKind::DimensionMismatch => write!(
389 fmt,
390 "The Image's dimensions are either too \
391 small or too large"
392 ),
393 ParameterErrorKind::FailedAlready => write!(
394 fmt,
395 "The end the image stream has been reached due to a previous error"
396 ),
397 ParameterErrorKind::Generic(message) => {
398 write!(fmt, "The parameter is malformed: {}", message,)
399 }
400 ParameterErrorKind::NoMoreData => write!(fmt, "The end of the image has been reached",),
401 }?;
402
403 if let Some(underlying) = &self.underlying {
404 write!(fmt, "\n{}", underlying)?;
405 }
406
407 Ok(())
408 }
409}
410
411impl Error for ParameterError {
412 fn source(&self) -> Option<&(dyn Error + 'static)> {
413 match &self.underlying {
414 None => None,
415 Some(source) => Some(&**source),
416 }
417 }
418}
419
420impl fmt::Display for EncodingError {
421 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
422 match &self.underlying {
423 Some(underlying) => write!(
424 fmt,
425 "Format error encoding {}:\n{}",
426 self.format, underlying,
427 ),
428 None => write!(fmt, "Format error encoding {}", self.format,),
429 }
430 }
431}
432
433impl Error for EncodingError {
434 fn source(&self) -> Option<&(dyn Error + 'static)> {
435 match &self.underlying {
436 None => None,
437 Some(source) => Some(&**source),
438 }
439 }
440}
441
442impl fmt::Display for DecodingError {
443 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
444 match &self.underlying {
445 None => match self.format {
446 ImageFormatHint::Unknown => write!(fmt, "Format error"),
447 _ => write!(fmt, "Format error decoding {}", self.format),
448 },
449 Some(underlying) => {
450 write!(fmt, "Format error decoding {}: {}", self.format, underlying)
451 }
452 }
453 }
454}
455
456impl Error for DecodingError {
457 fn source(&self) -> Option<&(dyn Error + 'static)> {
458 match &self.underlying {
459 None => None,
460 Some(source) => Some(&**source),
461 }
462 }
463}
464
465impl fmt::Display for LimitError {
466 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
467 match self.kind {
468 LimitErrorKind::InsufficientMemory => write!(fmt, "Memory limit exceeded"),
469 LimitErrorKind::DimensionError => write!(fmt, "Image size exceeds limit"),
470 LimitErrorKind::Unsupported { .. } => {
471 write!(fmt, "The following strict limits are specified but not supported by the opertation: ")?;
472 Ok(())
473 }
474 }
475 }
476}
477
478impl Error for LimitError {}
479
480impl fmt::Display for ImageFormatHint {
481 fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
482 match self {
483 ImageFormatHint::Exact(format) => write!(fmt, "{:?}", format),
484 ImageFormatHint::Name(name) => write!(fmt, "`{}`", name),
485 ImageFormatHint::PathExtension(ext) => write!(fmt, "`.{:?}`", ext),
486 ImageFormatHint::Unknown => write!(fmt, "`Unknown`"),
487 }
488 }
489}
490
491#[cfg(test)]
492mod tests {
493 use super::*;
494 use std::mem;
495
496 #[allow(dead_code)]
497 const ASSERT_SMALLISH: usize = [0][(mem::size_of::<ImageError>() >= 200) as usize];
499
500 #[test]
501 fn test_send_sync_stability() {
502 fn assert_send_sync<T: Send + Sync>() {}
503
504 assert_send_sync::<ImageError>();
505 }
506}