1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
use self::super::util::uppercase_first;
use std::error::Error as StdError;
use std::borrow::Cow;
use std::fmt;


/// Enum representing all possible ways the application can fail.
///
/// # Examples
///
/// ```
/// # use bloguen::Error;
/// assert_eq!(Error::Io {
///                desc: "network".into(),
///                op: "write",
///                more: "full buffer".into(),
///            }.to_string(),
///            "Writing network failed: full buffer.");
/// ```
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub enum Error {
    /// An I/O error occured.
    ///
    /// This includes higher-level I/O errors like FS ones.
    Io {
        /// The file the I/O operation regards.
        desc: Cow<'static, str>,
        /// The failed operation.
        ///
        /// This should be lowercase and imperative ("create", "open").
        op: &'static str,
        /// Additional data.
        more: Cow<'static, str>,
    },
    Parse {
        /// What failed to parse.
        ///
        /// Something like "URL", "datetime".
        tp: &'static str,
        /// Where the thing that failed to parse would go, were it to parse properly.
        wher: Cow<'static, str>,
        /// Additional data.
        more: Cow<'static, str>,
    },
    /// A requested file doesn't exist.
    FileNotFound {
        /// What requested the file.
        who: &'static str,
        /// The file that should exist.
        path: Cow<'static, str>,
    },
    /// A path is in a wrong state.
    WrongFileState {
        /// What the file is not.
        what: &'static str,
        /// The file that should be.
        path: Cow<'static, str>,
    },
    /// Failed to parse the specified file because of the specified error(s).
    FileParsingFailed {
        /// The file that failed to parse.
        desc: Cow<'static, str>,
        /// The parsing error(s) that occured.
        errors: Cow<'static, str>,
    },
}

impl Error {
    /// Get the executable exit value from an `Error` instance.
    ///
    /// # Examples
    ///
    /// ```
    /// # use bloguen::Error;
    /// assert_eq!(Error::Io {
    ///     desc: "".into(),
    ///     op: "",
    ///     more: "".into(),
    /// }.exit_value(), 1);
    /// ```
    pub fn exit_value(&self) -> i32 {
        match *self {
            Error::Io { .. } => 1,
            Error::Parse { .. } => 2,
            Error::FileNotFound { .. } => 3,
            Error::WrongFileState { .. } => 4,
            Error::FileParsingFailed { .. } => 5,
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, err_out: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            Error::Io { ref desc, op, ref more } => {
                // Strip the last 'e', if any, so we get correct inflection for continuous tenses
                let op = uppercase_first(if op.ends_with('e') {
                    &op[..op.len() - 1]
                } else {
                    op
                });

                write!(err_out, "{}ing {} failed: {}.", op, desc, more)
            }
            Error::Parse { tp, ref wher, ref more } => write!(err_out, "Failed to parse {} for {}: {}.", tp, wher, more),
            Error::FileNotFound { who, ref path } => write!(err_out, "File {} for {} not found.", path, who),
            Error::WrongFileState { what, ref path } => write!(err_out, "File {} is not {}.", path, what),
            Error::FileParsingFailed { ref desc, ref errors } => write!(err_out, "Failed to parse {}: {}.", desc, errors),
        }
    }
}

impl StdError for Error {}