1use std::fmt;
7
8#[non_exhaustive]
14#[derive(Debug, Clone, PartialEq, Eq)]
15pub enum UnsupportedFeature {
16 ProgressiveJpeg,
18 ExtendedSequentialJpeg,
20 ArithmeticCodedJpeg,
23 LosslessJpeg,
25 HierarchicalJpeg,
27 JpegPrecision {
29 bits: u8,
31 },
32 JpegComponentCount {
35 components: u8,
37 },
38 PngNotEnabled,
40 JpegChromaSubsampling,
44}
45
46impl fmt::Display for UnsupportedFeature {
47 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
48 match self {
49 Self::ProgressiveJpeg => write!(f, "progressive JPEG (SOF2)"),
50 Self::ExtendedSequentialJpeg => {
51 write!(f, "extended sequential JPEG (SOF1)")
52 }
53 Self::ArithmeticCodedJpeg => write!(
54 f,
55 "arithmetic-coded JPEG (SOF9/SOF10/SOF11/SOF13/SOF14/SOF15)"
56 ),
57 Self::LosslessJpeg => write!(f, "lossless JPEG (SOF3)"),
58 Self::HierarchicalJpeg => write!(f, "hierarchical JPEG (SOF5/SOF6/SOF7)"),
59 Self::JpegPrecision { bits } => {
60 write!(f, "JPEG sample precision {bits} (only 8-bit is supported)")
61 }
62 Self::JpegComponentCount { components } => {
63 write!(
64 f,
65 "JPEG component count {components} (only 1 or 3 are supported)"
66 )
67 }
68 Self::PngNotEnabled => write!(
69 f,
70 "PNG decoding is not enabled in this build (enable the `png` feature)"
71 ),
72 Self::JpegChromaSubsampling => {
73 write!(f, "JPEG chroma subsampling that exceeds luma sampling rate")
74 }
75 }
76 }
77}
78
79#[derive(Debug)]
81pub enum CodecError {
82 InsufficientCapacity {
84 image: (usize, usize),
86 tensor: (usize, usize),
88 },
89 UnsupportedDtype(edgefirst_tensor::DType),
91 UnsupportedFormat(edgefirst_tensor::PixelFormat),
93 Unsupported(UnsupportedFeature),
98 InvalidData(String),
100 Io(std::io::Error),
102 Tensor(edgefirst_tensor::Error),
104 NoDevice(String),
107 InvalidConfig(String),
109 InvalidInput(String),
111 Device {
113 op: String,
115 source: std::io::Error,
117 },
118 Timeout(String),
120 PoolExhausted {
124 held: usize,
126 pool: usize,
128 },
129}
130
131impl fmt::Display for CodecError {
132 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
133 match self {
134 Self::InsufficientCapacity { image, tensor } => write!(
135 f,
136 "image dimensions {}×{} exceed tensor capacity {}×{}",
137 image.0, image.1, tensor.0, tensor.1,
138 ),
139 Self::UnsupportedDtype(dt) => {
140 write!(f, "unsupported tensor dtype {dt:?} for image decode")
141 }
142 Self::UnsupportedFormat(pf) => {
143 write!(f, "unsupported pixel format {pf:?} for image decode")
144 }
145 Self::Unsupported(feat) => write!(f, "unsupported image feature: {feat}"),
146 Self::InvalidData(msg) => write!(f, "invalid image data: {msg}"),
147 Self::Io(e) => write!(f, "I/O error: {e}"),
148 Self::Tensor(e) => write!(f, "tensor error: {e}"),
149 Self::NoDevice(what) => write!(f, "no device: {what}"),
150 Self::InvalidConfig(what) => write!(f, "invalid configuration: {what}"),
151 Self::InvalidInput(what) => write!(f, "invalid input: {what}"),
152 Self::Device { op, source } => write!(f, "{op} failed: {source}"),
153 Self::Timeout(what) => write!(f, "timed out: {what}"),
154 Self::PoolExhausted { held, pool } => write!(
155 f,
156 "{held} of {pool} decoder output buffers are held by frames not yet dropped"
157 ),
158 }
159 }
160}
161
162impl std::error::Error for CodecError {
163 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
164 match self {
165 Self::Io(e) => Some(e),
166 Self::Tensor(e) => Some(e),
167 Self::Device { source, .. } => Some(source),
168 _ => None,
169 }
170 }
171}
172
173impl CodecError {
174 pub fn cpu_access_denied(&self) -> Option<&edgefirst_tensor::Error> {
177 match self {
178 Self::Tensor(e) => e.cpu_access_denied(),
179 _ => None,
180 }
181 }
182}
183
184impl From<std::io::Error> for CodecError {
185 fn from(e: std::io::Error) -> Self {
186 Self::Io(e)
187 }
188}
189
190impl From<edgefirst_tensor::Error> for CodecError {
191 fn from(e: edgefirst_tensor::Error) -> Self {
192 Self::Tensor(e)
193 }
194}
195
196#[cfg(feature = "png")]
197impl From<zune_png::error::PngDecodeErrors> for CodecError {
198 fn from(e: zune_png::error::PngDecodeErrors) -> Self {
199 Self::InvalidData(format!("PNG: {e}"))
200 }
201}