1use thiserror::Error;
4
5pub type Result<T> = std::result::Result<T, MinCutError>;
7
8#[derive(Error, Debug)]
10pub enum MinCutError {
11 #[error("Graph is empty")]
13 EmptyGraph,
14
15 #[error("Invalid vertex ID: {0}")]
17 InvalidVertex(u64),
18
19 #[error("Invalid edge: ({0}, {1})")]
21 InvalidEdge(u64, u64),
22
23 #[error("Edge already exists: ({0}, {1})")]
25 EdgeExists(u64, u64),
26
27 #[error("Edge not found: ({0}, {1})")]
29 EdgeNotFound(u64, u64),
30
31 #[error("Graph is disconnected")]
33 DisconnectedGraph,
34
35 #[error("Cut size {0} exceeds maximum supported size {1}")]
37 CutSizeExceeded(usize, usize),
38
39 #[error("Invalid epsilon value: {0} (must be in (0, 1])")]
41 InvalidEpsilon(f64),
42
43 #[error("Invalid parameter: {0}")]
45 InvalidParameter(String),
46
47 #[error("Monitoring callback failed: {0}")]
49 CallbackError(String),
50
51 #[error("Internal algorithm error: {0}")]
53 InternalError(String),
54
55 #[error("Concurrent modification detected")]
57 ConcurrentModification,
58
59 #[error("Capacity exceeded: {0}")]
61 CapacityExceeded(String),
62
63 #[error("Serialization error: {0}")]
65 SerializationError(String),
66}
67
68impl From<std::io::Error> for MinCutError {
71 fn from(err: std::io::Error) -> Self {
72 MinCutError::SerializationError(err.to_string())
73 }
74}
75
76impl From<serde_json::Error> for MinCutError {
77 fn from(err: serde_json::Error) -> Self {
78 MinCutError::SerializationError(err.to_string())
79 }
80}
81
82impl From<std::fmt::Error> for MinCutError {
83 fn from(err: std::fmt::Error) -> Self {
84 MinCutError::InternalError(err.to_string())
85 }
86}
87
88impl From<String> for MinCutError {
89 fn from(msg: String) -> Self {
90 MinCutError::InternalError(msg)
91 }
92}
93
94impl From<&str> for MinCutError {
95 fn from(msg: &str) -> Self {
96 MinCutError::InternalError(msg.to_string())
97 }
98}
99
100impl MinCutError {
102 pub fn is_recoverable(&self) -> bool {
104 matches!(
105 self,
106 MinCutError::InvalidVertex(_)
107 | MinCutError::InvalidEdge(_, _)
108 | MinCutError::EdgeNotFound(_, _)
109 | MinCutError::EdgeExists(_, _)
110 | MinCutError::InvalidEpsilon(_)
111 )
112 }
113
114 pub fn is_graph_structure_error(&self) -> bool {
116 matches!(
117 self,
118 MinCutError::EmptyGraph
119 | MinCutError::DisconnectedGraph
120 | MinCutError::InvalidVertex(_)
121 | MinCutError::InvalidEdge(_, _)
122 )
123 }
124
125 pub fn is_resource_error(&self) -> bool {
127 matches!(
128 self,
129 MinCutError::CutSizeExceeded(_, _) | MinCutError::CapacityExceeded(_)
130 )
131 }
132}
133
134#[cfg(test)]
135mod tests {
136 use super::*;
137
138 #[test]
139 fn test_error_display() {
140 let err = MinCutError::InvalidVertex(42);
141 assert_eq!(err.to_string(), "Invalid vertex ID: 42");
142
143 let err = MinCutError::InvalidEdge(1, 2);
144 assert_eq!(err.to_string(), "Invalid edge: (1, 2)");
145
146 let err = MinCutError::EmptyGraph;
147 assert_eq!(err.to_string(), "Graph is empty");
148 }
149
150 #[test]
151 fn test_error_from_string() {
152 let err: MinCutError = "test error".into();
153 assert!(matches!(err, MinCutError::InternalError(_)));
154 assert_eq!(err.to_string(), "Internal algorithm error: test error");
155 }
156
157 #[test]
158 fn test_is_recoverable() {
159 assert!(MinCutError::InvalidVertex(1).is_recoverable());
160 assert!(MinCutError::EdgeNotFound(1, 2).is_recoverable());
161 assert!(!MinCutError::EmptyGraph.is_recoverable());
162 assert!(!MinCutError::InternalError("test".to_string()).is_recoverable());
163 }
164
165 #[test]
166 fn test_is_graph_structure_error() {
167 assert!(MinCutError::EmptyGraph.is_graph_structure_error());
168 assert!(MinCutError::InvalidVertex(1).is_graph_structure_error());
169 assert!(MinCutError::DisconnectedGraph.is_graph_structure_error());
170 assert!(!MinCutError::CallbackError("test".to_string()).is_graph_structure_error());
171 }
172
173 #[test]
174 fn test_is_resource_error() {
175 assert!(MinCutError::CutSizeExceeded(100, 50).is_resource_error());
176 assert!(MinCutError::CapacityExceeded("test".to_string()).is_resource_error());
177 assert!(!MinCutError::EmptyGraph.is_resource_error());
178 }
179
180 #[test]
181 fn test_serde_json_error_conversion() {
182 let json_err = serde_json::from_str::<Vec<u32>>("invalid json");
183 assert!(json_err.is_err());
184 let mincut_err: MinCutError = json_err.unwrap_err().into();
185 assert!(matches!(mincut_err, MinCutError::SerializationError(_)));
186 }
187}