1pub type Result<T, E = Error> = std::result::Result<T, E>;
5
6#[derive(Debug)]
7pub enum Error {
8 Io(std::io::Error),
9 NotFound(String),
10 Library(libloading::Error),
11 JpegEncoding(jpeg_encoder::EncodingError),
12 #[cfg(feature = "codec")]
13 Codec(edgefirst_codec::CodecError),
14 ResizeImageBuffer(fast_image_resize::ImageBufferError),
15 Resize(fast_image_resize::ResizeError),
16 Yuv(yuv::YuvError),
17 #[cfg(target_os = "linux")]
18 G2D(g2d_sys::Error),
19 Tensor(edgefirst_tensor::Error),
20 NotImplemented(String),
21 NotSupported(String),
22 InvalidShape(String),
23 AliasedBuffers(String),
26 #[cfg(feature = "opengl")]
27 EGL(edgefirst_egl::Error),
28 GLVersion(String),
29 #[cfg(feature = "opengl")]
30 EGLLoad(edgefirst_egl::LoadError<libloading::Error>),
31 #[cfg(target_os = "linux")]
32 #[cfg(feature = "opengl")]
33 GbmInvalidFd(gbm::InvalidFdError),
34 #[cfg(target_os = "linux")]
35 #[cfg(feature = "opengl")]
36 GbmFrontBuffer(gbm::FrontBufferError),
37 OpenGl(String),
38 Internal(String),
39 CropInvalid(String),
40 InvalidOptions(String),
43 ForcedBackendUnavailable(String),
44 CpuFallbackDenied {
47 declined: String,
49 denied: edgefirst_tensor::Error,
52 },
53 NoConverter,
54 NotAnImage,
55 UnsupportedFormat(String),
56}
57
58impl From<std::io::Error> for Error {
59 fn from(err: std::io::Error) -> Self {
60 Error::Io(err)
61 }
62}
63
64impl From<libloading::Error> for Error {
65 fn from(err: libloading::Error) -> Self {
66 Error::Library(err)
67 }
68}
69
70impl From<jpeg_encoder::EncodingError> for Error {
71 fn from(err: jpeg_encoder::EncodingError) -> Self {
72 Error::JpegEncoding(err)
73 }
74}
75
76#[cfg(feature = "codec")]
77impl From<edgefirst_codec::CodecError> for Error {
78 fn from(err: edgefirst_codec::CodecError) -> Self {
79 Error::Codec(err)
80 }
81}
82
83impl From<fast_image_resize::ImageBufferError> for Error {
84 fn from(err: fast_image_resize::ImageBufferError) -> Self {
85 Error::ResizeImageBuffer(err)
86 }
87}
88
89impl From<fast_image_resize::ResizeError> for Error {
90 fn from(err: fast_image_resize::ResizeError) -> Self {
91 Error::Resize(err)
92 }
93}
94
95impl From<yuv::YuvError> for Error {
96 fn from(err: yuv::YuvError) -> Self {
97 Error::Yuv(err)
98 }
99}
100
101#[cfg(target_os = "linux")]
102impl From<g2d_sys::Error> for Error {
103 fn from(err: g2d_sys::Error) -> Self {
104 Error::G2D(err)
105 }
106}
107
108impl From<edgefirst_tensor::Error> for Error {
109 fn from(err: edgefirst_tensor::Error) -> Self {
110 Error::Tensor(err)
111 }
112}
113
114#[cfg(feature = "opengl")]
115impl From<edgefirst_egl::Error> for Error {
116 fn from(err: edgefirst_egl::Error) -> Self {
117 Error::EGL(err)
118 }
119}
120
121#[cfg(feature = "opengl")]
122impl From<edgefirst_egl::LoadError<libloading::Error>> for Error {
123 fn from(err: edgefirst_egl::LoadError<libloading::Error>) -> Self {
124 Error::EGLLoad(err)
125 }
126}
127
128#[cfg(target_os = "linux")]
129#[cfg(feature = "opengl")]
130impl From<gbm::InvalidFdError> for Error {
131 fn from(err: gbm::InvalidFdError) -> Self {
132 Error::GbmInvalidFd(err)
133 }
134}
135
136#[cfg(target_os = "linux")]
137#[cfg(feature = "opengl")]
138impl From<gbm::FrontBufferError> for Error {
139 fn from(err: gbm::FrontBufferError) -> Self {
140 Error::GbmFrontBuffer(err)
141 }
142}
143
144#[cfg(target_os = "linux")]
145#[cfg(feature = "opengl")]
146impl From<edgefirst_gl::Error> for Error {
147 fn from(err: edgefirst_gl::Error) -> Self {
148 Error::OpenGl(err.to_string())
149 }
150}
151
152impl From<ndarray::ShapeError> for Error {
153 fn from(err: ndarray::ShapeError) -> Self {
154 Error::Internal(format!("{err}"))
155 }
156}
157
158impl From<fast_image_resize::CropBoxError> for Error {
159 fn from(err: fast_image_resize::CropBoxError) -> Self {
160 Error::Internal(format!("{err}"))
161 }
162}
163
164impl Error {
165 pub fn cpu_access_denied(&self) -> Option<&edgefirst_tensor::Error> {
169 match self {
170 Error::Tensor(e) => e.cpu_access_denied(),
171 Error::CpuFallbackDenied { denied, .. } => Some(denied),
172 #[cfg(feature = "codec")]
173 Error::Codec(e) => e.cpu_access_denied(),
174 _ => None,
175 }
176 }
177}
178
179impl std::fmt::Display for Error {
180 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
181 match self {
182 Error::Tensor(e) => write!(f, "Tensor({e})"),
183 Error::CpuFallbackDenied { declined, denied } => write!(
184 f,
185 "the GPU path declined this convert ({declined}) and the CPU fallback \
186 was refused: {denied}"
187 ),
188 _ => write!(f, "{self:?}"),
189 }
190 }
191}
192
193impl std::error::Error for Error {}
194
195#[cfg(test)]
196mod tests {
197 use super::*;
198
199 #[test]
200 fn test_image_error_display() {
201 let e = Error::Io(std::io::Error::new(
202 std::io::ErrorKind::NotFound,
203 "file missing",
204 ));
205 let msg = e.to_string();
206 assert!(!msg.is_empty());
207 assert!(
208 msg.contains("Io") && msg.contains("file missing"),
209 "unexpected Io message: {msg}"
210 );
211
212 let e = Error::NotFound("texture.png".to_string());
213 let msg = e.to_string();
214 assert!(!msg.is_empty());
215 assert!(
216 msg.contains("NotFound") && msg.contains("texture.png"),
217 "unexpected NotFound message: {msg}"
218 );
219
220 let e = Error::Tensor(edgefirst_tensor::Error::InvalidSize(42));
221 let msg = e.to_string();
222 assert!(!msg.is_empty());
223 assert!(
224 msg.contains("Tensor") && msg.contains("InvalidSize"),
225 "unexpected Tensor message: {msg}"
226 );
227
228 let e = Error::NotImplemented("webp".to_string());
229 let msg = e.to_string();
230 assert!(!msg.is_empty());
231 assert!(
232 msg.contains("NotImplemented") && msg.contains("webp"),
233 "unexpected NotImplemented message: {msg}"
234 );
235
236 let e = Error::NotSupported("bmp format".to_string());
237 let msg = e.to_string();
238 assert!(!msg.is_empty());
239 assert!(
240 msg.contains("NotSupported") && msg.contains("bmp format"),
241 "unexpected NotSupported message: {msg}"
242 );
243
244 let e = Error::InvalidShape("wrong dims".to_string());
245 let msg = e.to_string();
246 assert!(!msg.is_empty());
247 assert!(
248 msg.contains("InvalidShape") && msg.contains("wrong dims"),
249 "unexpected InvalidShape message: {msg}"
250 );
251
252 let e = Error::GLVersion("4.5 required".to_string());
253 let msg = e.to_string();
254 assert!(!msg.is_empty());
255 assert!(
256 msg.contains("GLVersion") && msg.contains("4.5 required"),
257 "unexpected GLVersion message: {msg}"
258 );
259
260 let e = Error::OpenGl("shader compile failed".to_string());
261 let msg = e.to_string();
262 assert!(!msg.is_empty());
263 assert!(
264 msg.contains("OpenGl") && msg.contains("shader compile failed"),
265 "unexpected OpenGl message: {msg}"
266 );
267
268 let e = Error::Internal("unexpected state".to_string());
269 let msg = e.to_string();
270 assert!(!msg.is_empty());
271 assert!(
272 msg.contains("Internal") && msg.contains("unexpected state"),
273 "unexpected Internal message: {msg}"
274 );
275
276 let e = Error::CropInvalid("out of bounds".to_string());
277 let msg = e.to_string();
278 assert!(!msg.is_empty());
279 assert!(
280 msg.contains("CropInvalid") && msg.contains("out of bounds"),
281 "unexpected CropInvalid message: {msg}"
282 );
283
284 let e = Error::ForcedBackendUnavailable("g2d".to_string());
285 let msg = e.to_string();
286 assert!(!msg.is_empty());
287 assert!(
288 msg.contains("ForcedBackendUnavailable") && msg.contains("g2d"),
289 "unexpected ForcedBackendUnavailable message: {msg}"
290 );
291
292 let e = Error::NoConverter;
293 let msg = e.to_string();
294 assert!(!msg.is_empty());
295 assert!(
296 msg.contains("NoConverter"),
297 "unexpected NoConverter message: {msg}"
298 );
299
300 let e = Error::NotAnImage;
301 let msg = e.to_string();
302 assert!(!msg.is_empty());
303 assert!(
304 msg.contains("NotAnImage"),
305 "unexpected NotAnImage message: {msg}"
306 );
307
308 let e = Error::UnsupportedFormat("tiff".to_string());
309 let msg = e.to_string();
310 assert!(!msg.is_empty());
311 assert!(
312 msg.contains("UnsupportedFormat") && msg.contains("tiff"),
313 "unexpected UnsupportedFormat message: {msg}"
314 );
315 }
316}