use homedir::GetHomeError; use reqwest::{Error as ReqwestError, Url}; use serde_json::Error as JsonError; use std::fmt; use std::io; use std::path::PathBuf; pub type AppResult = Result; #[derive(Debug)] pub enum AppError { ConfigFileNotFound(PathBuf), ConfigFileNotProvided, ConfigParseError { source: JsonError, path: PathBuf }, IoError(io::Error), RequestFailed { url: Url, source: ReqwestError }, InvalidResponse { url: Url, reason: String }, UnableToGetHomeDirectory(GetHomeError), } impl fmt::Display for AppError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Self::ConfigFileNotFound(path) => { write!(f, "Config file not found: {}", path.display()) } Self::ConfigFileNotProvided => { write!(f, "Config file not provided") } Self::IoError(err) => write!(f, "I/O error: {}", err), Self::ConfigParseError { path, .. } => { write!(f, "Failed to parse config at {}", path.display()) } Self::RequestFailed { url, .. } => write!(f, "Request to {} failed", url), Self::InvalidResponse { url, reason } => { write!(f, "Invalid response from {}: {}", url, reason) } Self::UnableToGetHomeDirectory(err) => { write!(f, "Failed to get home directory: {}", err) } } } } impl std::error::Error for AppError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match self { Self::IoError(err) => Some(err), Self::ConfigParseError { source, .. } => Some(source), Self::RequestFailed { source, .. } => Some(source), _ => None, } } } // Convenient conversions from library errors impl From for AppError { fn from(err: io::Error) -> Self { Self::IoError(err) } } impl From for AppError { fn from(err: ReqwestError) -> Self { let url = match err.url() { Some(url) => url.clone(), None => Url::parse("http://unknown.url").unwrap(), }; Self::RequestFailed { url, source: err } } } impl From for AppError { fn from(err: JsonError) -> Self { Self::ConfigParseError { source: err, path: PathBuf::from("unknown"), // Default path } } }