1 | //! Error types
|
2 |
|
3 | use crate::Config;
|
4 | use std::error::Error as StdError;
|
5 | use std::path::PathBuf;
|
6 | use std::result::Result as StdResult;
|
7 | use std::{self, fmt, io};
|
8 |
|
9 | /// Type alias to use this library's `Error` type in a Result
|
10 | pub type Result<T> = StdResult<T, Error>;
|
11 |
|
12 | /// Error kinds
|
13 | #[derive (Debug)]
|
14 | pub enum ErrorKind {
|
15 | /// Generic error
|
16 | ///
|
17 | /// May be used in cases where a platform specific error is mapped to this type, or for opaque
|
18 | /// internal errors.
|
19 | Generic(String),
|
20 |
|
21 | /// I/O errors.
|
22 | Io(io::Error),
|
23 |
|
24 | /// A path does not exist.
|
25 | PathNotFound,
|
26 |
|
27 | /// Attempted to remove a watch that does not exist.
|
28 | WatchNotFound,
|
29 |
|
30 | /// An invalid value was passed as runtime configuration.
|
31 | InvalidConfig(Config),
|
32 |
|
33 | /// Can't watch (more) files, limit on the total number of inotify watches reached
|
34 | MaxFilesWatch,
|
35 | }
|
36 |
|
37 | /// Notify error type.
|
38 | ///
|
39 | /// Errors are emitted either at creation time of a `Watcher`, or during the event stream. They
|
40 | /// range from kernel errors to filesystem errors to argument errors.
|
41 | ///
|
42 | /// Errors can be general, or they can be about specific paths or subtrees. In that later case, the
|
43 | /// error's `paths` field will be populated.
|
44 | #[derive (Debug)]
|
45 | pub struct Error {
|
46 | /// Kind of the error.
|
47 | pub kind: ErrorKind,
|
48 |
|
49 | /// Relevant paths to the error, if any.
|
50 | pub paths: Vec<PathBuf>,
|
51 | }
|
52 |
|
53 | impl Error {
|
54 | /// Adds a path to the error.
|
55 | pub fn add_path(mut self, path: PathBuf) -> Self {
|
56 | self.paths.push(path);
|
57 | self
|
58 | }
|
59 |
|
60 | /// Replaces the paths for the error.
|
61 | pub fn set_paths(mut self, paths: Vec<PathBuf>) -> Self {
|
62 | self.paths = paths;
|
63 | self
|
64 | }
|
65 |
|
66 | /// Creates a new Error with empty paths given its kind.
|
67 | pub fn new(kind: ErrorKind) -> Self {
|
68 | Self {
|
69 | kind,
|
70 | paths: Vec::new(),
|
71 | }
|
72 | }
|
73 |
|
74 | /// Creates a new generic Error from a message.
|
75 | pub fn generic(msg: &str) -> Self {
|
76 | Self::new(ErrorKind::Generic(msg.into()))
|
77 | }
|
78 |
|
79 | /// Creates a new i/o Error from a stdlib `io::Error`.
|
80 | pub fn io(err: io::Error) -> Self {
|
81 | Self::new(ErrorKind::Io(err))
|
82 | }
|
83 |
|
84 | /// Creates a new "path not found" error.
|
85 | pub fn path_not_found() -> Self {
|
86 | Self::new(ErrorKind::PathNotFound)
|
87 | }
|
88 |
|
89 | /// Creates a new "watch not found" error.
|
90 | pub fn watch_not_found() -> Self {
|
91 | Self::new(ErrorKind::WatchNotFound)
|
92 | }
|
93 |
|
94 | /// Creates a new "invalid config" error from the given `Config`.
|
95 | pub fn invalid_config(config: &Config) -> Self {
|
96 | Self::new(ErrorKind::InvalidConfig(config.clone()))
|
97 | }
|
98 | }
|
99 |
|
100 | impl fmt::Display for Error {
|
101 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
102 | let error: String = match self.kind {
|
103 | ErrorKind::PathNotFound => "No path was found." .into(),
|
104 | ErrorKind::WatchNotFound => "No watch was found." .into(),
|
105 | ErrorKind::InvalidConfig(ref config: &Config) => format!("Invalid configuration: {:?}" , config),
|
106 | ErrorKind::Generic(ref err: &String) => err.clone(),
|
107 | ErrorKind::Io(ref err: &Error) => err.to_string(),
|
108 | ErrorKind::MaxFilesWatch => "OS file watch limit reached." .into(),
|
109 | };
|
110 |
|
111 | if self.paths.is_empty() {
|
112 | write!(f, " {}" , error)
|
113 | } else {
|
114 | write!(f, " {} about {:?}" , error, self.paths)
|
115 | }
|
116 | }
|
117 | }
|
118 |
|
119 | impl StdError for Error {
|
120 | fn cause(&self) -> Option<&dyn StdError> {
|
121 | match self.kind {
|
122 | ErrorKind::Io(ref cause: &Error) => Some(cause),
|
123 | _ => None,
|
124 | }
|
125 | }
|
126 | }
|
127 |
|
128 | impl From<io::Error> for Error {
|
129 | fn from(err: io::Error) -> Self {
|
130 | Error::io(err)
|
131 | }
|
132 | }
|
133 |
|
134 | #[cfg (feature = "crossbeam-channel" )]
|
135 | impl<T> From<crossbeam_channel::SendError<T>> for Error {
|
136 | fn from(err: crossbeam_channel::SendError<T>) -> Self {
|
137 | Error::generic(&format!("internal channel disconnect: {:?}" , err))
|
138 | }
|
139 | }
|
140 | #[cfg (not(feature = "crossbeam-channel" ))]
|
141 | impl<T> From<std::sync::mpsc::SendError<T>> for Error {
|
142 | fn from(err: std::sync::mpsc::SendError<T>) -> Self {
|
143 | Error::generic(&format!("internal channel disconnect: {:?}" , err))
|
144 | }
|
145 | }
|
146 | #[cfg (feature = "crossbeam-channel" )]
|
147 | impl From<crossbeam_channel::RecvError> for Error {
|
148 | fn from(err: crossbeam_channel::RecvError) -> Self {
|
149 | Error::generic(&format!("internal channel disconnect: {:?}" , err))
|
150 | }
|
151 | }
|
152 | #[cfg (not(feature = "crossbeam-channel" ))]
|
153 | impl From<std::sync::mpsc::RecvError> for Error {
|
154 | fn from(err: std::sync::mpsc::RecvError) -> Self {
|
155 | Error::generic(&format!("internal channel disconnect: {:?}" , err))
|
156 | }
|
157 | }
|
158 |
|
159 | impl<T> From<std::sync::PoisonError<T>> for Error {
|
160 | fn from(err: std::sync::PoisonError<T>) -> Self {
|
161 | Error::generic(&format!("internal mutex poisoned: {:?}" , err))
|
162 | }
|
163 | }
|
164 |
|
165 | #[test ]
|
166 | fn display_formatted_errors() {
|
167 | let expected: &str = "Some error" ;
|
168 |
|
169 | assert_eq!(expected, format!(" {}" , Error::generic(expected)));
|
170 |
|
171 | assert_eq!(
|
172 | expected,
|
173 | format!(
|
174 | " {}" ,
|
175 | Error::io(io::Error::new(io::ErrorKind::Other, expected))
|
176 | )
|
177 | );
|
178 | }
|
179 | |