use thiserror::Error;
#[derive(Error, Debug, Clone)]
pub enum GraphinaError {
#[error("Graphina error: {0}")]
Generic(String),
#[error("Node not found: {0}")]
NodeNotFound(String),
#[error("Edge not found: {0}")]
EdgeNotFound(String),
#[error("No path exists: {0}")]
NoPath(String),
#[error("No cycle exists: {0}")]
NoCycle(String),
#[error("Graph has a cycle: {0}")]
HasCycle(String),
#[error("Invalid graph: {0}")]
InvalidGraph(String),
#[error("Algorithm error: {0}")]
AlgorithmError(String),
#[error("No feasible solution: {0}")]
Unfeasible(String),
#[error("Unbounded solution: {0}")]
Unbounded(String),
#[error("Not implemented: {0}")]
NotImplemented(String),
#[error("Ambiguous solution: {0}")]
AmbiguousSolution(String),
#[error("Exceeded max iterations ({iterations}): {message}")]
ExceededMaxIterations {
iterations: usize,
message: String,
},
#[error("Convergence failed after {iterations} iterations: {message}")]
ConvergenceFailed {
iterations: usize,
message: String,
},
#[error("I/O error: {0}")]
IoError(String),
#[error("Serialization error: {0}")]
SerializationError(String),
#[error("Invalid argument: {0}")]
InvalidArgument(String),
#[error("Pointless concept: {0}")]
PointlessConcept(String),
}
pub type Result<T> = std::result::Result<T, GraphinaError>;
impl GraphinaError {
pub fn generic(message: impl Into<String>) -> Self {
GraphinaError::Generic(message.into())
}
pub fn node_not_found(message: impl Into<String>) -> Self {
GraphinaError::NodeNotFound(message.into())
}
pub fn edge_not_found(message: impl Into<String>) -> Self {
GraphinaError::EdgeNotFound(message.into())
}
pub fn no_path(message: impl Into<String>) -> Self {
GraphinaError::NoPath(message.into())
}
pub fn invalid_graph(message: impl Into<String>) -> Self {
GraphinaError::InvalidGraph(message.into())
}
pub fn algorithm_error(message: impl Into<String>) -> Self {
GraphinaError::AlgorithmError(message.into())
}
pub fn convergence_failed(iterations: usize, message: impl Into<String>) -> Self {
GraphinaError::ConvergenceFailed {
iterations,
message: message.into(),
}
}
pub fn invalid_argument(message: impl Into<String>) -> Self {
GraphinaError::InvalidArgument(message.into())
}
pub fn not_implemented(message: impl Into<String>) -> Self {
GraphinaError::NotImplemented(message.into())
}
pub fn has_cycle(message: impl Into<String>) -> Self {
GraphinaError::HasCycle(message.into())
}
pub fn no_cycle(message: impl Into<String>) -> Self {
GraphinaError::NoCycle(message.into())
}
pub fn unfeasible(message: impl Into<String>) -> Self {
GraphinaError::Unfeasible(message.into())
}
pub fn pointless_concept(message: impl Into<String>) -> Self {
GraphinaError::PointlessConcept(message.into())
}
}
impl From<std::io::Error> for GraphinaError {
fn from(e: std::io::Error) -> Self {
GraphinaError::IoError(e.to_string())
}
}
impl From<serde_json::Error> for GraphinaError {
fn from(e: serde_json::Error) -> Self {
GraphinaError::SerializationError(e.to_string())
}
}
impl From<bincode::error::EncodeError> for GraphinaError {
fn from(e: bincode::error::EncodeError) -> Self {
GraphinaError::SerializationError(e.to_string())
}
}
impl From<bincode::error::DecodeError> for GraphinaError {
fn from(e: bincode::error::DecodeError) -> Self {
GraphinaError::SerializationError(e.to_string())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_error_display() {
let err = GraphinaError::generic("test error");
assert_eq!(err.to_string(), "Graphina error: test error");
}
#[test]
fn test_node_not_found() {
let err = GraphinaError::node_not_found("Node 5");
assert_eq!(err.to_string(), "Node not found: Node 5");
}
#[test]
fn test_convergence_failed() {
let err = GraphinaError::convergence_failed(100, "tolerance not met");
assert!(err.to_string().contains("100 iterations"));
assert!(err.to_string().contains("tolerance not met"));
}
#[test]
fn test_error_is_clonable() {
let err = GraphinaError::generic("test");
let cloned = err.clone();
assert_eq!(err.to_string(), cloned.to_string());
}
#[test]
fn test_result_alias() {
fn returns_result() -> Result<i32> {
Ok(42)
}
assert_eq!(returns_result().unwrap(), 42);
}
}