use std::{fmt, io};
use httpstatus::StatusCode;
use itertools::Itertools;
use reqwest::Error as ReqwestError;
use serde::{Deserialize, Serialize};
use serde_json::Error as SerdeError;
use url::ParseError as UrlParseError;
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("Error deserializing json: {0}")]
JsonError(#[from] SerdeError),
#[error("Error writing URL query: {0}")]
UrlEncodedError(#[from] serde_urlencoded::ser::Error),
#[error("Error parsing URL: {0}")]
UrlParseError(#[from] UrlParseError),
#[error("Error making request to {url}: {error}")]
ReqwestError {
error: Box<ReqwestError>,
url: url::Url,
},
#[error("Scryfall error: {0}")]
ScryfallError(Box<ScryfallError>),
#[error("HTTP error: {0}")]
HttpError(StatusCode),
#[error("IO error: {0}")]
IoError(#[from] io::Error),
#[error("{0}")]
Other(String),
}
impl From<SerdeError> for Box<Error> {
fn from(err: SerdeError) -> Self {
Box::new(err.into())
}
}
impl From<UrlParseError> for Box<Error> {
fn from(err: UrlParseError) -> Self {
Box::new(err.into())
}
}
#[derive(Serialize, Deserialize, Clone, Eq, PartialEq, Hash, Debug)]
#[cfg_attr(test, serde(deny_unknown_fields))]
pub struct ScryfallError {
pub status: u16,
pub code: String,
pub details: String,
#[serde(rename = "type")]
pub error_type: Option<String>,
#[serde(default)]
pub warnings: Vec<String>,
#[cfg(test)]
#[serde(rename = "object")]
_object: String,
}
impl fmt::Display for ScryfallError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"\n\tdetails:{}{}",
self.details,
if self.warnings.is_empty() {
String::new()
} else {
format!(
"\n\twarnings:\n{}",
self.warnings.iter().map(|w| format!("\t\t{w}")).join("\n")
)
}
)
}
}