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
use std::{fmt, io};
use requestty::ErrorKind;
use std::error::Error;
use std::num::ParseIntError;
use RunError::*;
pub type Result<T> = std::result::Result<T, RunError>;
#[derive(Debug)]
pub enum RunError {
Clap(ClapError),
InvalidYearRange(ParseIntError),
NoSearchResults,
Reqwest(reqwest::Error),
InputUserHalted,
InputIo(io::Error),
NoDesiredSearchResults,
Serde(Box<dyn Error>),
OmdbNotFound(String),
OmdbUnrecognised(String, serde_json::Error),
}
impl RunError {
pub fn error_code(&self) -> i32 {
match self {
Clap(_) => 1,
InvalidYearRange(_) => 1,
NoSearchResults => 1,
Reqwest(_) => 2,
InputUserHalted => 1,
InputIo(_) => 2,
NoDesiredSearchResults => 0,
Serde(_) => 2,
OmdbNotFound(_) => 1,
OmdbUnrecognised(_, _) => 2,
}
}
}
impl fmt::Display for RunError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Clap(clap_err) => write!(f, "Argument parsing problem: {}", clap_err),
InvalidYearRange(err) => write!(f, "Invalid year / year range: {}", err),
NoSearchResults => write!(f, "No search results"),
Reqwest(reqwest_err) => write!(f, "Issue with web request: {}", reqwest_err),
InputUserHalted => write!(f, "Program halted at user request"),
InputIo(io_err) => write!(f, "IO error: {}", io_err),
NoDesiredSearchResults => write!(f, "You couldn't find what you wanted :("),
Serde(e) => write!(f, "Failed to serialise output data: {}", e),
OmdbNotFound(search_term) => write!(f, "No record found on OMDb for {:?}", search_term),
OmdbUnrecognised(json, err) => write!(
f,
"Unrecognised response from OMDb, please raise an issue including the following text:\n\
Serde error: \n\
```\n\
{}\n\
```\n\
JSON: \n\
```\n\
{}\n\
```",
err, json
),
}
}
}
impl Error for RunError {}
impl From<ClapError> for RunError {
fn from(clap_err: ClapError) -> Self {
Clap(clap_err)
}
}
impl From<reqwest::Error> for RunError {
fn from(reqwest_err: reqwest::Error) -> Self {
Reqwest(reqwest_err)
}
}
impl From<requestty::ErrorKind> for RunError {
fn from(requestty_err: ErrorKind) -> Self {
use requestty::ErrorKind::*;
match requestty_err {
Eof | Interrupted => InputUserHalted,
IoError(io_err) => Self::from(io_err),
}
}
}
impl From<io::Error> for RunError {
fn from(io_err: io::Error) -> Self {
InputIo(io_err)
}
}
impl From<serde_json::Error> for RunError {
fn from(ser_err: serde_json::Error) -> Self {
Serde(Box::new(ser_err))
}
}
#[cfg(feature = "yaml")]
impl From<serde_yaml::Error> for RunError {
fn from(ser_err: serde_yaml::Error) -> Self {
Serde(Box::new(ser_err))
}
}
#[derive(Debug, Copy, Clone)]
pub enum ClapError {
NotUsize,
InvalidFormat,
}
impl fmt::Display for ClapError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use ClapError::*;
match self {
NotUsize => write!(f, "expected a positive integer"),
InvalidFormat => write!(
f,
"invalid format\nIf you think this should have \
worked, please ensure you installed the tool with the required features\n\
See the project README for more information"
),
}
}
}
impl Error for ClapError {}