use std::fmt;
use std::io;
use std::borrow::Cow;
use std::str::Utf8Error;
use std::result::Result as StdResult;
use std::error::Error as StdError;
use std::convert::{From, Into};
use httparse;
#[cfg(feature="ssl")]
use openssl::ssl::error::SslError;
pub type Result<T> = StdResult<T, Error>;
#[derive(Debug)]
pub enum Kind {
CloseSingal,
OutNotEnough,
Internal,
Capacity,
Protocol,
Encoding(Utf8Error),
Io(io::Error),
Http(httparse::Error),
#[cfg(feature="ssl")]
Ssl(SslError),
Custom(Box<StdError + Send + Sync>),
}
pub struct Error {
pub kind: Kind,
pub details: Cow<'static, str>,
}
impl Error {
pub fn new<I>(kind: Kind, details: I) -> Error
where I: Into<Cow<'static, str>>
{
Error {
kind: kind,
details: details.into(),
}
}
pub fn into_box(self) -> Box<StdError> {
match self.kind {
Kind::Custom(err) => err,
_ => Box::new(self),
}
}
}
impl fmt::Debug for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.details.len() > 0 {
write!(f, "WS Error <{:?}>: {}", self.kind, self.details)
} else {
write!(f, "WS Error <{:?}>", self.kind)
}
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self.details.len() > 0 {
write!(f, "{}: {}", self.description(), self.details)
} else {
write!(f, "{}", self.description())
}
}
}
impl StdError for Error {
fn description(&self) -> &str {
match self.kind {
Kind::CloseSingal => "Close Signal Error",
Kind::OutNotEnough => "Outbuff NotEnough Error",
Kind::Internal => "Internal Application Error",
Kind::Capacity => "WebSocket at Capacity",
Kind::Protocol => "WebSocket Protocol Error",
Kind::Encoding(ref err) => err.description(),
Kind::Io(ref err) => err.description(),
Kind::Http(_) => "Unable to parse HTTP",
#[cfg(feature="ssl")]
Kind::Ssl(ref err) => err.description(),
Kind::Custom(ref err) => err.description(),
}
}
fn cause(&self) -> Option<&StdError> {
match self.kind {
Kind::Encoding(ref err) => Some(err),
Kind::Io(ref err) => Some(err),
#[cfg(feature="ssl")]
Kind::Ssl(ref err) => Some(err),
Kind::Custom(ref err) => Some(err.as_ref()),
_ => None,
}
}
}
impl From<io::Error> for Error {
fn from(err: io::Error) -> Error {
Error::new(Kind::Io(err), "")
}
}
impl From<httparse::Error> for Error {
fn from(err: httparse::Error) -> Error {
let details = match err {
httparse::Error::HeaderName => "Invalid byte in header name.",
httparse::Error::HeaderValue => "Invalid byte in header value.",
httparse::Error::NewLine => "Invalid byte in new line.",
httparse::Error::Status => "Invalid byte in Response status.",
httparse::Error::Token => "Invalid byte where token is required.",
httparse::Error::TooManyHeaders => "Parsed more headers than provided buffer can contain.",
httparse::Error::Version => "Invalid byte in HTTP version.",
};
Error::new(Kind::Http(err), details)
}
}
impl From<Utf8Error> for Error {
fn from(err: Utf8Error) -> Error {
Error::new(Kind::Encoding(err), "")
}
}
#[cfg(feature="ssl")]
impl From<SslError> for Error {
fn from(err: SslError) -> Error {
Error::new(Kind::Ssl(err), "")
}
}
impl<B> From<Box<B>> for Error
where B: StdError + Send + Sync + 'static
{
fn from(err: Box<B>) -> Error {
Error::new(Kind::Custom(err), "")
}
}