use std::io;
use std::fmt;
use std::net;
use std::num;
use std::error::Error as StdError;
use std::sync::mpsc;
use std::sync;
use std::result::Result as StdResult;
use serde_json;
use ansi_term::Colour;
pub type Result<T> = StdResult<T, Error>;
#[derive(Debug)]
pub enum ErrorKind {
ProviderNotFound(String),
InvalidInput(String),
NotBehindProxy,
WrongRequestKind,
InvalidHexChar(char),
InvalidHexLength,
BrokenChannel,
PoisonedLock,
ThreadCrashed,
IoError(io::Error),
JsonError(serde_json::Error),
AddrParseError(net::AddrParseError),
ParseIntError(num::ParseIntError),
GenericError(Box<StdError + Send + Sync>),
#[doc(hidden)]
Dummy,
}
impl fmt::Display for ErrorKind {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", match *self {
ErrorKind::ProviderNotFound(ref provider) =>
format!("Provider {} not found", provider),
ErrorKind::InvalidInput(ref error) =>
format!("invalid input: {}", error),
ErrorKind::NotBehindProxy =>
"not behind the proxies".into(),
ErrorKind::WrongRequestKind =>
"wrong request kind".into(),
ErrorKind::InvalidHexChar(chr) =>
format!("{} is not valid hex", chr),
ErrorKind::InvalidHexLength =>
"invalid length of the hex".into(),
ErrorKind::BrokenChannel =>
"an internal communication channel crashed".into(),
ErrorKind::PoisonedLock =>
"an internal lock was poisoned".into(),
ErrorKind::ThreadCrashed =>
"an internal thread crashed".into(),
ErrorKind::IoError(ref error) =>
format!("{}", error),
ErrorKind::JsonError(ref error) =>
format!("{}", error),
ErrorKind::AddrParseError(ref error) =>
format!("{}", error),
ErrorKind::ParseIntError(..) =>
"you didn't provide a valid number".into(),
ErrorKind::GenericError(ref error) =>
format!("{}", error),
ErrorKind::Dummy =>
"dummy_error".into(),
})
}
}
#[derive(Debug, PartialEq, Eq)]
pub enum ErrorLocation {
File(String, Option<u32>),
HookProcessing(String),
Unknown,
#[doc(hidden)]
__NonExaustiveMatch,
}
impl fmt::Display for ErrorLocation {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
ErrorLocation::File(ref path, line) => {
write!(f, "file {}", path)?;
if let Some(num) = line {
write!(f, ", on line {}", num)?;
}
Ok(())
},
ErrorLocation::HookProcessing(ref name) => {
write!(f, "while processing {}", name)
},
ErrorLocation::Unknown => {
write!(f, "")
},
ErrorLocation::__NonExaustiveMatch => {
panic!("You shouldn't use this.");
},
}
}
}
#[derive(Debug)]
pub struct Error {
kind: ErrorKind,
location: ErrorLocation,
}
impl Error {
pub fn new(kind: ErrorKind) -> Self {
Error {
kind: kind,
location: ErrorLocation::Unknown,
}
}
pub fn set_location(&mut self, location: ErrorLocation) {
self.location = location;
}
pub fn location(&self) -> &ErrorLocation {
&self.location
}
pub fn kind(&self) -> &ErrorKind {
&self.kind
}
pub fn pretty_print(&self) {
println!("{} {}",
Colour::Red.bold().paint("Error:"),
self
);
if self.location != ErrorLocation::Unknown {
println!("{} {}",
Colour::Yellow.bold().paint("Location:"),
self.location
);
}
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.kind)
}
}
impl StdError for Error {
fn description(&self) -> &str {
match self.kind {
ErrorKind::ProviderNotFound(..) =>
"provider not found",
ErrorKind::InvalidInput(..) =>
"invalid input",
ErrorKind::NotBehindProxy =>
"not behind the proxies",
ErrorKind::WrongRequestKind =>
"wrong request kind",
ErrorKind::InvalidHexChar(..) =>
"invalid character in hex",
ErrorKind::InvalidHexLength =>
"invalid length of the hex",
ErrorKind::BrokenChannel =>
"internal communication channel crashed",
ErrorKind::PoisonedLock =>
"poisoned lock",
ErrorKind::ThreadCrashed =>
"thread crashed",
ErrorKind::IoError(ref error) =>
error.description(),
ErrorKind::JsonError(ref error) =>
error.description(),
ErrorKind::AddrParseError(ref error) =>
error.description(),
ErrorKind::ParseIntError(..) =>
"invalid number",
ErrorKind::GenericError(ref error) =>
error.description(),
ErrorKind::Dummy =>
"dummy error",
}
}
fn cause(&self) -> Option<&StdError> {
match self.kind {
ErrorKind::IoError(ref error) => Some(error as &StdError),
ErrorKind::JsonError(ref error) => Some(error as &StdError),
ErrorKind::AddrParseError(ref error) => Some(error as &StdError),
ErrorKind::ParseIntError(ref error) => Some(error as &StdError),
_ => None,
}
}
}
macro_rules! derive_error {
($from:path, $to:path) => {
impl From<$from> for Error {
fn from(error: $from) -> Self {
Error::new($to(error))
}
}
};
}
impl From<ErrorKind> for Error {
fn from(error: ErrorKind) -> Self {
Error::new(error)
}
}
impl From<mpsc::RecvError> for Error {
fn from(_: mpsc::RecvError) -> Self {
Error::new(ErrorKind::BrokenChannel)
}
}
impl<T> From<mpsc::SendError<T>> for Error {
fn from(_: mpsc::SendError<T>) -> Self {
Error::new(ErrorKind::BrokenChannel)
}
}
impl<T> From<sync::PoisonError<T>> for Error {
fn from(_: sync::PoisonError<T>) -> Self {
Error::new(ErrorKind::PoisonedLock)
}
}
derive_error!(io::Error, ErrorKind::IoError);
derive_error!(serde_json::Error, ErrorKind::JsonError);
derive_error!(net::AddrParseError, ErrorKind::AddrParseError);
derive_error!(num::ParseIntError, ErrorKind::ParseIntError);
derive_error!(Box<StdError + Send + Sync>, ErrorKind::GenericError);