oxify_connect_vision/
errors.rs1use crate::diagnostics::ErrorDiagnostic;
4use thiserror::Error;
5
6#[derive(Debug, Error)]
8pub enum VisionError {
9 #[error("Failed to load model: {0}")]
11 ModelLoad(String),
12
13 #[error("Model is not loaded. Call load_model() first.")]
15 ModelNotLoaded,
16
17 #[error("Image processing error: {0}")]
19 ImageProcessing(String),
20
21 #[error("Invalid image format: {0}")]
23 InvalidFormat(String),
24
25 #[error("Failed to decode image: {0}")]
27 ImageDecode(String),
28
29 #[error("OCR engine error: {0}")]
31 OcrEngine(String),
32
33 #[error("ONNX runtime error: {0}")]
35 OnnxRuntime(String),
36
37 #[error("Tesseract error: {0}")]
39 Tesseract(String),
40
41 #[error("Configuration error: {0}")]
43 Config(String),
44
45 #[error("Unsupported provider: {0}")]
47 UnsupportedProvider(String),
48
49 #[error("Processing timeout after {0}ms")]
51 Timeout(u64),
52
53 #[error("Resource exhaustion: {0}")]
55 ResourceExhaustion(String),
56
57 #[error("I/O error: {0}")]
59 Io(#[from] std::io::Error),
60
61 #[error("{0}")]
63 Other(String),
64}
65
66impl VisionError {
67 pub fn model_load(msg: impl Into<String>) -> Self {
69 VisionError::ModelLoad(msg.into())
70 }
71
72 pub fn image_processing(msg: impl Into<String>) -> Self {
74 VisionError::ImageProcessing(msg.into())
75 }
76
77 pub fn ocr_engine(msg: impl Into<String>) -> Self {
79 VisionError::OcrEngine(msg.into())
80 }
81
82 pub fn onnx_runtime(msg: impl Into<String>) -> Self {
84 VisionError::OnnxRuntime(msg.into())
85 }
86
87 pub fn tesseract(msg: impl Into<String>) -> Self {
89 VisionError::Tesseract(msg.into())
90 }
91
92 pub fn config(msg: impl Into<String>) -> Self {
94 VisionError::Config(msg.into())
95 }
96
97 pub fn unsupported_provider(provider: impl Into<String>) -> Self {
99 VisionError::UnsupportedProvider(provider.into())
100 }
101
102 pub fn diagnostic(&self) -> ErrorDiagnostic {
107 match self {
108 VisionError::ModelLoad(msg) => {
109 let path = msg.split(':').next_back().unwrap_or(msg).trim();
111 ErrorDiagnostic::model_load(path)
112 }
113 VisionError::ModelNotLoaded => ErrorDiagnostic::model_not_loaded(),
114 VisionError::ImageProcessing(msg) | VisionError::ImageDecode(msg) => {
115 ErrorDiagnostic::image_format(msg)
116 }
117 VisionError::InvalidFormat(msg) => ErrorDiagnostic::image_format(msg),
118 VisionError::OnnxRuntime(msg) => ErrorDiagnostic::onnx_runtime(msg),
119 VisionError::Tesseract(msg) => ErrorDiagnostic::tesseract(msg),
120 VisionError::Config(msg) => ErrorDiagnostic::configuration(msg),
121 VisionError::ResourceExhaustion(msg) => ErrorDiagnostic::resource_exhaustion(msg),
122 VisionError::OcrEngine(msg) => {
123 if msg.contains("Tesseract") || msg.contains("tesseract") {
125 ErrorDiagnostic::tesseract(msg)
126 } else if msg.contains("ONNX") || msg.contains("onnx") {
127 ErrorDiagnostic::onnx_runtime(msg)
128 } else {
129 ErrorDiagnostic::configuration(msg)
130 }
131 }
132 _ => ErrorDiagnostic::configuration(&self.to_string()),
133 }
134 }
135
136 pub fn with_diagnostics(&self) -> String {
140 format!("{}\n{}", self, self.diagnostic().format())
141 }
142}
143
144pub type Result<T> = std::result::Result<T, VisionError>;
146
147#[cfg(test)]
148mod tests {
149 use super::*;
150
151 #[test]
152 fn test_error_display() {
153 let err = VisionError::model_load("Model file not found");
154 assert_eq!(
155 err.to_string(),
156 "Failed to load model: Model file not found"
157 );
158 }
159
160 #[test]
161 fn test_error_variants() {
162 let errors = vec![
163 VisionError::ModelNotLoaded,
164 VisionError::image_processing("test"),
165 VisionError::ocr_engine("test"),
166 VisionError::config("test"),
167 VisionError::unsupported_provider("test"),
168 VisionError::Timeout(1000),
169 ];
170
171 for err in errors {
172 let _ = err.to_string();
174 }
175 }
176
177 #[test]
178 fn test_error_diagnostics() {
179 let err = VisionError::ModelNotLoaded;
180 let diag = err.diagnostic();
181 assert!(!diag.suggestions.is_empty());
182
183 let err = VisionError::model_load("/nonexistent/model.onnx");
184 let diag = err.diagnostic();
185 assert!(!diag.suggestions.is_empty());
186 assert!(diag.system_info.is_some());
187 }
188
189 #[test]
190 fn test_error_with_diagnostics() {
191 let err = VisionError::ModelNotLoaded;
192 let msg = err.with_diagnostics();
193 assert!(msg.contains("Call provider.load_model()"));
194 assert!(msg.contains("Suggestions"));
195 }
196
197 #[test]
198 fn test_onnx_runtime_diagnostics() {
199 let err = VisionError::onnx_runtime("CUDA memory allocation failed");
200 let diag = err.diagnostic();
201 assert!(!diag.suggestions.is_empty());
202 assert!(diag.system_info.is_some());
203 }
204
205 #[test]
206 fn test_tesseract_diagnostics() {
207 let err = VisionError::tesseract("Language data not found");
208 let diag = err.diagnostic();
209 assert!(!diag.suggestions.is_empty());
210 }
211
212 #[test]
213 fn test_image_format_diagnostics() {
214 let err = VisionError::InvalidFormat("decode error".to_string());
215 let diag = err.diagnostic();
216 assert!(!diag.suggestions.is_empty());
217 }
218}