use thiserror::Error;
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum Error {
#[error("bad argument `{param_name}`: {desc}")]
BadArgument {
param_name: String,
desc: String,
},
#[error("I/O error: {0:?}")]
Io(#[from] std::io::Error),
#[cfg(feature = "historical")]
#[error("HTTP error: {0:?}")]
Http(#[from] reqwest::Error),
#[cfg(feature = "historical")]
#[error("API error: {0}")]
Api(ApiError),
#[error("internal error: {0}")]
Internal(String),
#[error("DBN error: {0}")]
Dbn(#[source] dbn::Error),
#[error("authentication failed: {0}")]
Auth(String),
}
pub type Result<T> = std::result::Result<T, Error>;
#[cfg(feature = "historical")]
#[derive(Debug)]
pub struct ApiError {
pub request_id: Option<String>,
pub status_code: reqwest::StatusCode,
pub message: String,
pub docs_url: Option<String>,
}
impl Error {
pub(crate) fn bad_arg(param_name: impl ToString, desc: impl ToString) -> Self {
Self::BadArgument {
param_name: param_name.to_string(),
desc: desc.to_string(),
}
}
pub(crate) fn internal(msg: impl ToString) -> Self {
Self::Internal(msg.to_string())
}
}
impl From<dbn::Error> for Error {
fn from(dbn_err: dbn::Error) -> Self {
match dbn_err {
dbn::Error::Io { source, .. } => Self::Io(source),
dbn_err => Self::Dbn(dbn_err),
}
}
}
#[cfg(feature = "historical")]
impl std::fmt::Display for ApiError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let doc = if let Some(ref docs_url) = self.docs_url {
format!(" See {docs_url} for documentation.")
} else {
String::new()
};
let status = self.status_code;
let msg = &self.message;
if let Some(ref request_id) = self.request_id {
write!(f, "{request_id} failed with {status} {msg}{doc}")
} else {
write!(f, "{status} {msg}{doc}")
}
}
}