xbdm/
error.rs

1// Copyright 2017 xbdm-rs Developers
2//
3// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5// http://opensource.org/licenses/MIT>, at your option. This file may not be
6// copied, modified, or distributed except according to those terms.
7
8use std::error;
9use std::fmt;
10use std::io;
11use std::result;
12
13use status::StatusCode;
14
15pub type Result<T> = result::Result<T, Error>;
16
17#[derive(Debug)]
18pub enum ErrorKind {
19    /// An I/O error occurred.
20    Io(io::Error),
21    /// A response line was malformed or unexpected.
22    BadResponse(String),
23    /// A command returned a 4xx status code.
24    CommandFailed(StatusCode, String),
25}
26
27#[derive(Debug)]
28pub struct Error {
29    kind: ErrorKind,
30    command: String,
31}
32
33impl Error {
34    pub fn new<C: Into<String>>(kind: ErrorKind, command: C) -> Error {
35        Error { kind: kind, command: command.into() }
36    }
37
38    pub fn io<C: Into<String>>(err: io::Error, command: C) -> Error {
39        Error::new(ErrorKind::Io(err), command)
40    }
41
42    pub fn io_custom<E, C>(kind: io::ErrorKind, error: E, command: C) -> Error
43        where E: Into<Box<error::Error + Send + Sync>>, C: Into<String>
44    {
45        Error::new(ErrorKind::Io(io::Error::new(kind, error)), command)
46    }
47
48    pub fn bad_response<D, C>(desc: D, command: C) -> Error
49        where D: Into<String>, C: Into<String>
50    {
51        Error::new(ErrorKind::BadResponse(desc.into()), command)
52    }
53
54    pub fn command_failed<M, C>(code: StatusCode, message: M, command: C) -> Error
55        where M: Into<String>, C: Into<String>
56    {
57        Error::new(ErrorKind::CommandFailed(code, message.into()), command)
58    }
59
60    pub fn kind(&self) -> &ErrorKind { &self.kind }
61    pub fn command(&self) -> &str { &self.command }
62
63    /// If true, this `Error` requires the `Client` to reconnect.
64    pub fn is_fatal(&self) -> bool {
65        match self.kind {
66            ErrorKind::Io(_) | ErrorKind::BadResponse(_) => true,
67            _ => false,
68        }
69    }
70}
71
72impl fmt::Display for Error {
73    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
74        let have_command = self.command.len() > 0;
75        if have_command {
76            write!(f, "command failed: '{}' (", self.command)?;
77        }
78        match self.kind {
79            ErrorKind::Io(ref err) => write!(f, "I/O error: {}", err)?,
80            ErrorKind::BadResponse(ref desc) => write!(f, "bad response: {}", desc)?,
81            ErrorKind::CommandFailed(code, ref msg) => write!(f, "{}- {}", code, msg)?,
82        }
83        if have_command {
84            write!(f, ")")?;
85        }
86        Ok(())
87    }
88}
89
90impl error::Error for Error {
91    fn description(&self) -> &str {
92        match self.kind {
93            ErrorKind::Io(ref err) => err.description(),
94            ErrorKind::BadResponse(ref desc) => desc.as_ref(),
95            ErrorKind::CommandFailed(_, ref msg) => msg.as_ref(),
96        }
97    }
98
99    fn cause(&self) -> Option<&::std::error::Error> {
100        match self.kind {
101            ErrorKind::Io(ref err) => Some(err),
102            _ => None,
103        }
104    }
105}