Skip to main content

ithmb_core/
error.rs

1//! Error types and image container for ithmb-core.
2//!
3//! # `DecodeError`
4//!
5//! Every decoder path returns [`DecodeError`] on failure — never `Box<dyn Error>` or
6//! raw I/O errors (this crate is pure, no I/O).
7//!
8//! # `DecodedImage`
9//!
10//! The canonical output type: a decoded bitmap with its dimensions.
11
12use std::fmt;
13
14// ---------------------------------------------------------------------------
15// DecodedImage
16// ---------------------------------------------------------------------------
17
18/// A fully decoded bitmap.
19#[derive(Clone, Debug, PartialEq, Eq)]
20pub struct DecodedImage {
21    /// Raw pixel data in BGRA 8-bit order (blue, green, red, alpha).
22    pub data: Vec<u8>,
23    /// Image width in pixels.
24    pub width: u32,
25    /// Image height in pixels.
26    pub height: u32,
27}
28
29// ---------------------------------------------------------------------------
30// DecodeError
31// ---------------------------------------------------------------------------
32
33/// Errors that can occur while decoding an `.ithmb` thumbnail.
34///
35/// Every variant carries a human-readable detail string or structured fields.
36#[derive(Debug, thiserror::Error)]
37#[non_exhaustive]
38pub enum DecodeError {
39    /// An I/O-level failure (e.g. end of stream, read error).
40    #[error("I/O error: {0}")]
41    Io(String),
42
43    /// A JPEG decode failure (corrupt or unsupported JPEG data).
44    #[error("JPEG error: {0}")]
45    Jpeg(String),
46
47    /// The file format is invalid or unrecognized.
48    #[error("Invalid format: {0}")]
49    InvalidFormat(String),
50
51    /// The format is recognized but not supported by this decoder.
52    #[error("Unsupported format: {0}")]
53    Unsupported(String),
54
55    /// The input buffer ended before the expected amount of data was consumed.
56    #[error("Buffer too short: expected {expected} bytes, got {actual}")]
57    BufferTooShort {
58        /// Number of bytes the decoder expected.
59        expected: usize,
60        /// Actual number of bytes available.
61        actual: usize,
62    },
63
64    /// A decoder profile mismatch or configuration error.
65    #[error("Profile error: {0}")]
66    Profile(String),
67
68    /// The operation was canceled by the caller.
69    #[error("Canceled: {0}")]
70    Canceled(String),
71
72    /// The input file exceeds the maximum allowed size.
73    #[error("File too large: {size} bytes exceeds limit of {limit} bytes")]
74    FileTooLarge {
75        /// Actual file size in bytes.
76        size: usize,
77        /// Maximum allowed size in bytes.
78        limit: usize,
79    },
80}
81
82// Manual impls for traits that derive cannot produce for enum variants with
83// named fields only (same as derived Debug + Display above — placeholder for
84// future manual formatting).
85impl fmt::Display for DecodedImage {
86    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
87        write!(
88            f,
89            "DecodedImage {{ data: {} bytes, width: {}, height: {} }}",
90            self.data.len(),
91            self.width,
92            self.height,
93        )
94    }
95}