1use thiserror::Error;
7
8pub type Result<T> = std::result::Result<T, SensorError>;
10
11#[derive(Debug, Error)]
13pub enum SensorError {
14 #[error("Invalid sensor: {0}")]
16 InvalidSensor(String),
17
18 #[error("Invalid band: {0}")]
20 InvalidBand(String),
21
22 #[error("Band '{band}' not found for sensor '{sensor}'")]
24 BandNotFound {
25 sensor: String,
27 band: String,
29 },
30
31 #[error("Invalid spectral index: {0}")]
33 InvalidIndex(String),
34
35 #[error("Missing required band '{band}' for operation '{operation}'")]
37 MissingBand {
38 band: String,
40 operation: String,
42 },
43
44 #[error("Invalid metadata: {0}")]
46 InvalidMetadata(String),
47
48 #[error("Radiometric calibration failed: {0}")]
50 CalibrationError(String),
51
52 #[error("Atmospheric correction failed: {0}")]
54 AtmosphericCorrectionError(String),
55
56 #[error("BRDF normalization failed: {0}")]
58 BrdfError(String),
59
60 #[error("Spectral index calculation failed: {0}")]
62 IndexError(String),
63
64 #[error("Pan-sharpening failed: {0}")]
66 PanSharpeningError(String),
67
68 #[error("Classification failed: {0}")]
70 ClassificationError(String),
71
72 #[error("Invalid DN value: {0}")]
74 InvalidDN(String),
75
76 #[error("Invalid radiance value: {0}")]
78 InvalidRadiance(String),
79
80 #[error("Invalid reflectance value: {0}")]
82 InvalidReflectance(String),
83
84 #[error("Invalid solar angle: {0}")]
86 InvalidSolarAngle(String),
87
88 #[error("Invalid date/time: {0}")]
90 InvalidDateTime(String),
91
92 #[error("Dimension mismatch: expected {expected}, got {actual}")]
94 DimensionMismatch {
95 expected: String,
97 actual: String,
99 },
100
101 #[error("Invalid parameter '{param}': {reason}")]
103 InvalidParameter {
104 param: String,
106 reason: String,
108 },
109
110 #[error("Numerical instability: {0}")]
112 NumericalInstability(String),
113
114 #[error("Division by zero in operation: {0}")]
116 DivisionByZero(String),
117
118 #[error("Core error: {0}")]
120 CoreError(#[from] oxigdal_core::error::OxiGdalError),
121
122 #[error("SciRS2 error: {0}")]
124 SciRS2Error(String),
125
126 #[error("I/O error: {0}")]
128 IoError(#[from] std::io::Error),
129
130 #[error("Serialization error: {0}")]
132 SerializationError(#[from] serde_json::Error),
133}
134
135impl SensorError {
136 pub fn invalid_sensor(msg: impl Into<String>) -> Self {
138 Self::InvalidSensor(msg.into())
139 }
140
141 pub fn invalid_band(msg: impl Into<String>) -> Self {
143 Self::InvalidBand(msg.into())
144 }
145
146 pub fn band_not_found(sensor: impl Into<String>, band: impl Into<String>) -> Self {
148 Self::BandNotFound {
149 sensor: sensor.into(),
150 band: band.into(),
151 }
152 }
153
154 pub fn invalid_index(msg: impl Into<String>) -> Self {
156 Self::InvalidIndex(msg.into())
157 }
158
159 pub fn missing_band(band: impl Into<String>, operation: impl Into<String>) -> Self {
161 Self::MissingBand {
162 band: band.into(),
163 operation: operation.into(),
164 }
165 }
166
167 pub fn invalid_metadata(msg: impl Into<String>) -> Self {
169 Self::InvalidMetadata(msg.into())
170 }
171
172 pub fn calibration_error(msg: impl Into<String>) -> Self {
174 Self::CalibrationError(msg.into())
175 }
176
177 pub fn atmospheric_correction_error(msg: impl Into<String>) -> Self {
179 Self::AtmosphericCorrectionError(msg.into())
180 }
181
182 pub fn brdf_error(msg: impl Into<String>) -> Self {
184 Self::BrdfError(msg.into())
185 }
186
187 pub fn index_error(msg: impl Into<String>) -> Self {
189 Self::IndexError(msg.into())
190 }
191
192 pub fn pan_sharpening_error(msg: impl Into<String>) -> Self {
194 Self::PanSharpeningError(msg.into())
195 }
196
197 pub fn classification_error(msg: impl Into<String>) -> Self {
199 Self::ClassificationError(msg.into())
200 }
201
202 pub fn dimension_mismatch(expected: impl Into<String>, actual: impl Into<String>) -> Self {
204 Self::DimensionMismatch {
205 expected: expected.into(),
206 actual: actual.into(),
207 }
208 }
209
210 pub fn invalid_parameter(param: impl Into<String>, reason: impl Into<String>) -> Self {
212 Self::InvalidParameter {
213 param: param.into(),
214 reason: reason.into(),
215 }
216 }
217
218 pub fn numerical_instability(msg: impl Into<String>) -> Self {
220 Self::NumericalInstability(msg.into())
221 }
222
223 pub fn division_by_zero(msg: impl Into<String>) -> Self {
225 Self::DivisionByZero(msg.into())
226 }
227
228 pub fn scirs2_error(msg: impl Into<String>) -> Self {
230 Self::SciRS2Error(msg.into())
231 }
232}
233
234#[cfg(test)]
235mod tests {
236 use super::*;
237
238 #[test]
239 fn test_error_creation() {
240 let err = SensorError::invalid_sensor("Unknown sensor");
241 assert!(matches!(err, SensorError::InvalidSensor(_)));
242
243 let err = SensorError::band_not_found("Landsat8", "B10");
244 assert!(matches!(err, SensorError::BandNotFound { .. }));
245
246 let err = SensorError::missing_band("NIR", "NDVI");
247 assert!(matches!(err, SensorError::MissingBand { .. }));
248 }
249
250 #[test]
251 fn test_error_display() {
252 let err = SensorError::invalid_sensor("Unknown sensor type");
253 assert_eq!(format!("{}", err), "Invalid sensor: Unknown sensor type");
254
255 let err = SensorError::band_not_found("Landsat8", "B10");
256 assert_eq!(
257 format!("{}", err),
258 "Band 'B10' not found for sensor 'Landsat8'"
259 );
260
261 let err = SensorError::dimension_mismatch("100x100", "200x200");
262 assert_eq!(
263 format!("{}", err),
264 "Dimension mismatch: expected 100x100, got 200x200"
265 );
266 }
267}