use std::error::Error as StdError; use std::fmt; use std::mem; use std::result; pub type StdResult = result::Result>; pub type Result = result::Result; #[derive(Debug)] pub struct Error { repr: Repr, } enum Repr { Simple(ErrorKind), Custom(Box), } #[derive(Debug)] struct Custom { kind: ErrorKind, error: Box, } #[derive(Debug, Clone)] pub enum ErrorKind { MissedEnvVar(String), } impl fmt::Display for ErrorKind { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { ErrorKind::MissedEnvVar(ref name) => { write!(fmt, r#"Missed "{}" environment variable"#, name) } } } } impl PartialEq for ErrorKind { fn eq(&self, other: &Self) -> bool { mem::discriminant(self) == mem::discriminant(other) } } impl From for Error { #[inline] fn from(kind: ErrorKind) -> Error { Error { repr: Repr::Simple(kind), } } } impl Error { pub fn new(kind: ErrorKind, error: E) -> Error where E: Into>, { Self::_new(kind, error.into()) } fn _new(kind: ErrorKind, error: Box) -> Error { Error { repr: Repr::Custom(Box::new(Custom { kind, error })), } } pub fn kind(&self) -> &ErrorKind { match &self.repr { Repr::Custom(ref c) => &c.kind, Repr::Simple(kind) => &kind, } } } impl fmt::Debug for Repr { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Repr::Custom(ref c) => fmt::Debug::fmt(&c, fmt), Repr::Simple(kind) => fmt.debug_tuple("Kind").field(&kind).finish(), } } } impl fmt::Display for Error { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.repr { Repr::Custom(ref c) => c.error.fmt(fmt), Repr::Simple(kind) => write!(fmt, "{}", kind), } } } impl StdError for Error { fn source(&self) -> Option<&(dyn StdError + 'static)> { match self.repr { Repr::Simple(..) => None, Repr::Custom(ref c) => c.error.source(), } } }