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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
//! Error types used by this crate

use chrono;
use git2;
use std::{
    fmt::{self, Display},
    io,
    str::Utf8Error,
};
use thiserror::Error;
use toml;

/// Create a new error (of a given enum variant) with a formatted message
macro_rules! format_err {
    ($kind:path, $msg:expr) => {
        crate::error::Error::new(
            $kind,
            &$msg.to_string()
        )
    };
    ($kind:path, $fmt:expr, $($arg:tt)+) => {
        format_err!($kind, &format!($fmt, $($arg)+))
    };
}

/// Create and return an error with a formatted message
macro_rules! fail {
    ($kind:path, $msg:expr) => {
        return Err(format_err!($kind, $msg).into());
    };
    ($kind:path, $fmt:expr, $($arg:tt)+) => {
        fail!($kind, &format!($fmt, $($arg)+));
    };
}

/// Error type
#[derive(Debug)]
pub struct Error {
    /// Kind of error
    kind: ErrorKind,

    /// Message providing additional information
    msg: String,
}

impl Error {
    /// Create a new error with the given description
    pub fn new<S: ToString>(kind: ErrorKind, description: &S) -> Self {
        Self {
            kind,
            msg: description.to_string(),
        }
    }

    /// Obtain the inner `ErrorKind` for this error
    pub fn kind(&self) -> ErrorKind {
        self.kind
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}: {}", &self.kind, &self.msg)
    }
}

impl std::error::Error for Error {}

/// Custom error type for this library
#[derive(Copy, Clone, Debug, Error, Eq, PartialEq)]
pub enum ErrorKind {
    /// Invalid argument or parameter
    #[error("bad parameter")]
    BadParam,

    /// Error performing an automatic fix
    #[cfg(feature = "fix")]
    #[error("fix failed")]
    Fix,

    /// An error occurred performing an I/O operation (e.g. network, file)
    #[error("I/O operation failed")]
    Io,

    /// Not found
    #[error("not found")]
    NotFound,

    /// Couldn't parse response data
    #[error("parse error")]
    Parse,

    /// Registry-related error
    #[error("registry")]
    Registry,

    /// Git operation failed
    #[error("git operation failed")]
    Repo,

    /// Errors related to versions
    #[error("bad version")]
    Version,
}

impl From<Utf8Error> for Error {
    fn from(other: Utf8Error) -> Self {
        format_err!(ErrorKind::Parse, &other)
    }
}

#[cfg(feature = "fix")]
impl From<cargo_edit::Error> for Error {
    fn from(other: cargo_edit::Error) -> Self {
        format_err!(ErrorKind::Fix, &other)
    }
}

impl From<chrono::ParseError> for Error {
    fn from(other: chrono::ParseError) -> Self {
        format_err!(ErrorKind::Parse, &other)
    }
}

impl From<fmt::Error> for Error {
    fn from(other: fmt::Error) -> Self {
        format_err!(ErrorKind::Io, &other)
    }
}

impl From<git2::Error> for Error {
    fn from(other: git2::Error) -> Self {
        format_err!(ErrorKind::Repo, &other)
    }
}

impl From<io::Error> for Error {
    fn from(other: io::Error) -> Self {
        format_err!(ErrorKind::Io, &other)
    }
}

impl From<crates_index::Error> for Error {
    fn from(other: crates_index::Error) -> Self {
        format_err!(ErrorKind::Registry, "{}", other)
    }
}

impl From<semver::SemVerError> for Error {
    fn from(other: semver::SemVerError) -> Self {
        format_err!(ErrorKind::Version, &other)
    }
}

impl From<semver::ReqParseError> for Error {
    fn from(other: semver::ReqParseError) -> Self {
        format_err!(ErrorKind::Version, &other)
    }
}

impl From<toml::de::Error> for Error {
    fn from(other: toml::de::Error) -> Self {
        format_err!(ErrorKind::Parse, &other)
    }
}