1use crate::Config;
4use std::error::Error as StdError;
5use std::path::PathBuf;
6use std::result::Result as StdResult;
7use std::{self, fmt, io};
8
9pub type Result<T> = StdResult<T, Error>;
11
12#[derive(Debug)]
14pub enum ErrorKind {
15 Generic(String),
20
21 Io(io::Error),
23
24 PathNotFound,
26
27 WatchNotFound,
29
30 InvalidConfig(Config),
32
33 MaxFilesWatch,
35}
36
37#[derive(Debug)]
45pub struct Error {
46 pub kind: ErrorKind,
48
49 pub paths: Vec<PathBuf>,
51}
52
53impl Error {
54 pub fn add_path(mut self, path: PathBuf) -> Self {
56 self.paths.push(path);
57 self
58 }
59
60 pub fn set_paths(mut self, paths: Vec<PathBuf>) -> Self {
62 self.paths = paths;
63 self
64 }
65
66 pub fn new(kind: ErrorKind) -> Self {
68 Self {
69 kind,
70 paths: Vec::new(),
71 }
72 }
73
74 pub fn generic(msg: &str) -> Self {
76 Self::new(ErrorKind::Generic(msg.into()))
77 }
78
79 pub fn io(err: io::Error) -> Self {
81 Self::new(ErrorKind::Io(err))
82 }
83
84 pub fn io_watch(err: io::Error) -> Self {
86 if err.kind() == io::ErrorKind::NotFound {
87 Self::path_not_found()
88 } else {
89 Self::io(err)
90 }
91 }
92
93 pub fn path_not_found() -> Self {
95 Self::new(ErrorKind::PathNotFound)
96 }
97
98 pub fn watch_not_found() -> Self {
100 Self::new(ErrorKind::WatchNotFound)
101 }
102
103 pub fn invalid_config(config: &Config) -> Self {
105 Self::new(ErrorKind::InvalidConfig(*config))
106 }
107}
108
109impl fmt::Display for Error {
110 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
111 let error = match self.kind {
112 ErrorKind::PathNotFound => "No path was found.".into(),
113 ErrorKind::WatchNotFound => "No watch was found.".into(),
114 ErrorKind::InvalidConfig(ref config) => format!("Invalid configuration: {:?}", config),
115 ErrorKind::Generic(ref err) => err.clone(),
116 ErrorKind::Io(ref err) => err.to_string(),
117 ErrorKind::MaxFilesWatch => "OS file watch limit reached.".into(),
118 };
119
120 if self.paths.is_empty() {
121 write!(f, "{}", error)
122 } else {
123 write!(f, "{} about {:?}", error, self.paths)
124 }
125 }
126}
127
128impl StdError for Error {
129 fn cause(&self) -> Option<&dyn StdError> {
130 match self.kind {
131 ErrorKind::Io(ref cause) => Some(cause),
132 _ => None,
133 }
134 }
135}
136
137impl From<io::Error> for Error {
138 fn from(err: io::Error) -> Self {
139 Error::io(err)
140 }
141}
142
143impl<T> From<std::sync::mpsc::SendError<T>> for Error {
144 fn from(err: std::sync::mpsc::SendError<T>) -> Self {
145 Error::generic(&format!("internal channel disconnect: {:?}", err))
146 }
147}
148
149impl From<std::sync::mpsc::RecvError> for Error {
150 fn from(err: std::sync::mpsc::RecvError) -> Self {
151 Error::generic(&format!("internal channel disconnect: {:?}", err))
152 }
153}
154
155impl<T> From<std::sync::PoisonError<T>> for Error {
156 fn from(err: std::sync::PoisonError<T>) -> Self {
157 Error::generic(&format!("internal mutex poisoned: {:?}", err))
158 }
159}
160
161#[test]
162fn display_formatted_errors() {
163 let expected = "Some error";
164
165 assert_eq!(expected, format!("{}", Error::generic(expected)));
166
167 assert_eq!(
168 expected,
169 format!(
170 "{}",
171 Error::io(io::Error::new(io::ErrorKind::Other, expected))
172 )
173 );
174}