#[derive(Debug, derive_more::Display, derive_more::Error, derive_getters::Getters)]
#[display("HTTP request failed: {}", source)]
pub struct HttpError {
source: reqwest::Error,
line: u32,
file: &'static str,
}
impl HttpError {
#[track_caller]
pub fn new(source: reqwest::Error) -> Self {
let loc = std::panic::Location::caller();
Self {
source,
line: loc.line(),
file: loc.file(),
}
}
}
impl From<reqwest::Error> for HttpError {
#[track_caller]
fn from(source: reqwest::Error) -> Self {
Self::new(source)
}
}
#[derive(Debug, derive_more::Display, derive_more::Error, derive_getters::Getters)]
#[display("JSON error: {}", source)]
pub struct JsonError {
source: serde_json::Error,
line: u32,
file: &'static str,
}
impl JsonError {
#[track_caller]
pub fn new(source: serde_json::Error) -> Self {
let loc = std::panic::Location::caller();
Self {
source,
line: loc.line(),
file: loc.file(),
}
}
}
impl From<serde_json::Error> for JsonError {
#[track_caller]
fn from(source: serde_json::Error) -> Self {
Self::new(source)
}
}
#[derive(Debug, derive_more::Display, derive_more::Error, derive_getters::Getters)]
#[display("Invalid URL: {}", source)]
pub struct UrlError {
source: url::ParseError,
line: u32,
file: &'static str,
}
impl UrlError {
#[track_caller]
pub fn new(source: url::ParseError) -> Self {
let loc = std::panic::Location::caller();
Self {
source,
line: loc.line(),
file: loc.file(),
}
}
}
impl From<url::ParseError> for UrlError {
#[track_caller]
fn from(source: url::ParseError) -> Self {
Self::new(source)
}
}
#[derive(Debug, derive_more::Display, derive_more::Error, derive_getters::Getters)]
#[display("I/O error: {}", source)]
pub struct IoError {
source: std::io::Error,
line: u32,
file: &'static str,
}
impl IoError {
#[track_caller]
pub fn new(source: std::io::Error) -> Self {
let loc = std::panic::Location::caller();
Self {
source,
line: loc.line(),
file: loc.file(),
}
}
}
impl From<std::io::Error> for IoError {
#[track_caller]
fn from(source: std::io::Error) -> Self {
Self::new(source)
}
}
#[derive(Debug, derive_more::Display, derive_more::Error, derive_getters::Getters)]
#[display("URL encoding error: {}", source)]
pub struct UrlEncodedError {
source: serde_urlencoded::ser::Error,
line: u32,
file: &'static str,
}
impl UrlEncodedError {
#[track_caller]
pub fn new(source: serde_urlencoded::ser::Error) -> Self {
let loc = std::panic::Location::caller();
Self {
source,
line: loc.line(),
file: loc.file(),
}
}
}
impl From<serde_urlencoded::ser::Error> for UrlEncodedError {
#[track_caller]
fn from(source: serde_urlencoded::ser::Error) -> Self {
Self::new(source)
}
}
#[derive(Debug, derive_more::Display, derive_more::Error, derive_getters::Getters)]
#[display("Environment variable error: {}", source)]
pub struct EnvError {
source: std::env::VarError,
line: u32,
file: &'static str,
}
impl EnvError {
#[track_caller]
pub fn new(source: std::env::VarError) -> Self {
let loc = std::panic::Location::caller();
Self {
source,
line: loc.line(),
file: loc.file(),
}
}
}
impl From<std::env::VarError> for EnvError {
#[track_caller]
fn from(source: std::env::VarError) -> Self {
Self::new(source)
}
}
#[derive(Debug, derive_more::Display, derive_more::Error, derive_getters::Getters)]
#[display("Builder error: {}", message)]
pub struct BuilderError {
message: String,
line: u32,
file: &'static str,
}
impl BuilderError {
#[track_caller]
pub fn new(message: impl Into<String>) -> Self {
let loc = std::panic::Location::caller();
Self {
message: message.into(),
line: loc.line(),
file: loc.file(),
}
}
}
impl From<String> for BuilderError {
#[track_caller]
fn from(message: String) -> Self {
Self::new(message)
}
}
#[derive(Debug, derive_more::Display, derive_more::From)]
pub enum ErrorKind {
#[display("{}", _0)]
#[from]
Http(HttpError),
#[display("Authentication failed: {}", _0)]
Auth(String),
#[display("ArcGIS API error {}: {}", code, message)]
Api {
code: i32,
message: String,
},
#[display("{}", _0)]
#[from]
Json(JsonError),
#[display("{}", _0)]
#[from]
Url(UrlError),
#[display("{}", _0)]
#[from]
Io(IoError),
#[display("{}", _0)]
#[from]
UrlEncoded(UrlEncodedError),
#[display("{}", _0)]
#[from]
Env(EnvError),
#[display("{}", _0)]
#[from]
Builder(BuilderError),
#[display("OAuth error: {}", _0)]
OAuth(String),
#[display("Geometry conversion error: {}", _0)]
Geometry(String),
#[display("Validation error: {}", _0)]
Validation(String),
#[display("{}", _0)]
Other(String),
}
macro_rules! bridge_error {
($external:ty => $wrapper:ty) => {
impl From<$external> for ErrorKind {
#[track_caller]
fn from(err: $external) -> Self {
<$wrapper>::from(err).into()
}
}
};
}
bridge_error!(reqwest::Error => HttpError);
bridge_error!(serde_json::Error => JsonError);
bridge_error!(url::ParseError => UrlError);
bridge_error!(std::io::Error => IoError);
bridge_error!(serde_urlencoded::ser::Error => UrlEncodedError);
bridge_error!(std::env::VarError => EnvError);
#[derive(Debug, derive_more::Display)]
#[display("ArcGIS SDK: {}", _0)]
pub struct Error(Box<ErrorKind>);
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match &*self.0 {
ErrorKind::Http(e) => Some(e.source()),
ErrorKind::Json(e) => Some(e.source()),
ErrorKind::Url(e) => Some(e.source()),
ErrorKind::Io(e) => Some(e.source()),
ErrorKind::UrlEncoded(e) => Some(e.source()),
ErrorKind::Env(e) => Some(e.source()),
_ => None,
}
}
}
impl Error {
pub fn kind(&self) -> &ErrorKind {
&self.0
}
}
macro_rules! error_from {
($source:ty) => {
impl From<$source> for Error {
#[track_caller]
fn from(err: $source) -> Self {
let kind = ErrorKind::from(err);
tracing::error!(error_kind = %kind, "Error created");
Self(Box::new(kind))
}
}
};
}
impl From<ErrorKind> for Error {
#[track_caller]
fn from(kind: ErrorKind) -> Self {
tracing::error!(error_kind = %kind, "Error created");
Self(Box::new(kind))
}
}
error_from!(reqwest::Error);
error_from!(serde_json::Error);
error_from!(url::ParseError);
error_from!(std::io::Error);
error_from!(serde_urlencoded::ser::Error);
error_from!(std::env::VarError);
error_from!(BuilderError);