use std::error::Error as StdError;
use std::fmt::{self, Display};
#[derive(Debug)]
#[non_exhaustive]
pub enum FetchError {
OutOfRange { index: usize, len: usize },
TooLarge {
location: String,
limit: u64,
size: Option<u64>,
},
Status {
url: String,
status: u16,
attempts: u32,
},
Io {
location: String,
attempts: u32,
timeout: bool,
source: Box<dyn StdError + Send + Sync>,
},
Store {
location: String,
max_attempts: Option<u32>,
source: Box<dyn StdError + Send + Sync>,
},
}
impl FetchError {
pub fn is_timeout(&self) -> bool {
matches!(self, Self::Io { timeout: true, .. })
}
}
impl Display for FetchError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::OutOfRange { index, len } => {
write!(
f,
"index {index} is out of range for a dataset of {len} items"
)
}
Self::TooLarge {
location,
limit,
size: Some(size),
} => write!(
f,
"{location}: {size} bytes, more than the limit of {limit}"
),
Self::TooLarge {
location, limit, ..
} => write!(f, "{location}: more than the limit of {limit} bytes"),
Self::Status {
url,
status,
attempts,
} => write!(f, "{url}: HTTP status {status} after {attempts} attempt(s)"),
Self::Io {
location,
attempts,
timeout,
source,
} => {
let what = if *timeout { "timed out" } else { "failed" };
write!(
f,
"{location}: {what} after {attempts} attempt(s): {source}"
)
}
Self::Store {
location,
max_attempts: Some(max_attempts),
source,
} => write!(
f,
"{location}: failed after up to {max_attempts} attempt(s), \
retried by object_store: {source}"
),
Self::Store {
location, source, ..
} => write!(
f,
"{location}: failed, retried by the store's own settings: {source}"
),
}
}
}
impl StdError for FetchError {
fn source(&self) -> Option<&(dyn StdError + 'static)> {
match self {
Self::Io { source, .. } | Self::Store { source, .. } => Some(source.as_ref()),
_ => None,
}
}
}