Skip to main content

oxigdal_analytics/
error.rs

1//! Error types for OxiGDAL Analytics
2//!
3//! This module provides comprehensive error handling for all analytics operations.
4//! All errors implement `std::error::Error` and are designed for production use.
5
6use thiserror::Error;
7
8/// Result type alias for analytics operations
9pub type Result<T> = std::result::Result<T, AnalyticsError>;
10
11/// Comprehensive error types for analytics operations
12#[derive(Debug, Error)]
13pub enum AnalyticsError {
14    /// Invalid input parameters
15    #[error("Invalid input: {0}")]
16    InvalidInput(String),
17
18    /// Insufficient data for computation
19    #[error("Insufficient data: {0}")]
20    InsufficientData(String),
21
22    /// Computation failed to converge
23    #[error("Convergence failed: {0}")]
24    ConvergenceError(String),
25
26    /// Numerical instability detected
27    #[error("Numerical instability: {0}")]
28    NumericalInstability(String),
29
30    /// Matrix operation failed
31    #[error("Matrix operation failed: {0}")]
32    MatrixError(String),
33
34    /// Dimension mismatch in arrays
35    #[error("Dimension mismatch: expected {expected}, got {actual}")]
36    DimensionMismatch { expected: String, actual: String },
37
38    /// Invalid parameter value
39    #[error("Invalid parameter '{param}': {reason}")]
40    InvalidParameter { param: String, reason: String },
41
42    /// Statistical test failed
43    #[error("Statistical test failed: {0}")]
44    StatisticalTestError(String),
45
46    /// Clustering operation failed
47    #[error("Clustering failed: {0}")]
48    ClusteringError(String),
49
50    /// Interpolation failed
51    #[error("Interpolation failed: {0}")]
52    InterpolationError(String),
53
54    /// Time series analysis failed
55    #[error("Time series analysis failed: {0}")]
56    TimeSeriesError(String),
57
58    /// Hotspot analysis failed
59    #[error("Hotspot analysis failed: {0}")]
60    HotspotError(String),
61
62    /// Change detection failed
63    #[error("Change detection failed: {0}")]
64    ChangeDetectionError(String),
65
66    /// Zonal statistics failed
67    #[error("Zonal statistics failed: {0}")]
68    ZonalStatsError(String),
69
70    /// Core library error
71    #[error("Core error: {0}")]
72    CoreError(#[from] oxigdal_core::error::OxiGdalError),
73
74    /// SciRS2 error
75    #[error("SciRS2 error: {0}")]
76    SciRS2Error(String),
77
78    /// I/O error
79    #[error("I/O error: {0}")]
80    IoError(#[from] std::io::Error),
81}
82
83impl AnalyticsError {
84    /// Create an invalid input error
85    pub fn invalid_input(msg: impl Into<String>) -> Self {
86        Self::InvalidInput(msg.into())
87    }
88
89    /// Create an insufficient data error
90    pub fn insufficient_data(msg: impl Into<String>) -> Self {
91        Self::InsufficientData(msg.into())
92    }
93
94    /// Create a convergence error
95    pub fn convergence_error(msg: impl Into<String>) -> Self {
96        Self::ConvergenceError(msg.into())
97    }
98
99    /// Create a numerical instability error
100    pub fn numerical_instability(msg: impl Into<String>) -> Self {
101        Self::NumericalInstability(msg.into())
102    }
103
104    /// Create a matrix error
105    pub fn matrix_error(msg: impl Into<String>) -> Self {
106        Self::MatrixError(msg.into())
107    }
108
109    /// Create a dimension mismatch error
110    pub fn dimension_mismatch(expected: impl Into<String>, actual: impl Into<String>) -> Self {
111        Self::DimensionMismatch {
112            expected: expected.into(),
113            actual: actual.into(),
114        }
115    }
116
117    /// Create an invalid parameter error
118    pub fn invalid_parameter(param: impl Into<String>, reason: impl Into<String>) -> Self {
119        Self::InvalidParameter {
120            param: param.into(),
121            reason: reason.into(),
122        }
123    }
124
125    /// Create a statistical test error
126    pub fn statistical_test_error(msg: impl Into<String>) -> Self {
127        Self::StatisticalTestError(msg.into())
128    }
129
130    /// Create a clustering error
131    pub fn clustering_error(msg: impl Into<String>) -> Self {
132        Self::ClusteringError(msg.into())
133    }
134
135    /// Create an interpolation error
136    pub fn interpolation_error(msg: impl Into<String>) -> Self {
137        Self::InterpolationError(msg.into())
138    }
139
140    /// Create a time series error
141    pub fn time_series_error(msg: impl Into<String>) -> Self {
142        Self::TimeSeriesError(msg.into())
143    }
144
145    /// Create a hotspot analysis error
146    pub fn hotspot_error(msg: impl Into<String>) -> Self {
147        Self::HotspotError(msg.into())
148    }
149
150    /// Create a change detection error
151    pub fn change_detection_error(msg: impl Into<String>) -> Self {
152        Self::ChangeDetectionError(msg.into())
153    }
154
155    /// Create a zonal statistics error
156    pub fn zonal_stats_error(msg: impl Into<String>) -> Self {
157        Self::ZonalStatsError(msg.into())
158    }
159
160    /// Create a SciRS2 error
161    pub fn scirs2_error(msg: impl Into<String>) -> Self {
162        Self::SciRS2Error(msg.into())
163    }
164}
165
166#[cfg(test)]
167mod tests {
168    use super::*;
169
170    #[test]
171    fn test_error_creation() {
172        let err = AnalyticsError::invalid_input("test");
173        assert!(matches!(err, AnalyticsError::InvalidInput(_)));
174
175        let err = AnalyticsError::dimension_mismatch("3x3", "4x4");
176        assert!(matches!(err, AnalyticsError::DimensionMismatch { .. }));
177    }
178
179    #[test]
180    fn test_error_display() {
181        let err = AnalyticsError::invalid_input("invalid parameter value");
182        assert_eq!(format!("{}", err), "Invalid input: invalid parameter value");
183
184        let err = AnalyticsError::dimension_mismatch("3x3", "4x4");
185        assert_eq!(
186            format!("{}", err),
187            "Dimension mismatch: expected 3x3, got 4x4"
188        );
189    }
190}