use failure::{Backtrace, Context, Fail};
use std::{fmt, fmt::Display, result};
pub type Result<T> = result::Result<T, Error>;
pub use failure::ResultExt;
#[derive(Debug)]
pub struct Error {
ctx: Context<ErrorKind>,
}
#[derive(PartialEq, Debug, Fail)]
pub enum ErrorKind {
#[fail(display = "Log error: {}", _0)]
LogError(String),
#[fail(display = "Invalid argument: {}", _0)]
InvalidArgument(String),
#[fail(display = "Invalid operation: {}", _0)]
InvalidOperation(String),
#[fail(display = "{}", _0)]
Other(String),
#[fail(display = "Multiple errors occurred. Check the log.")]
Multiple(Vec<ErrorKind>),
#[fail(display = "Inter-thread communication error: {}", _0)]
ITCError(String),
#[fail(display = "Interprocess communication error: {}", _0)]
IPCError(String),
#[fail(display = "I/O error: {}", _0)]
IoError(String, std::io::ErrorKind),
#[fail(display = "Terminal error: {}", _0)]
TermError(String, term::Error),
}
pub fn log_err<T>(s: impl Into<String>) -> Result<T> {
Err(ErrorKind::LogError(s.into()).into())
}
pub fn oe_log_err(s: impl Into<String>) -> impl FnOnce() -> Error {
move || ErrorKind::LogError(s.into()).into()
}
pub fn inv_arg<T>(s: impl Into<String>) -> Result<T> {
Err(ErrorKind::InvalidArgument(s.into()).into())
}
pub fn oe_inv_arg(s: impl Into<String>) -> impl FnOnce() -> Error {
move || ErrorKind::InvalidArgument(s.into()).into()
}
pub fn inv_op<T>(s: impl Into<String>) -> Result<T> {
Err(ErrorKind::InvalidOperation(s.into()).into())
}
pub fn oe_inv_op(s: impl Into<String>) -> impl FnOnce() -> Error {
move || ErrorKind::InvalidOperation(s.into()).into()
}
pub fn err<T>(s: impl Into<String>) -> Result<T> {
Err(ErrorKind::Other(s.into()).into())
}
pub fn oe_err(s: impl Into<String>) -> impl FnOnce() -> Error {
move || ErrorKind::Other(s.into()).into()
}
impl Fail for Error {
fn cause(&self) -> Option<&dyn Fail> {
self.ctx.cause()
}
fn backtrace(&self) -> Option<&Backtrace> {
self.ctx.backtrace()
}
}
impl Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.ctx.fmt(f)
}
}
impl From<ErrorKind> for Error {
fn from(ctx: ErrorKind) -> Error {
Error {
ctx: Context::new(ctx),
}
}
}
impl From<Context<String>> for Error {
fn from(ctx: Context<String>) -> Error {
Error {
ctx: ctx.map(ErrorKind::Other),
}
}
}
impl From<Context<ErrorKind>> for Error {
fn from(ctx: Context<ErrorKind>) -> Error {
Error { ctx }
}
}
impl From<std::io::Error> for Error {
fn from(error: std::io::Error) -> Error {
let msg = error.to_string();
Error {
ctx: Context::new(ErrorKind::IoError(msg, error.kind())),
}
}
}
impl From<term::Error> for Error {
fn from(error: term::Error) -> Error {
let msg = error.to_string();
Error {
ctx: Context::new(ErrorKind::TermError(msg, error)),
}
}
}
impl<T> From<crossbeam_channel::SendError<T>> for Error {
fn from(error: crossbeam_channel::SendError<T>) -> Error {
let msg = error.to_string();
Error {
ctx: Context::new(ErrorKind::ITCError(msg)),
}
}
}
impl From<ipc_channel::Error> for Error {
fn from(error: ipc_channel::Error) -> Error {
let msg = error.to_string();
Error {
ctx: Context::new(ErrorKind::IPCError(msg)),
}
}
}
impl From<ipc_channel::ipc::IpcError> for Error {
fn from(error: ipc_channel::ipc::IpcError) -> Error {
let msg = match error {
ipc_channel::ipc::IpcError::Bincode(err) => err.to_string(),
ipc_channel::ipc::IpcError::Io(err) => err.to_string(),
ipc_channel::ipc::IpcError::Disconnected => "disconnected".to_string(),
};
Error {
ctx: Context::new(ErrorKind::IPCError(msg)),
}
}
}
impl From<strum::ParseError> for Error {
fn from(error: strum::ParseError) -> Error {
let msg = error.to_string();
Error {
ctx: Context::new(ErrorKind::InvalidArgument(msg)),
}
}
}
impl From<serde_yaml::Error> for Error {
fn from(error: serde_yaml::Error) -> Error {
let msg = error.to_string();
Error {
ctx: Context::new(ErrorKind::InvalidArgument(msg)),
}
}
}
impl From<serde_json::Error> for Error {
fn from(error: serde_json::Error) -> Error {
let msg = error.to_string();
Error {
ctx: Context::new(ErrorKind::InvalidArgument(msg)),
}
}
}
impl From<std::str::Utf8Error> for Error {
fn from(error: std::str::Utf8Error) -> Error {
let msg = error.to_string();
Error {
ctx: Context::new(ErrorKind::InvalidArgument(msg)),
}
}
}
impl From<std::string::FromUtf8Error> for Error {
fn from(error: std::string::FromUtf8Error) -> Error {
let msg = error.to_string();
Error {
ctx: Context::new(ErrorKind::InvalidArgument(msg)),
}
}
}
impl From<std::num::ParseFloatError> for Error {
fn from(error: std::num::ParseFloatError) -> Error {
let msg = error.to_string();
Error {
ctx: Context::new(ErrorKind::InvalidArgument(msg)),
}
}
}
impl From<std::ffi::NulError> for Error {
fn from(error: std::ffi::NulError) -> Error {
let msg = error.to_string();
Error {
ctx: Context::new(ErrorKind::InvalidArgument(msg)),
}
}
}
impl From<crossbeam_channel::RecvError> for Error {
fn from(error: crossbeam_channel::RecvError) -> Error {
let msg = error.to_string();
Error {
ctx: Context::new(ErrorKind::ITCError(msg)),
}
}
}