use failure::*;
use std::{
fmt::{self, Display},
io,
};
#[cfg(feature = "secret-connection")]
use {chrono, prost, subtle_encoding};
#[allow(unused_macros)]
macro_rules! err {
($kind:path, $msg:expr) => {
$crate::error::Error::new(failure::Context::new($kind), Some($msg.to_string()))
};
($kind:path, $fmt:expr, $($arg:tt)+) => {
err!($kind, &format!($fmt, $($arg)+))
};
}
#[derive(Debug)]
pub struct Error {
inner: Context<ErrorKind>,
msg: Option<String>,
}
impl Error {
pub fn new<C>(context: C, msg: Option<String>) -> Self
where
C: Into<Context<ErrorKind>>,
{
Self {
inner: context.into(),
msg,
}
}
pub fn kind(&self) -> &ErrorKind {
self.inner.get_context()
}
pub fn msg(&self) -> Option<&str> {
self.msg.as_ref().map(AsRef::as_ref)
}
}
impl Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(msg) = &self.msg {
write!(f, "{}: {}", self.kind(), msg)
} else {
write!(f, "{}", self.kind())
}
}
}
impl Fail for Error {
fn cause(&self) -> Option<&dyn Fail> {
self.inner.cause()
}
fn backtrace(&self) -> Option<&Backtrace> {
self.inner.backtrace()
}
}
impl From<ErrorKind> for Error {
fn from(kind: ErrorKind) -> Self {
Error::new(kind, None)
}
}
impl From<chrono::ParseError> for Error {
fn from(err: chrono::ParseError) -> Error {
err!(ErrorKind::Parse, err)
}
}
impl From<io::Error> for Error {
fn from(err: io::Error) -> Self {
err!(ErrorKind::Io, err)
}
}
#[cfg(feature = "secret-connection")]
impl From<prost::DecodeError> for Error {
fn from(err: prost::DecodeError) -> Self {
err!(ErrorKind::Parse, err)
}
}
#[cfg(feature = "secret-connection")]
impl From<prost::EncodeError> for Error {
fn from(err: prost::EncodeError) -> Self {
err!(ErrorKind::Parse, err)
}
}
#[cfg(feature = "serde_json")]
impl From<serde_json::error::Error> for Error {
fn from(err: serde_json::error::Error) -> Self {
err!(ErrorKind::Parse, err)
}
}
impl From<signatory::Error> for Error {
fn from(_err: signatory::Error) -> Self {
err!(ErrorKind::Crypto, "signature error")
}
}
impl From<subtle_encoding::Error> for Error {
fn from(err: subtle_encoding::Error) -> Error {
err!(ErrorKind::Parse, err)
}
}
#[cfg(feature = "toml")]
impl From<toml::de::Error> for Error {
fn from(err: toml::de::Error) -> Self {
err!(ErrorKind::Parse, err)
}
}
#[derive(Clone, Eq, PartialEq, Debug, Fail)]
pub enum ErrorKind {
#[fail(display = "cryptographic error")]
Crypto,
#[fail(display = "invalid key")]
InvalidKey,
#[fail(display = "I/O error")]
Io,
#[fail(display = "length error")]
Length,
#[fail(display = "parse error")]
Parse,
#[fail(display = "protocol error")]
Protocol,
#[fail(display = "value out of range")]
OutOfRange,
#[fail(display = "bad signature")]
SignatureInvalid,
}