use std::path::PathBuf;
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("Authentication failed: {0}")]
Authentication(String),
#[error("Access forbidden: {0}")]
Forbidden(String),
#[error("Resource not found: {0}")]
NotFound(String),
#[error("Rate limit exceeded")]
RateLimit,
#[error("API error ({status}): {message}")]
Api { status: u16, message: String },
#[error("Not logged in — run `hy login` first")]
NotLoggedIn,
#[allow(dead_code)]
#[error("Credentials not found: {0}")]
CredentialsNotFound(String),
#[error("OAuth flow failed: {0}")]
OAuthFailed(String),
#[error("No space left on device at {path}")]
NoSpace {
path: PathBuf,
required: Option<u64>,
available: Option<u64>,
},
#[error("File not found: {0}")]
FileNotFound(PathBuf),
#[error("I/O error: {0}")]
Io(#[from] std::io::Error),
#[error("Plugin already installed: {0}")]
PluginAlreadyInstalled(String),
#[error("Plugin not installed: {0}")]
PluginNotInstalled(String),
#[error("Platform incompatible: {0}")]
PlatformIncompatible(String),
#[error("IDA version incompatible: {0}")]
IdaVersionIncompatible(String),
#[error("Invalid plugin name: {0}")]
InvalidPluginName(String),
#[error("Plugin installation error: {0}")]
PluginInstall(String),
#[allow(dead_code)]
#[error("IDA installation not found")]
IdaNotFound,
#[error("IDA installation failed: {0}")]
IdaInstallFailed(String),
#[error("Update failed: {0}")]
UpdateFailed(String),
#[error("JSON error: {0}")]
Json(#[from] serde_json::Error),
#[error("HTTP error: {0}")]
Http(#[from] reqwest::Error),
#[error("ZIP error: {0}")]
Zip(#[from] zip::result::ZipError),
#[error("{0}")]
Other(String),
}
pub type Result<T, E = Error> = std::result::Result<T, E>;
impl Error {
pub fn from_status(status: u16, body: &str) -> Self {
match status {
401 => Self::Authentication("Authentication failed".into()),
403 => Self::Forbidden("Access forbidden".into()),
404 => Self::NotFound("Resource not found".into()),
429 => Self::RateLimit,
_ => {
let message = serde_json::from_str::<serde_json::Value>(body)
.ok()
.and_then(|v| v.get("message")?.as_str().map(String::from))
.unwrap_or_else(|| format!("HTTP {status}"));
Self::Api { status, message }
}
}
}
}