ruvector_mincut/
error.rs

1//! Error types for the dynamic minimum cut algorithm
2
3use thiserror::Error;
4
5/// Result type for mincut operations
6pub type Result<T> = std::result::Result<T, MinCutError>;
7
8/// Errors that can occur in minimum cut operations
9#[derive(Error, Debug)]
10pub enum MinCutError {
11    /// Graph is empty
12    #[error("Graph is empty")]
13    EmptyGraph,
14
15    /// Invalid vertex ID
16    #[error("Invalid vertex ID: {0}")]
17    InvalidVertex(u64),
18
19    /// Invalid edge
20    #[error("Invalid edge: ({0}, {1})")]
21    InvalidEdge(u64, u64),
22
23    /// Edge already exists
24    #[error("Edge already exists: ({0}, {1})")]
25    EdgeExists(u64, u64),
26
27    /// Edge not found
28    #[error("Edge not found: ({0}, {1})")]
29    EdgeNotFound(u64, u64),
30
31    /// Graph is disconnected
32    #[error("Graph is disconnected")]
33    DisconnectedGraph,
34
35    /// Cut size exceeds supported limit
36    #[error("Cut size {0} exceeds maximum supported size {1}")]
37    CutSizeExceeded(usize, usize),
38
39    /// Invalid epsilon value for approximate algorithm
40    #[error("Invalid epsilon value: {0} (must be in (0, 1])")]
41    InvalidEpsilon(f64),
42
43    /// Invalid parameter
44    #[error("Invalid parameter: {0}")]
45    InvalidParameter(String),
46
47    /// Monitoring callback failed
48    #[error("Monitoring callback failed: {0}")]
49    CallbackError(String),
50
51    /// Internal algorithm error
52    #[error("Internal algorithm error: {0}")]
53    InternalError(String),
54
55    /// Concurrent modification error
56    #[error("Concurrent modification detected")]
57    ConcurrentModification,
58
59    /// Capacity exceeded
60    #[error("Capacity exceeded: {0}")]
61    CapacityExceeded(String),
62
63    /// Serialization error
64    #[error("Serialization error: {0}")]
65    SerializationError(String),
66}
67
68// From implementations for common error types
69
70impl 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
100// Additional utility methods for MinCutError
101impl MinCutError {
102    /// Check if the error is recoverable
103    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    /// Check if the error indicates a graph structure problem
115    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    /// Check if the error is related to capacity or resource limits
126    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}