use std::fmt;
#[derive(Debug)]
pub(crate) enum TabloError {
Cursor(String),
CursorRejected(String),
Declaration(String),
Infrastructure(&'static str),
}
impl TabloError {
pub(crate) fn of(error: &topcoat::Error) -> Option<&Self> {
error.downcast_ref::<Self>()
}
pub(crate) fn is_cursor(error: &topcoat::Error) -> bool {
matches!(
Self::of(error),
Some(Self::Cursor(_) | Self::CursorRejected(_))
)
}
pub(crate) fn is_infrastructure(error: &topcoat::Error) -> bool {
matches!(Self::of(error), Some(Self::Infrastructure(_)))
}
}
impl fmt::Display for TabloError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let message = match self {
Self::Cursor(message) | Self::CursorRejected(message) | Self::Declaration(message) => {
message.as_str()
}
Self::Infrastructure(message) => message,
};
f.write_str(message)
}
}
impl std::error::Error for TabloError {}
pub(crate) fn misdeclared(errors: &[crate::DeclarationErrorKind]) -> topcoat::Error {
declaration(
errors
.iter()
.map(ToString::to_string)
.collect::<Vec<_>>()
.join("; "),
)
}
pub(crate) fn declaration(message: impl Into<String>) -> topcoat::Error {
let message = message.into();
tracing::error!(error = %message, "declaration failure");
TabloError::Declaration(message).into()
}
pub(crate) const DATABASE_UNAVAILABLE: &str = "database unavailable";
pub(crate) fn unavailable(source: impl fmt::Display) -> topcoat::Error {
tracing::error!(error = %source, "database unavailable");
TabloError::Infrastructure(DATABASE_UNAVAILABLE).into()
}
pub(crate) fn driver_failure(
error: impl Into<topcoat::Error>,
message: &'static str,
) -> topcoat::Error {
let error = error.into();
if error.is::<toasty::Error>() {
tracing::error!(error = %error, answer = message, "infrastructure failure");
TabloError::Infrastructure(message).into()
} else {
error
}
}
#[cfg(test)]
mod tests;