libspot_rs/
error.rs

1//! Error types for the SPOT algorithm implementation
2//!
3//! This module defines error types that match the C implementation exactly.
4
5use std::fmt;
6
7/// Result type for SPOT operations
8pub type SpotResult<T> = Result<T, SpotError>;
9
10/// Error codes that match the C implementation
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub enum SpotError {
13    /// Memory allocation failed
14    MemoryAllocationFailed = 1000,
15    /// The level parameter must be between 0 and 1
16    LevelOutOfBounds = 1001,
17    /// The q parameter must be between 0 and 1-level
18    QOutOfBounds = 1002,
19    /// The excess threshold has not been initialized
20    ExcessThresholdIsNaN = 1003,
21    /// The anomaly threshold has not been initialized
22    AnomalyThresholdIsNaN = 1004,
23    /// The input data is NaN
24    DataIsNaN = 1005,
25}
26
27impl SpotError {
28    /// Convert from C error code
29    pub fn from_code(code: i32) -> Self {
30        match code.abs() {
31            1000 => SpotError::MemoryAllocationFailed,
32            1001 => SpotError::LevelOutOfBounds,
33            1002 => SpotError::QOutOfBounds,
34            1003 => SpotError::ExcessThresholdIsNaN,
35            1004 => SpotError::AnomalyThresholdIsNaN,
36            1005 => SpotError::DataIsNaN,
37            _ => SpotError::MemoryAllocationFailed, // Default fallback
38        }
39    }
40
41    /// Get error message
42    pub fn message(&self) -> &'static str {
43        match self {
44            SpotError::MemoryAllocationFailed => "Memory allocation failed",
45            SpotError::LevelOutOfBounds => {
46                "The level parameter is out of bounds (it must be between 0 and 1, but close to 1)"
47            }
48            SpotError::QOutOfBounds => "The q parameter must between 0 and 1-level",
49            SpotError::ExcessThresholdIsNaN => "The excess threshold has not been initialized",
50            SpotError::AnomalyThresholdIsNaN => "The anomaly threshold has not been initialized",
51            SpotError::DataIsNaN => "The input data is NaN",
52        }
53    }
54
55    /// Get error code
56    pub fn code(&self) -> i32 {
57        *self as i32
58    }
59}
60
61impl fmt::Display for SpotError {
62    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
63        write!(f, "{}", self.message())
64    }
65}
66
67impl std::error::Error for SpotError {}
68
69#[cfg(test)]
70mod tests {
71    use super::*;
72
73    #[test]
74    fn test_error_codes_match_c() {
75        assert_eq!(SpotError::MemoryAllocationFailed.code(), 1000);
76        assert_eq!(SpotError::LevelOutOfBounds.code(), 1001);
77        assert_eq!(SpotError::QOutOfBounds.code(), 1002);
78        assert_eq!(SpotError::ExcessThresholdIsNaN.code(), 1003);
79        assert_eq!(SpotError::AnomalyThresholdIsNaN.code(), 1004);
80        assert_eq!(SpotError::DataIsNaN.code(), 1005);
81    }
82
83    #[test]
84    fn test_from_code() {
85        assert_eq!(
86            SpotError::from_code(-1000),
87            SpotError::MemoryAllocationFailed
88        );
89        assert_eq!(SpotError::from_code(-1001), SpotError::LevelOutOfBounds);
90        assert_eq!(SpotError::from_code(-1002), SpotError::QOutOfBounds);
91        assert_eq!(SpotError::from_code(-1003), SpotError::ExcessThresholdIsNaN);
92        assert_eq!(
93            SpotError::from_code(-1004),
94            SpotError::AnomalyThresholdIsNaN
95        );
96        assert_eq!(SpotError::from_code(-1005), SpotError::DataIsNaN);
97    }
98
99    #[test]
100    fn test_error_messages() {
101        assert_eq!(
102            SpotError::MemoryAllocationFailed.message(),
103            "Memory allocation failed"
104        );
105        assert_eq!(
106            SpotError::LevelOutOfBounds.message(),
107            "The level parameter is out of bounds (it must be between 0 and 1, but close to 1)"
108        );
109    }
110
111    #[test]
112    fn test_error_display() {
113        let error = SpotError::DataIsNaN;
114        assert_eq!(format!("{}", error), "The input data is NaN");
115    }
116}