rivia/errors/
mod.rs

1//! Provides a common set of errors across the rivia crates to reduce the verbosity of error
2//! handling
3//!
4//! ### Using Rivia errors
5//! ```
6//! use rivia::prelude::*;
7//!
8//! let mut err = RvError::from(std::env::VarError::NotPresent);
9//! assert!(err.downcast_ref::<std::env::VarError>().is_some());
10//! assert!(err.downcast_mut::<std::env::VarError>().is_some());
11//! assert!(err.source().is_none());
12//! ```
13mod core;
14mod file;
15mod iter;
16mod path;
17mod string;
18mod user;
19mod vfs;
20
21use std::{error::Error as StdError, fmt, io, time::SystemTimeError};
22
23pub use file::*;
24pub use iter::*;
25pub use path::*;
26pub use string::*;
27pub use user::*;
28pub use vfs::*;
29
30pub use self::core::*;
31
32/// Provides a simplified Rivia result type with a common Rivia error type
33pub type RvResult<T> = std::result::Result<T, RvError>;
34
35/// An error that provides a common error for Rivia wrapping other internal errors
36#[derive(Debug)]
37pub enum RvError {
38    /// Core error
39    Core(CoreError),
40
41    /// File error
42    File(FileError),
43
44    /// An io error
45    Io(io::Error),
46
47    /// A interator error
48    Iter(IterError),
49
50    /// Nix low level error
51    Nix(nix::errno::Errno),
52
53    /// A pathing error
54    Path(PathError),
55
56    /// A string error
57    String(StringError),
58
59    /// A system time error
60    SystemTime(SystemTimeError),
61
62    /// A user errro
63    User(UserError),
64
65    /// An internal Utf8 error
66    Utf8(std::str::Utf8Error),
67
68    /// Environment variable error
69    Var(std::env::VarError),
70
71    /// Virtul File System errror
72    Vfs(VfsError),
73}
74
75impl RvError {
76    /// Implemented directly on the `Error` type to reduce casting required
77    pub fn is<T: StdError + 'static>(&self) -> bool {
78        self.as_ref().is::<T>()
79    }
80
81    /// Implemented directly on the `Error` type to reduce casting required
82    pub fn downcast_ref<T: StdError + 'static>(&self) -> Option<&T> {
83        self.as_ref().downcast_ref::<T>()
84    }
85
86    /// Implemented directly on the `Error` type to reduce casting required
87    pub fn downcast_mut<T: StdError + 'static>(&mut self) -> Option<&mut T> {
88        self.as_mut().downcast_mut::<T>()
89    }
90
91    /// Implemented directly on the `Error` type to reduce casting required
92    /// which allows for using as_ref to get the correct pass through.
93    pub fn source(&self) -> Option<&(dyn StdError + 'static)> {
94        self.as_ref().source()
95    }
96}
97impl StdError for RvError {}
98
99impl fmt::Display for RvError {
100    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
101        match *self {
102            RvError::Core(ref err) => write!(f, "{}", err),
103            RvError::File(ref err) => write!(f, "{}", err),
104            RvError::Io(ref err) => write!(f, "{}", err),
105            RvError::Iter(ref err) => write!(f, "{}", err),
106            RvError::Nix(ref err) => write!(f, "{}", err),
107            RvError::Path(ref err) => write!(f, "{}", err),
108            RvError::String(ref err) => write!(f, "{}", err),
109            RvError::SystemTime(ref err) => write!(f, "{}", err),
110            RvError::User(ref err) => write!(f, "{}", err),
111            RvError::Utf8(ref err) => write!(f, "{}", err),
112            RvError::Var(ref err) => write!(f, "{}", err),
113            RvError::Vfs(ref err) => write!(f, "{}", err),
114        }
115    }
116}
117
118impl AsRef<dyn StdError> for RvError {
119    fn as_ref(&self) -> &(dyn StdError + 'static) {
120        match *self {
121            RvError::Core(ref err) => err,
122            RvError::File(ref err) => err,
123            RvError::Io(ref err) => err,
124            RvError::Iter(ref err) => err,
125            RvError::Nix(ref err) => err,
126            RvError::Path(ref err) => err,
127            RvError::String(ref err) => err,
128            RvError::SystemTime(ref err) => err,
129            RvError::User(ref err) => err,
130            RvError::Utf8(ref err) => err,
131            RvError::Var(ref err) => err,
132            RvError::Vfs(ref err) => err,
133        }
134    }
135}
136
137impl AsMut<dyn StdError> for RvError {
138    fn as_mut(&mut self) -> &mut (dyn StdError + 'static) {
139        match *self {
140            RvError::Core(ref mut err) => err,
141            RvError::File(ref mut err) => err,
142            RvError::Io(ref mut err) => err,
143            RvError::Iter(ref mut err) => err,
144            RvError::Nix(ref mut err) => err,
145            RvError::Path(ref mut err) => err,
146            RvError::String(ref mut err) => err,
147            RvError::SystemTime(ref mut err) => err,
148            RvError::User(ref mut err) => err,
149            RvError::Utf8(ref mut err) => err,
150            RvError::Var(ref mut err) => err,
151            RvError::Vfs(ref mut err) => err,
152        }
153    }
154}
155
156impl From<CoreError> for RvError {
157    fn from(err: CoreError) -> RvError {
158        RvError::Core(err)
159    }
160}
161
162impl From<FileError> for RvError {
163    fn from(err: FileError) -> RvError {
164        RvError::File(err)
165    }
166}
167
168impl From<io::Error> for RvError {
169    fn from(err: io::Error) -> RvError {
170        RvError::Io(err)
171    }
172}
173
174impl From<IterError> for RvError {
175    fn from(err: IterError) -> RvError {
176        RvError::Iter(err)
177    }
178}
179
180impl From<nix::errno::Errno> for RvError {
181    fn from(err: nix::errno::Errno) -> RvError {
182        RvError::Nix(err)
183    }
184}
185
186impl From<PathError> for RvError {
187    fn from(err: PathError) -> RvError {
188        RvError::Path(err)
189    }
190}
191
192impl From<StringError> for RvError {
193    fn from(err: StringError) -> RvError {
194        RvError::String(err)
195    }
196}
197
198impl From<&str> for RvError {
199    fn from(err: &str) -> RvError {
200        RvError::Core(CoreError::msg(err))
201    }
202}
203
204impl From<SystemTimeError> for RvError {
205    fn from(err: SystemTimeError) -> RvError {
206        RvError::SystemTime(err)
207    }
208}
209
210impl From<UserError> for RvError {
211    fn from(err: UserError) -> RvError {
212        RvError::User(err)
213    }
214}
215
216impl From<std::str::Utf8Error> for RvError {
217    fn from(err: std::str::Utf8Error) -> RvError {
218        RvError::Utf8(err)
219    }
220}
221
222impl From<std::env::VarError> for RvError {
223    fn from(err: std::env::VarError) -> RvError {
224        RvError::Var(err)
225    }
226}
227
228impl From<VfsError> for RvError {
229    fn from(err: VfsError) -> RvError {
230        RvError::Vfs(err)
231    }
232}
233
234#[cfg(test)]
235mod tests {
236    use std::path::PathBuf;
237
238    use crate::errors::*;
239
240    #[test]
241    fn test_error() {
242        let mut err = RvError::from(CoreError::msg("foo"));
243        assert_eq!(err.to_string(), "foo");
244        assert_eq!(err.as_ref().to_string(), "foo");
245        assert_eq!(err.as_mut().to_string(), "foo");
246        assert!(err.downcast_ref::<CoreError>().is_some());
247        assert!(err.downcast_mut::<CoreError>().is_some());
248        assert!(err.source().is_none());
249
250        let mut err = RvError::from(io::Error::new(io::ErrorKind::AlreadyExists, "foo"));
251        assert_eq!("foo", err.to_string());
252        assert_eq!("foo", err.as_ref().to_string());
253        assert_eq!("foo", err.as_mut().to_string());
254        assert!(err.downcast_ref::<io::Error>().is_some());
255        assert!(err.downcast_mut::<io::Error>().is_some());
256        assert!(err.source().is_none());
257
258        let mut err = RvError::from(IterError::ItemNotFound);
259        assert_eq!("iterator item not found", err.to_string());
260        assert_eq!("iterator item not found", err.as_ref().to_string());
261        assert_eq!("iterator item not found", err.as_mut().to_string());
262        assert!(err.downcast_ref::<IterError>().is_some());
263        assert!(err.downcast_mut::<IterError>().is_some());
264        assert!(err.source().is_none());
265
266        let mut err = RvError::from(FileError::FailedToExtractString);
267        assert_eq!("Failed to extract string from file", err.to_string());
268        assert_eq!("Failed to extract string from file", err.as_ref().to_string());
269        assert_eq!("Failed to extract string from file", err.as_mut().to_string());
270        assert!(err.downcast_ref::<FileError>().is_some());
271        assert!(err.downcast_mut::<FileError>().is_some());
272        assert!(err.source().is_none());
273
274        let mut err = RvError::from(nix::errno::Errno::UnknownErrno);
275        assert_eq!(err.to_string(), "UnknownErrno: Unknown errno");
276        assert_eq!(err.as_ref().to_string(), "UnknownErrno: Unknown errno");
277        assert_eq!(err.as_mut().to_string(), "UnknownErrno: Unknown errno");
278        assert!(err.downcast_ref::<nix::errno::Errno>().is_some());
279        assert!(err.downcast_mut::<nix::errno::Errno>().is_some());
280        assert!(err.source().is_none());
281
282        let mut err = RvError::from(PathError::Empty);
283        assert_eq!("path empty", err.to_string());
284        assert_eq!("path empty", err.as_ref().to_string());
285        assert_eq!("path empty", err.as_mut().to_string());
286        assert!(err.downcast_ref::<PathError>().is_some());
287        assert!(err.downcast_mut::<PathError>().is_some());
288        assert!(err.source().is_none());
289
290        let mut err = RvError::from(StringError::FailedToString);
291        assert_eq!("failed to convert value to string", err.to_string());
292        assert_eq!("failed to convert value to string", err.as_ref().to_string());
293        assert_eq!("failed to convert value to string", err.as_mut().to_string());
294        assert!(err.downcast_ref::<StringError>().is_some());
295        assert!(err.downcast_mut::<StringError>().is_some());
296        assert!(err.source().is_none());
297
298        let time1 = std::time::SystemTime::now();
299        std::thread::sleep(std::time::Duration::from_millis(5));
300        let time2 = std::time::SystemTime::now();
301        let mut err = RvError::from(time1.duration_since(time2).unwrap_err());
302        assert_eq!(err.to_string(), "second time provided was later than self");
303        assert_eq!(err.as_ref().to_string(), "second time provided was later than self");
304        assert_eq!(err.as_mut().to_string(), "second time provided was later than self");
305        assert!(err.downcast_ref::<std::time::SystemTimeError>().is_some());
306        assert!(err.downcast_mut::<std::time::SystemTimeError>().is_some());
307        assert!(err.source().is_none());
308
309        let mut err = RvError::from(std::str::from_utf8(&vec![0, 159, 146, 150]).unwrap_err());
310        assert_eq!(err.to_string(), "invalid utf-8 sequence of 1 bytes from index 1");
311        assert_eq!(err.as_ref().to_string(), "invalid utf-8 sequence of 1 bytes from index 1");
312        assert_eq!(err.as_mut().to_string(), "invalid utf-8 sequence of 1 bytes from index 1");
313        assert!(err.downcast_ref::<std::str::Utf8Error>().is_some());
314        assert!(err.downcast_mut::<std::str::Utf8Error>().is_some());
315        assert!(err.source().is_none());
316
317        let mut err = RvError::from(std::env::VarError::NotPresent);
318        assert_eq!("environment variable not found", err.to_string());
319        assert_eq!("environment variable not found", err.as_ref().to_string());
320        assert_eq!("environment variable not found", err.as_mut().to_string());
321        assert!(err.downcast_ref::<std::env::VarError>().is_some());
322        assert!(err.downcast_mut::<std::env::VarError>().is_some());
323        assert!(err.source().is_none());
324
325        let mut err = RvError::from(VfsError::Unavailable);
326        assert_eq!("Virtual filesystem is unavailable", err.to_string());
327        assert_eq!("Virtual filesystem is unavailable", err.as_ref().to_string());
328        assert_eq!("Virtual filesystem is unavailable", err.as_mut().to_string());
329        assert!(err.downcast_ref::<VfsError>().is_some());
330        assert!(err.downcast_mut::<VfsError>().is_some());
331        assert!(err.source().is_none());
332    }
333
334    fn path_empty() -> RvResult<PathBuf> {
335        Err(PathError::Empty)?
336    }
337
338    #[test]
339    fn test_is() {
340        assert!(path_empty().is_err());
341        assert!(path_empty().unwrap_err().is::<PathError>());
342    }
343
344    #[test]
345    fn test_downcast_ref() {
346        assert!(path_empty().is_err());
347        assert_eq!(path_empty().unwrap_err().downcast_ref::<PathError>(), Some(&PathError::Empty));
348    }
349}