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