Skip to main content

causal_triangulations/
errors.rs

1//! Error types for the CDT library.
2
3use std::fmt;
4
5/// Main error type for CDT operations.
6#[derive(Debug, Clone, PartialEq)]
7pub enum CdtError {
8    /// Invalid triangulation parameters
9    InvalidParameters(String),
10    /// Triangulation generation failed
11    TriangulationGeneration(String),
12    /// Ergodic move failed
13    ErgodicsFailure(String),
14    /// Invalid dimension specified
15    UnsupportedDimension(u32),
16    /// Action calculation error
17    ActionCalculation(String),
18    /// Delaunay triangulation generation failed with detailed context
19    DelaunayGenerationFailed {
20        /// Number of vertices requested for the triangulation
21        vertex_count: u32,
22        /// Coordinate range used for generation
23        coordinate_range: (f64, f64),
24        /// Attempt number when the failure occurred
25        attempt: u32,
26        /// Description of the underlying error that caused the failure
27        underlying_error: String,
28    },
29    /// Invalid generation parameters detected before attempting triangulation
30    InvalidGenerationParameters {
31        /// Description of the specific parameter issue
32        issue: String,
33        /// The actual value that was provided
34        provided_value: String,
35        /// The expected range or constraint for the parameter
36        expected_range: String,
37    },
38    /// Validation of a constructed triangulation failed
39    ValidationFailed {
40        /// Name of the validation check that failed (e.g. "geometry", "topology", "Delaunay")
41        check: String,
42        /// Human-readable description of the failure
43        detail: String,
44    },
45}
46
47impl fmt::Display for CdtError {
48    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49        match self {
50            Self::InvalidParameters(msg) => write!(f, "Invalid parameters: {msg}"),
51            Self::TriangulationGeneration(msg) => {
52                write!(f, "Triangulation generation failed: {msg}")
53            }
54            Self::ErgodicsFailure(msg) => write!(f, "Ergodic move failed: {msg}"),
55            Self::UnsupportedDimension(dim) => write!(
56                f,
57                "Unsupported dimension: {dim}. Only 2D is currently supported"
58            ),
59            Self::ActionCalculation(msg) => write!(f, "Action calculation error: {msg}"),
60            Self::DelaunayGenerationFailed {
61                vertex_count,
62                coordinate_range,
63                attempt,
64                underlying_error,
65            } => write!(
66                f,
67                "Delaunay triangulation generation failed: {vertex_count} vertices, range [{}, {}], attempt {attempt}: {underlying_error}",
68                coordinate_range.0, coordinate_range.1
69            ),
70            Self::InvalidGenerationParameters {
71                issue,
72                provided_value,
73                expected_range,
74            } => write!(
75                f,
76                "Invalid triangulation parameters: {issue} (got: {provided_value}, expected: {expected_range})",
77            ),
78            Self::ValidationFailed { check, detail } => {
79                write!(f, "Validation failed [{check}]: {detail}")
80            }
81        }
82    }
83}
84
85impl std::error::Error for CdtError {}
86
87/// Result type for CDT operations.
88pub type CdtResult<T> = Result<T, CdtError>;
89
90#[cfg(test)]
91mod tests {
92    use super::*;
93
94    #[test]
95    fn test_invalid_parameters_error() {
96        let error = CdtError::InvalidParameters("Test message".to_string());
97        let display = format!("{error}");
98        assert_eq!(display, "Invalid parameters: Test message");
99    }
100
101    #[test]
102    fn test_triangulation_generation_error() {
103        let error = CdtError::TriangulationGeneration("Generation failed".to_string());
104        let display = format!("{error}");
105        assert_eq!(
106            display,
107            "Triangulation generation failed: Generation failed"
108        );
109    }
110
111    #[test]
112    fn test_ergodics_failure_error() {
113        let error = CdtError::ErgodicsFailure("Move rejected".to_string());
114        let display = format!("{error}");
115        assert_eq!(display, "Ergodic move failed: Move rejected");
116    }
117
118    #[test]
119    fn test_unsupported_dimension_error() {
120        let error = CdtError::UnsupportedDimension(3);
121        let display = format!("{error}");
122        assert_eq!(
123            display,
124            "Unsupported dimension: 3. Only 2D is currently supported"
125        );
126    }
127
128    #[test]
129    fn test_action_calculation_error() {
130        let error = CdtError::ActionCalculation("NaN result".to_string());
131        let display = format!("{error}");
132        assert_eq!(display, "Action calculation error: NaN result");
133    }
134
135    #[test]
136    fn test_delaunay_generation_failed_error() {
137        let error = CdtError::DelaunayGenerationFailed {
138            vertex_count: 10,
139            coordinate_range: (-1.0, 1.0),
140            attempt: 5,
141            underlying_error: "Too many duplicate points".to_string(),
142        };
143        let display = format!("{error}");
144        assert_eq!(
145            display,
146            "Delaunay triangulation generation failed: 10 vertices, range [-1, 1], attempt 5: Too many duplicate points"
147        );
148    }
149
150    #[test]
151    fn test_invalid_generation_parameters_error() {
152        let error = CdtError::InvalidGenerationParameters {
153            issue: "Vertex count too small".to_string(),
154            provided_value: "2".to_string(),
155            expected_range: "at least 3".to_string(),
156        };
157        let display = format!("{error}");
158        assert_eq!(
159            display,
160            "Invalid triangulation parameters: Vertex count too small (got: 2, expected: at least 3)"
161        );
162    }
163
164    #[test]
165    fn test_validation_failed_error() {
166        let error = CdtError::ValidationFailed {
167            check: "topology".to_string(),
168            detail: "Euler characteristic χ=3 unexpected (V=5, E=8, F=6)".to_string(),
169        };
170        let display = format!("{error}");
171        assert_eq!(
172            display,
173            "Validation failed [topology]: Euler characteristic χ=3 unexpected (V=5, E=8, F=6)"
174        );
175    }
176
177    #[test]
178    fn test_error_equality() {
179        let error1 = CdtError::InvalidParameters("Test".to_string());
180        let error2 = CdtError::InvalidParameters("Test".to_string());
181        let error3 = CdtError::InvalidParameters("Different".to_string());
182
183        assert_eq!(error1, error2);
184        assert_ne!(error1, error3);
185    }
186
187    #[test]
188    fn test_error_clone() {
189        let error = CdtError::UnsupportedDimension(4);
190        let cloned = error.clone();
191        assert_eq!(error, cloned);
192    }
193
194    #[test]
195    fn test_error_debug() {
196        let error = CdtError::InvalidParameters("Debug test".to_string());
197        let debug_str = format!("{error:?}");
198        assert!(debug_str.contains("InvalidParameters"));
199        assert!(debug_str.contains("Debug test"));
200    }
201
202    #[test]
203    fn test_cdt_result_type() {
204        let success: CdtResult<i32> = Ok(42);
205        let failure: CdtResult<i32> = Err(CdtError::InvalidParameters("Test".to_string()));
206
207        assert!(success.is_ok());
208        assert!(failure.is_err());
209        assert_eq!(success, Ok(42));
210    }
211
212    #[test]
213    fn test_error_is_send_sync() {
214        fn assert_send_sync<T: Send + Sync>() {}
215        assert_send_sync::<CdtError>();
216    }
217
218    #[test]
219    fn test_std_error_trait() {
220        let error = CdtError::InvalidParameters("Test error".to_string());
221        let _: &dyn std::error::Error = &error;
222        // If this compiles, the trait is implemented correctly
223    }
224}