use thiserror::Error;
#[derive(Error, Debug)]
pub enum TransportError {
#[error("websocket error: {0}")]
WebSocket(String),
#[error("http error: {0}")]
Http(String),
#[error("connection closed")]
Closed,
}
#[non_exhaustive]
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum ActionErrorKind {
Unsupported,
BadParams,
AuthFailed,
RateLimited,
Internal,
NotFound,
Other,
}
#[derive(Error, Debug)]
pub enum Error {
#[error("action failed: retcode={retcode} {message}")]
Action { retcode: i64, message: String, kind: ActionErrorKind },
#[error("action `{0}` not supported by this implementation")]
Unsupported(String),
#[error("action timed out")]
Timeout,
#[error("connection closed mid-call")]
ConnectionClosed,
#[error(transparent)]
Transport(#[from] TransportError),
#[error(transparent)]
Decode(#[from] serde_json::Error),
}
pub type Result<T> = std::result::Result<T, Error>;
impl Error {
pub const NON_PROTOCOL_RETCODE: i64 = -1;
pub fn action(message: impl Into<String>) -> Self {
Error::action_kind(ActionErrorKind::Internal, message)
}
pub fn action_kind(kind: ActionErrorKind, message: impl Into<String>) -> Self {
Error::Action { retcode: Self::NON_PROTOCOL_RETCODE, message: message.into(), kind }
}
pub fn is_unsupported(&self) -> bool {
matches!(self, Error::Unsupported(_))
|| matches!(self, Error::Action { kind: ActionErrorKind::Unsupported, .. })
}
}
#[macro_export]
macro_rules! bail {
($kind:expr, $fmt:literal $(, $($arg:tt)*)?) => {
return ::core::result::Result::Err(
$crate::error::Error::action_kind($kind, ::std::format!($fmt $(, $($arg)*)?))
)
};
($fmt:literal $(, $($arg:tt)*)?) => {
return ::core::result::Result::Err(
$crate::error::Error::action(::std::format!($fmt $(, $($arg)*)?))
)
};
}