use std::fmt;
#[derive(Debug)]
pub struct Error(ErrorKind);
#[derive(Debug)]
pub(crate) enum ErrorKind {
Sqlite(rusqlite::Error),
InvalidDatabase(std::path::PathBuf),
#[cfg(feature = "builder")]
Io(std::io::Error),
#[cfg(feature = "builder")]
Json(serde_json::Error),
#[cfg(feature = "builder")]
Http(reqwest::Error),
#[cfg(feature = "builder")]
HttpStatus { url: String, status: u16 },
#[cfg(feature = "builder")]
Zip(zip::result::ZipError),
#[cfg(feature = "builder")]
Data(String),
}
impl Error {
pub(crate) fn invalid_database(path: std::path::PathBuf) -> Self {
Error(ErrorKind::InvalidDatabase(path))
}
#[cfg(feature = "builder")]
pub(crate) fn data(message: impl Into<String>) -> Self {
Error(ErrorKind::Data(message.into()))
}
#[cfg(feature = "builder")]
pub(crate) fn http_status(url: impl Into<String>, status: u16) -> Self {
Error(ErrorKind::HttpStatus {
url: url.into(),
status,
})
}
#[allow(dead_code)]
pub(crate) fn kind(&self) -> &ErrorKind {
&self.0
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.0 {
ErrorKind::InvalidDatabase(path) => {
write!(f, "invalid SQLite database: {}", path.display())
}
ErrorKind::Sqlite(err) => write!(f, "SQLite error: {err}"),
#[cfg(feature = "builder")]
ErrorKind::Io(err) => write!(f, "I/O error: {err}"),
#[cfg(feature = "builder")]
ErrorKind::Json(err) => write!(f, "JSON error: {err}"),
#[cfg(feature = "builder")]
ErrorKind::Http(err) => write!(f, "HTTP error: {err}"),
#[cfg(feature = "builder")]
ErrorKind::HttpStatus { url, status } => {
write!(f, "{url} responded with status {status}")
}
#[cfg(feature = "builder")]
ErrorKind::Zip(err) => write!(f, "Zip error: {err}"),
#[cfg(feature = "builder")]
ErrorKind::Data(message) => write!(f, "malformed SDE record: {message}"),
}
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match &self.0 {
ErrorKind::InvalidDatabase(_) => None,
ErrorKind::Sqlite(err) => Some(err),
#[cfg(feature = "builder")]
ErrorKind::Io(err) => Some(err),
#[cfg(feature = "builder")]
ErrorKind::Json(err) => Some(err),
#[cfg(feature = "builder")]
ErrorKind::Http(err) => Some(err),
#[cfg(feature = "builder")]
ErrorKind::Zip(err) => Some(err),
#[cfg(feature = "builder")]
ErrorKind::HttpStatus { .. } | ErrorKind::Data(_) => None,
}
}
}
impl From<rusqlite::Error> for Error {
fn from(err: rusqlite::Error) -> Self {
Error(ErrorKind::Sqlite(err))
}
}
#[cfg(feature = "builder")]
impl From<std::io::Error> for Error {
fn from(err: std::io::Error) -> Self {
Error(ErrorKind::Io(err))
}
}
#[cfg(feature = "builder")]
impl From<serde_json::Error> for Error {
fn from(err: serde_json::Error) -> Self {
Error(ErrorKind::Json(err))
}
}
#[cfg(feature = "builder")]
impl From<reqwest::Error> for Error {
fn from(err: reqwest::Error) -> Self {
Error(ErrorKind::Http(err))
}
}
#[cfg(feature = "builder")]
impl From<zip::result::ZipError> for Error {
fn from(err: zip::result::ZipError) -> Self {
Error(ErrorKind::Zip(err))
}
}