/* * meli - error module * * Copyright 2017 Manos Pitsidianakis * * This file is part of meli. * * meli is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * meli is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with meli. If not, see . */ /*! * An error object for `melib` */ use std::borrow::Cow; use std::error::Error; use std::fmt; use std::io; use std::result; use std::str; use std::string; use std::sync::Arc; pub type Result = result::Result; #[derive(Debug, Copy, PartialEq, Clone)] pub enum ErrorKind { None, External, Authentication, Bug, Network, Timeout, OSError, NotImplemented, NotSupported, } impl fmt::Display for ErrorKind { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { write!( fmt, "{}", match self { ErrorKind::None => "None", ErrorKind::External => "External", ErrorKind::Authentication => "Authentication", ErrorKind::Bug => "Bug, please report this!", ErrorKind::Network => "Network", ErrorKind::Timeout => "Timeout", ErrorKind::OSError => "OS Error", ErrorKind::NotImplemented => "Not implemented", ErrorKind::NotSupported => "Not supported", } ) } } impl ErrorKind { pub fn is_network(&self) -> bool { match self { ErrorKind::Network => true, _ => false, } } pub fn is_timeout(&self) -> bool { match self { ErrorKind::Timeout => true, _ => false, } } pub fn is_authentication(&self) -> bool { match self { ErrorKind::Authentication => true, _ => false, } } } #[derive(Debug, Clone)] pub struct MeliError { pub summary: Option>, pub details: Cow<'static, str>, pub source: Option>, pub kind: ErrorKind, } pub trait IntoMeliError { fn set_err_summary(self, msg: M) -> MeliError where M: Into>; fn set_err_kind(self, kind: ErrorKind) -> MeliError; } pub trait ResultIntoMeliError { fn chain_err_summary(self, msg_fn: F) -> Result where F: Fn() -> M, M: Into>; fn chain_err_kind(self, kind: ErrorKind) -> Result; } impl> IntoMeliError for I { #[inline] fn set_err_summary(self, msg: M) -> MeliError where M: Into>, { let err: MeliError = self.into(); err.set_summary(msg) } #[inline] fn set_err_kind(self, kind: ErrorKind) -> MeliError { let err: MeliError = self.into(); err.set_kind(kind) } } impl> ResultIntoMeliError for std::result::Result { #[inline] fn chain_err_summary(self, msg_fn: F) -> Result where F: Fn() -> M, M: Into>, { self.map_err(|err| err.set_err_summary(msg_fn())) } #[inline] fn chain_err_kind(self, kind: ErrorKind) -> Result { self.map_err(|err| err.set_err_kind(kind)) } } impl MeliError { pub fn new(msg: M) -> MeliError where M: Into>, { MeliError { summary: None, details: msg.into(), source: None, kind: ErrorKind::None, } } pub fn set_summary(mut self, summary: M) -> MeliError where M: Into>, { if let Some(old_summary) = self.summary.take() { self.summary = Some(format!("{}. {}", old_summary, summary.into()).into()); } else { self.summary = Some(summary.into()); } self } pub fn set_source( mut self, new_val: Option>, ) -> MeliError { self.source = new_val; self } pub fn set_kind(mut self, new_val: ErrorKind) -> MeliError { self.kind = new_val; self } } impl fmt::Display for MeliError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { if let Some(summary) = self.summary.as_ref() { writeln!(f, "Summary: {}", summary)?; } write!(f, "{}", self.details)?; if let Some(source) = self.source.as_ref() { write!(f, "\nCaused by: {}", source)?; } if self.kind != ErrorKind::None { write!(f, "\nKind: {}", self.kind)?; } Ok(()) } } impl Error for MeliError { fn source(&self) -> Option<&(dyn Error + 'static)> { self.source.as_ref().map(|s| &(*(*s)) as _) } } impl From for MeliError { #[inline] fn from(kind: io::Error) -> MeliError { MeliError::new(kind.to_string()) .set_summary(format!("{:?}", kind.kind())) .set_source(Some(Arc::new(kind))) .set_kind(ErrorKind::OSError) } } impl<'a> From> for MeliError { #[inline] fn from(kind: Cow<'_, str>) -> MeliError { MeliError::new(format!("{:?}", kind)) } } impl From for MeliError { #[inline] fn from(kind: string::FromUtf8Error) -> MeliError { MeliError::new(format!("{:?}", kind)).set_source(Some(Arc::new(kind))) } } impl From for MeliError { #[inline] fn from(kind: str::Utf8Error) -> MeliError { MeliError::new(format!("{:?}", kind)).set_source(Some(Arc::new(kind))) } } //use std::option; //impl From for MeliError { // #[inline] // fn from(kind: option::NoneError) -> MeliError { // MeliError::new(format!("{:?}", kind)) // } //} impl From> for MeliError { #[inline] fn from(kind: std::sync::PoisonError) -> MeliError { MeliError::new(format!("{}", kind)) } } #[cfg(feature = "tls")] impl From> for MeliError { #[inline] fn from(kind: native_tls::HandshakeError) -> MeliError { MeliError::new(format!("{}", kind)).set_source(Some(Arc::new(kind))) } } #[cfg(feature = "tls")] impl From for MeliError { #[inline] fn from(kind: native_tls::Error) -> MeliError { MeliError::new(format!("{}", kind)).set_source(Some(Arc::new(kind))) } } impl From for MeliError { #[inline] fn from(kind: std::num::ParseIntError) -> MeliError { MeliError::new(format!("{}", kind)).set_source(Some(Arc::new(kind))) } } #[cfg(feature = "jmap_backend")] impl From for MeliError { #[inline] fn from(kind: isahc::Error) -> MeliError { MeliError::new(kind.to_string()).set_source(Some(Arc::new(kind))) } } #[cfg(feature = "jmap_backend")] impl From for MeliError { #[inline] fn from(kind: serde_json::error::Error) -> MeliError { MeliError::new(format!("{}", kind)).set_source(Some(Arc::new(kind))) } } impl From> for MeliError { #[inline] fn from(kind: Box) -> MeliError { MeliError::new(format!("{}", kind)).set_source(Some(kind.into())) } } impl From for MeliError { #[inline] fn from(kind: std::ffi::NulError) -> MeliError { MeliError::new(format!("{}", kind)).set_source(Some(Arc::new(kind))) } } impl From> for MeliError { #[inline] fn from(kind: Box) -> MeliError { MeliError::new(format!("{}", kind)).set_source(Some(Arc::new(kind))) } } impl From for MeliError { #[inline] fn from(kind: nix::Error) -> MeliError { MeliError::new(format!("{}", kind)).set_source(Some(Arc::new(kind))) } } #[cfg(feature = "sqlite3")] impl From for MeliError { #[inline] fn from(kind: rusqlite::Error) -> MeliError { MeliError::new(format!("{}", kind)).set_source(Some(Arc::new(kind))) } } impl From for MeliError { #[inline] fn from(kind: libloading::Error) -> MeliError { MeliError::new(format!("{}", kind)).set_source(Some(Arc::new(kind))) } } impl From<&str> for MeliError { #[inline] fn from(kind: &str) -> MeliError { MeliError::new(kind.to_string()) } } impl From for MeliError { #[inline] fn from(kind: String) -> MeliError { MeliError::new(kind) } } impl From> for MeliError { #[inline] fn from(kind: nom::Err<(&[u8], nom::error::ErrorKind)>) -> MeliError { MeliError::new("Parsing error") .set_source(Some(Arc::new(MeliError::new(format!("{}", kind))))) } } impl From> for MeliError { #[inline] fn from(kind: nom::Err<(&str, nom::error::ErrorKind)>) -> MeliError { MeliError::new("Parsing error") .set_source(Some(Arc::new(MeliError::new(format!("{}", kind))))) } } impl<'a> From<&'a mut MeliError> for MeliError { #[inline] fn from(kind: &'a mut MeliError) -> MeliError { kind.clone() } } impl<'a> From<&'a MeliError> for MeliError { #[inline] fn from(kind: &'a MeliError) -> MeliError { kind.clone() } }