Skip to main content

oxigdal_sensors/
error.rs

1//! Error types for OxiGDAL Sensors
2//!
3//! This module provides comprehensive error handling for all sensor operations.
4//! All errors implement `std::error::Error` and are designed for production use.
5
6use thiserror::Error;
7
8/// Result type alias for sensor operations
9pub type Result<T> = std::result::Result<T, SensorError>;
10
11/// Comprehensive error types for sensor operations
12#[derive(Debug, Error)]
13pub enum SensorError {
14    /// Invalid sensor type or configuration
15    #[error("Invalid sensor: {0}")]
16    InvalidSensor(String),
17
18    /// Invalid band specification
19    #[error("Invalid band: {0}")]
20    InvalidBand(String),
21
22    /// Band not found for sensor
23    #[error("Band '{band}' not found for sensor '{sensor}'")]
24    BandNotFound {
25        /// The sensor name
26        sensor: String,
27        /// The band name that was not found
28        band: String,
29    },
30
31    /// Invalid spectral index
32    #[error("Invalid spectral index: {0}")]
33    InvalidIndex(String),
34
35    /// Missing required band for operation
36    #[error("Missing required band '{band}' for operation '{operation}'")]
37    MissingBand {
38        /// The missing band name
39        band: String,
40        /// The operation that required the band
41        operation: String,
42    },
43
44    /// Invalid metadata
45    #[error("Invalid metadata: {0}")]
46    InvalidMetadata(String),
47
48    /// Radiometric calibration failed
49    #[error("Radiometric calibration failed: {0}")]
50    CalibrationError(String),
51
52    /// Atmospheric correction failed
53    #[error("Atmospheric correction failed: {0}")]
54    AtmosphericCorrectionError(String),
55
56    /// BRDF normalization failed
57    #[error("BRDF normalization failed: {0}")]
58    BrdfError(String),
59
60    /// Spectral index calculation failed
61    #[error("Spectral index calculation failed: {0}")]
62    IndexError(String),
63
64    /// Pan-sharpening failed
65    #[error("Pan-sharpening failed: {0}")]
66    PanSharpeningError(String),
67
68    /// Classification failed
69    #[error("Classification failed: {0}")]
70    ClassificationError(String),
71
72    /// Invalid DN (Digital Number) value
73    #[error("Invalid DN value: {0}")]
74    InvalidDN(String),
75
76    /// Invalid radiance value
77    #[error("Invalid radiance value: {0}")]
78    InvalidRadiance(String),
79
80    /// Invalid reflectance value
81    #[error("Invalid reflectance value: {0}")]
82    InvalidReflectance(String),
83
84    /// Invalid solar angle
85    #[error("Invalid solar angle: {0}")]
86    InvalidSolarAngle(String),
87
88    /// Invalid date/time
89    #[error("Invalid date/time: {0}")]
90    InvalidDateTime(String),
91
92    /// Dimension mismatch in arrays
93    #[error("Dimension mismatch: expected {expected}, got {actual}")]
94    DimensionMismatch {
95        /// The expected dimension
96        expected: String,
97        /// The actual dimension
98        actual: String,
99    },
100
101    /// Invalid parameter value
102    #[error("Invalid parameter '{param}': {reason}")]
103    InvalidParameter {
104        /// The invalid parameter name
105        param: String,
106        /// The reason why it is invalid
107        reason: String,
108    },
109
110    /// Numerical instability detected
111    #[error("Numerical instability: {0}")]
112    NumericalInstability(String),
113
114    /// Division by zero
115    #[error("Division by zero in operation: {0}")]
116    DivisionByZero(String),
117
118    /// Core library error
119    #[error("Core error: {0}")]
120    CoreError(#[from] oxigdal_core::error::OxiGdalError),
121
122    /// SciRS2 error
123    #[error("SciRS2 error: {0}")]
124    SciRS2Error(String),
125
126    /// I/O error
127    #[error("I/O error: {0}")]
128    IoError(#[from] std::io::Error),
129
130    /// Serialization error
131    #[error("Serialization error: {0}")]
132    SerializationError(#[from] serde_json::Error),
133}
134
135impl SensorError {
136    /// Create an invalid sensor error
137    pub fn invalid_sensor(msg: impl Into<String>) -> Self {
138        Self::InvalidSensor(msg.into())
139    }
140
141    /// Create an invalid band error
142    pub fn invalid_band(msg: impl Into<String>) -> Self {
143        Self::InvalidBand(msg.into())
144    }
145
146    /// Create a band not found error
147    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    /// Create an invalid index error
155    pub fn invalid_index(msg: impl Into<String>) -> Self {
156        Self::InvalidIndex(msg.into())
157    }
158
159    /// Create a missing band error
160    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    /// Create an invalid metadata error
168    pub fn invalid_metadata(msg: impl Into<String>) -> Self {
169        Self::InvalidMetadata(msg.into())
170    }
171
172    /// Create a calibration error
173    pub fn calibration_error(msg: impl Into<String>) -> Self {
174        Self::CalibrationError(msg.into())
175    }
176
177    /// Create an atmospheric correction error
178    pub fn atmospheric_correction_error(msg: impl Into<String>) -> Self {
179        Self::AtmosphericCorrectionError(msg.into())
180    }
181
182    /// Create a BRDF error
183    pub fn brdf_error(msg: impl Into<String>) -> Self {
184        Self::BrdfError(msg.into())
185    }
186
187    /// Create an index error
188    pub fn index_error(msg: impl Into<String>) -> Self {
189        Self::IndexError(msg.into())
190    }
191
192    /// Create a pan-sharpening error
193    pub fn pan_sharpening_error(msg: impl Into<String>) -> Self {
194        Self::PanSharpeningError(msg.into())
195    }
196
197    /// Create a classification error
198    pub fn classification_error(msg: impl Into<String>) -> Self {
199        Self::ClassificationError(msg.into())
200    }
201
202    /// Create a dimension mismatch error
203    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    /// Create an invalid parameter error
211    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    /// Create a numerical instability error
219    pub fn numerical_instability(msg: impl Into<String>) -> Self {
220        Self::NumericalInstability(msg.into())
221    }
222
223    /// Create a division by zero error
224    pub fn division_by_zero(msg: impl Into<String>) -> Self {
225        Self::DivisionByZero(msg.into())
226    }
227
228    /// Create a SciRS2 error
229    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}