use thiserror::Error;
pub type Result<T> = std::result::Result<T, CjvError>;
#[derive(Error, Debug)]
pub enum CjvError {
#[error("Network error: {0}")]
Network(#[from] reqwest::Error),
#[error("IO error: {0}")]
Io(#[from] std::io::Error),
#[error("Serialization error: {0}")]
Serde(#[from] serde_json::Error),
#[error("TOML parsing error: {0}")]
Toml(#[from] toml::de::Error),
#[error("TOML serialization error: {0}")]
TomlSer(#[from] toml::ser::Error),
#[error("Zip error: {0}")]
Zip(#[from] zip::result::ZipError),
#[error("Not found: {0}")]
NotFound(String),
#[error("Already exists: {0}")]
AlreadyExists(String),
#[error("Invalid argument: {0}")]
InvalidArgument(String),
#[error("Toolchain '{0}' not installed")]
ToolchainNotInstalled(String),
#[error("Unsupported platform: {0}")]
UnsupportedPlatform(String),
#[error("Checksum mismatch: expected {expected}, got {actual}")]
ChecksumMismatch { expected: String, actual: String },
#[error("Download failed: {0}")]
DownloadFailed(String),
#[error("Extraction failed: {0}")]
ExtractionFailed(String),
#[error("Proxy error: {0}")]
Proxy(String),
#[error("{0}")]
Other(String),
}
impl CjvError {
pub fn exit_code(&self) -> u8 {
match self {
CjvError::NotFound(_) => 2,
CjvError::InvalidArgument(_) => 3,
CjvError::ToolchainNotInstalled(_) => 4,
_ => 1,
}
}
}
impl From<&str> for CjvError {
fn from(s: &str) -> Self {
CjvError::Other(s.to_string())
}
}
impl From<String> for CjvError {
fn from(s: String) -> Self {
CjvError::Other(s)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn stable_exit_codes_for_common_failures() {
assert_eq!(CjvError::NotFound("x".to_string()).exit_code(), 2);
assert_eq!(CjvError::InvalidArgument("x".to_string()).exit_code(), 3);
assert_eq!(
CjvError::ToolchainNotInstalled("x".to_string()).exit_code(),
4
);
assert_eq!(CjvError::Other("x".to_string()).exit_code(), 1);
}
}