Skip to main content

glint_mask_tools/
error.rs

1/// Error types for the glint mask generation library.
2///
3/// This module provides comprehensive error handling using thiserror for
4/// structured error types and anyhow for error context.
5use std::path::PathBuf;
6use thiserror::Error;
7
8/// Main error type for the glint mask generation library
9#[derive(Error, Debug)]
10pub enum GlintError {
11    #[error("IO error: {0}")]
12    Io(#[from] std::io::Error),
13
14    #[error("Image processing error: {0}")]
15    Image(#[from] image::ImageError),
16
17    #[error("Configuration error: {message}")]
18    Config { message: String },
19
20    #[error("Sensor error: {message}")]
21    Sensor { message: String },
22
23    #[error("Invalid file format: {path}")]
24    InvalidFormat { path: PathBuf },
25
26    #[error("Missing required files: {files:?}")]
27    MissingFiles { files: Vec<PathBuf> },
28
29    #[error("Invalid threshold value: {value} (must be between 0.0 and 1.0)")]
30    InvalidThreshold { value: f64 },
31
32    #[error("Invalid bit depth: {bit_depth} (supported: 8, 16, 32)")]
33    InvalidBitDepth { bit_depth: u8 },
34
35    #[error("Dimension mismatch: expected {expected:?}, got {actual:?}")]
36    DimensionMismatch {
37        expected: (u32, u32),
38        actual: (u32, u32),
39    },
40
41    #[error("Band count mismatch: expected {expected}, got {actual}")]
42    BandCountMismatch { expected: usize, actual: usize },
43
44    #[error("Processing error: {message}")]
45    Processing { message: String },
46
47    #[error("Validation error: {message}")]
48    Validation { message: String },
49
50    #[error("Serialization error: {0}")]
51    Serialization(#[from] toml::ser::Error),
52
53    #[error("Deserialization error: {0}")]
54    Deserialization(#[from] toml::de::Error),
55
56    #[error("Pattern matching error: {pattern}")]
57    PatternMatch { pattern: String },
58
59    #[error("Concurrency error: {message}")]
60    Concurrency { message: String },
61
62    #[error("Resource exhaustion: {message}")]
63    ResourceExhaustion { message: String },
64}
65
66/// Convenience Result type for the library
67pub type Result<T> = std::result::Result<T, GlintError>;
68
69impl GlintError {
70    /// Create a new configuration error
71    pub fn config(message: impl Into<String>) -> Self {
72        Self::Config {
73            message: message.into(),
74        }
75    }
76
77    /// Create a new sensor error
78    pub fn sensor(message: impl Into<String>) -> Self {
79        Self::Sensor {
80            message: message.into(),
81        }
82    }
83
84    /// Create a new processing error
85    pub fn processing(message: impl Into<String>) -> Self {
86        Self::Processing {
87            message: message.into(),
88        }
89    }
90
91    /// Create a new validation error
92    pub fn validation(message: impl Into<String>) -> Self {
93        Self::Validation {
94            message: message.into(),
95        }
96    }
97
98    /// Create a new concurrency error
99    pub fn concurrency(message: impl Into<String>) -> Self {
100        Self::Concurrency {
101            message: message.into(),
102        }
103    }
104
105    /// Create a new resource exhaustion error
106    pub fn resource_exhaustion(message: impl Into<String>) -> Self {
107        Self::ResourceExhaustion {
108            message: message.into(),
109        }
110    }
111}
112
113#[cfg(test)]
114mod tests {
115    use super::*;
116
117    #[test]
118    fn test_error_creation() {
119        let error = GlintError::config("test message");
120        assert!(matches!(error, GlintError::Config { .. }));
121    }
122
123    #[test]
124    fn test_error_display() {
125        let error = GlintError::InvalidThreshold { value: 1.5 };
126        let message = error.to_string();
127        assert!(message.contains("1.5"));
128        assert!(message.contains("0.0 and 1.0"));
129    }
130}