use crate::frame::DecodeError;
use std::error::Error as StdError;
use std::fmt;
use std::io;
pub type Result<T> = std::result::Result<T, Error>;
pub struct Error {
inner: Box<ErrorImpl>,
}
type Source = Box<dyn Send + Sync + StdError>;
struct ErrorImpl {
kind: Kind,
source: Option<Source>,
}
#[derive(Debug, PartialEq)]
#[non_exhaustive]
pub(crate) enum Kind {
Decode(DecodeError),
InvalidSetup,
UnsupportedSetup,
RejectedSetup,
RejectedResume,
ConnectionError,
ConnectionClose,
ApplicationError,
Rejected,
Canceled,
Invalid,
Io,
}
#[non_exhaustive]
#[rustfmt::skip]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Code {
InvalidSetup = 0x00000001,
UnsupportedSetup = 0x00000002,
RejectedSetup = 0x00000003,
RejectedResume = 0x00000004,
ConnectionError = 0x00000101,
ConnectionClose = 0x00000102,
ApplicationError = 0x00000201,
Rejected = 0x00000202,
Canceled = 0x00000203,
Invalid = 0x00000204,
}
impl Error {
pub(crate) fn new<E>(kind: Kind, source: Option<E>) -> Error
where
E: Into<Source>,
{
Error {
inner: Box::new(ErrorImpl {
kind,
source: source.map(Into::into),
}),
}
}
pub fn is_decode(&self) -> bool {
matches!(self.inner.kind, Kind::Decode(_))
}
pub fn is_protocol(&self) -> bool {
use Kind::*;
matches!(
self.inner.kind,
InvalidSetup
| UnsupportedSetup
| RejectedSetup
| RejectedResume
| ConnectionError
| ConnectionClose
| ApplicationError
| Rejected
| Canceled
| Invalid
)
}
pub fn is_setup(&self) -> bool {
matches!(
self.inner.kind,
Kind::InvalidSetup | Kind::UnsupportedSetup | Kind::RejectedSetup
)
}
pub fn is_invalid_setup(&self) -> bool {
matches!(self.inner.kind, Kind::InvalidSetup)
}
pub fn is_unsupported_setup(&self) -> bool {
matches!(self.inner.kind, Kind::UnsupportedSetup)
}
pub fn is_rejected_setup(&self) -> bool {
matches!(self.inner.kind, Kind::RejectedSetup)
}
pub fn is_rejected_resume(&self) -> bool {
matches!(self.inner.kind, Kind::RejectedResume)
}
pub fn is_connection_error(&self) -> bool {
matches!(self.inner.kind, Kind::ConnectionError)
}
pub fn is_connection_close(&self) -> bool {
matches!(self.inner.kind, Kind::ConnectionClose)
}
pub fn is_application_error(&self) -> bool {
matches!(self.inner.kind, Kind::ApplicationError)
}
pub fn is_rejected(&self) -> bool {
matches!(self.inner.kind, Kind::Rejected)
}
pub fn is_cancel(&self) -> bool {
matches!(self.inner.kind, Kind::Canceled)
}
pub fn is_invalid(&self) -> bool {
matches!(self.inner.kind, Kind::Invalid)
}
fn description(&self) -> &str {
use Kind::*;
match &self.inner.kind {
InvalidSetup => "INVALID_SETUP (0x00000001)",
UnsupportedSetup => "UNSUPPORTED_SETUP (0x00000002)",
RejectedSetup => "REJECTED_SETUP (0x00000003)",
RejectedResume => "REJECTED_RESUME (0x00000004)",
ConnectionError => "CONNECTION_ERROR (0x00000101)",
ConnectionClose => "CONNECTION_CLOSE (0x00000102)",
ApplicationError => "APPLICATION_ERROR (0x00000201)",
Rejected => "CONNECTION_ERROR (0x00000202)",
Canceled => "CANCELED (0x00000203)",
Invalid => "INVALID (0x00000204)",
Decode(_) => "error decoding frame",
Io => "I/O error",
}
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if let Some(ref source) = self.inner.source {
write!(f, "{}: {}", self.description(), source)
} else {
f.write_str(self.description())
}
}
}
impl fmt::Debug for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut f = f.debug_tuple("nightwatch_rsocket::Error");
f.field(&self.inner.kind);
if let Some(ref source) = self.inner.source {
f.field(source);
}
f.finish()
}
}
impl StdError for Error {
fn source(&self) -> Option<&(dyn StdError + 'static)> {
self.inner.source.as_ref().map(|e| &**e as _)
}
}
impl From<DecodeError> for Error {
fn from(e: DecodeError) -> Error {
let source = e.to_string();
Error::new(Kind::Decode(e), Some(source))
}
}
impl From<io::Error> for Error {
fn from(e: io::Error) -> Error {
Error::new(Kind::Io, Some(e))
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::mem;
fn assert_send<T: Send>() {}
fn assert_sync<T: Sync>() {}
#[test]
fn size_of() {
assert_eq!(mem::size_of::<Error>(), mem::size_of::<usize>());
}
#[test]
fn assert_send_sync() {
assert_send::<Error>();
assert_sync::<Error>();
}
#[test]
fn from_decode_error() {
let decode = DecodeError::InComplete;
let actual: Error = decode.clone().into();
match actual.inner.kind {
Kind::Decode(e) => assert_eq!(e, decode),
_ => panic!("{:?}", actual),
}
assert!(actual.inner.source.is_some());
}
}