1use thiserror::Error;
3
4#[derive(Debug, Error)]
6#[non_exhaustive]
7pub enum Error {
8 #[error("bad argument `{param_name}`: {desc}")]
10 BadArgument {
11 param_name: &'static str,
13 desc: String,
15 },
16 #[error("I/O error: {0:?}")]
18 Io(#[from] std::io::Error),
19 #[cfg(feature = "historical")]
21 #[error("HTTP error: {0:?}")]
22 Http(#[from] reqwest::Error),
23 #[cfg(feature = "historical")]
25 #[error("JSON error: {0:?}")]
26 Json(#[from] serde_json::Error),
27 #[cfg(feature = "historical")]
29 #[error("invalid UTF-8: {0:?}")]
30 Utf8(#[from] std::str::Utf8Error),
31 #[cfg(feature = "historical")]
33 #[error("API error: {0}")]
34 Api(ApiError),
35 #[error("internal error: {0}")]
37 Internal(String),
38 #[error("DBN error: {0}")]
40 Dbn(#[source] dbn::Error),
41 #[error("authentication failed: {0}")]
43 Auth(String),
44}
45pub type Result<T> = std::result::Result<T, Error>;
47
48#[cfg(feature = "historical")]
50#[derive(Debug)]
51pub struct ApiError {
52 pub request_id: Option<String>,
54 pub status_code: reqwest::StatusCode,
56 pub message: String,
58 pub docs_url: Option<String>,
60}
61
62impl Error {
63 pub(crate) fn bad_arg(param_name: &'static str, desc: impl ToString) -> Self {
64 Self::BadArgument {
65 param_name,
66 desc: desc.to_string(),
67 }
68 }
69
70 pub(crate) fn internal(msg: impl ToString) -> Self {
71 Self::Internal(msg.to_string())
72 }
73}
74
75impl From<dbn::Error> for Error {
76 fn from(dbn_err: dbn::Error) -> Self {
77 match dbn_err {
78 dbn::Error::Io { source, .. } => Self::Io(source),
80 dbn_err => Self::Dbn(dbn_err),
81 }
82 }
83}
84
85#[cfg(feature = "historical")]
86impl std::fmt::Display for ApiError {
87 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
88 let doc = if let Some(ref docs_url) = self.docs_url {
89 format!(" See {docs_url} for documentation.")
90 } else {
91 String::new()
92 };
93 let status = self.status_code;
94 let msg = &self.message;
95 if let Some(ref request_id) = self.request_id {
96 write!(f, "{request_id} failed with {status} {msg}{doc}")
97 } else {
98 write!(f, "{status} {msg}{doc}")
99 }
100 }
101}