use std::fmt;
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct AdapterError {
pub code: &'static str,
pub stage: &'static str,
pub retryable: bool,
pub uncertain_effect: bool,
pub detail: Option<String>,
}
impl AdapterError {
pub const fn permanent(code: &'static str, stage: &'static str) -> Self {
Self {
code,
stage,
retryable: false,
uncertain_effect: false,
detail: None,
}
}
pub const fn retryable(code: &'static str, stage: &'static str) -> Self {
Self {
code,
stage,
retryable: true,
uncertain_effect: false,
detail: None,
}
}
pub const fn uncertain(code: &'static str, stage: &'static str) -> Self {
Self {
code,
stage,
retryable: true,
uncertain_effect: true,
detail: None,
}
}
pub fn with_detail(mut self, detail: impl Into<String>) -> Self {
self.detail = Some(detail.into());
self
}
pub(crate) fn io(code: &'static str, stage: &'static str, error: std::io::Error) -> Self {
let kind = error.kind();
let mut failure = match kind {
std::io::ErrorKind::NotFound => Self::permanent(code, stage),
std::io::ErrorKind::PermissionDenied => Self::permanent(code, stage),
std::io::ErrorKind::TimedOut => Self::retryable(code, stage),
_ => Self::uncertain(code, stage),
};
failure.detail = Some(error.to_string());
failure
}
}
impl fmt::Display for AdapterError {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.detail {
Some(detail) => write!(formatter, "{} [{}]: {}", self.code, self.stage, detail),
None => write!(formatter, "{} [{}]", self.code, self.stage),
}
}
}
impl std::error::Error for AdapterError {}
pub type Result<T> = std::result::Result<T, AdapterError>;