Skip to main content

fungus/errors/
path_error.rs

1use std::{
2    error::Error as StdError,
3    fmt,
4    path::{Path, PathBuf},
5};
6
7// An error indicating that something went wrong with a path operation
8#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
9pub enum PathError {
10    /// An error indicating that the path does not exist.
11    DoesNotExist(PathBuf),
12
13    /// An error indicating that the path is empty.
14    Empty,
15
16    /// An error indicating that the path exists already.
17    ExistsAlready(PathBuf),
18
19    /// An error indicating that the path does not have an extension.
20    ExtensionNotFound(PathBuf),
21
22    /// An error indicating a failure to convert the path to a string.
23    FailedToString(PathBuf),
24
25    /// An error indicating that the path does not contain a filename.
26    FileNameNotFound(PathBuf),
27
28    /// An error indicating that the path failed to expand properly.
29    InvalidExpansion(PathBuf),
30
31    /// An error indicating that the path is not a directory.
32    IsNotDir(PathBuf),
33
34    /// An error indicating that the path is not an executable file.
35    IsNotExec(PathBuf),
36
37    /// An error indicating that the path is not a file.
38    IsNotFile(PathBuf),
39
40    /// An error indicating that the path is not a file or symlink to a file.
41    IsNotFileOrSymlinkToFile(PathBuf),
42
43    /// An error indicating that the path contains multiple user home symbols i.e. tilda.
44    MultipleHomeSymbols(PathBuf),
45
46    /// An error indicating that the path does not have a valid parent path.
47    ParentNotFound(PathBuf),
48}
49impl PathError {
50    /// Return an error indicating that the path does not exist
51    pub fn does_not_exist<T: AsRef<Path>>(path: T) -> PathError {
52        PathError::DoesNotExist(path.as_ref().to_path_buf())
53    }
54
55    /// Return an error indicating that the path exists already
56    pub fn exists_already<T: AsRef<Path>>(path: T) -> PathError {
57        PathError::ExistsAlready(path.as_ref().to_path_buf())
58    }
59
60    /// Return an error indicating that the path extension was not found
61    pub fn extension_not_found<T: AsRef<Path>>(path: T) -> PathError {
62        PathError::ExtensionNotFound(path.as_ref().to_path_buf())
63    }
64
65    /// Return an error indicating a failure to convert the path to a string
66    pub fn failed_to_string<T: AsRef<Path>>(path: T) -> PathError {
67        PathError::FailedToString(path.as_ref().to_path_buf())
68    }
69
70    /// Return an error indicating that the path does not contain a filename
71    pub fn filename_not_found<T: AsRef<Path>>(path: T) -> PathError {
72        PathError::FileNameNotFound(path.as_ref().to_path_buf())
73    }
74
75    /// Return an error indicating that the path is not a directory
76    pub fn is_not_dir<T: AsRef<Path>>(path: T) -> PathError {
77        PathError::IsNotDir(path.as_ref().to_path_buf())
78    }
79
80    /// Return an error indicating that the path is not an executable
81    pub fn is_not_exec<T: AsRef<Path>>(path: T) -> PathError {
82        PathError::IsNotExec(path.as_ref().to_path_buf())
83    }
84
85    /// Return an error indicating that the path is not a file
86    pub fn is_not_file<T: AsRef<Path>>(path: T) -> PathError {
87        PathError::IsNotFile(path.as_ref().to_path_buf())
88    }
89
90    /// Return an error indicating that the path is not a file or symlink to file
91    pub fn is_not_file_or_symlink_to_file<T: AsRef<Path>>(path: T) -> PathError {
92        PathError::IsNotFileOrSymlinkToFile(path.as_ref().to_path_buf())
93    }
94
95    /// Return an error indicating that the path failed to expand properly
96    pub fn invalid_expansion<T: AsRef<Path>>(path: T) -> PathError {
97        PathError::InvalidExpansion(path.as_ref().to_path_buf())
98    }
99
100    /// Return an error indicating that the path contains multiple user home symbols i.e. tilda
101    pub fn multiple_home_symbols<T: AsRef<Path>>(path: T) -> PathError {
102        PathError::MultipleHomeSymbols(path.as_ref().to_path_buf())
103    }
104
105    /// Return an error indicating that the path does not have a valid parent path
106    pub fn parent_not_found<T: AsRef<Path>>(path: T) -> PathError {
107        PathError::ParentNotFound(path.as_ref().to_path_buf())
108    }
109}
110
111impl StdError for PathError {}
112
113impl AsRef<dyn StdError> for PathError {
114    fn as_ref(&self) -> &(dyn StdError+'static) {
115        self
116    }
117}
118
119impl fmt::Display for PathError {
120    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
121        match *self {
122            PathError::DoesNotExist(ref path) => write!(f, "path does not exist: {}", path.display()),
123            PathError::Empty => write!(f, "path empty"),
124            PathError::ExistsAlready(ref path) => write!(f, "path exists already: {}", path.display()),
125            PathError::ExtensionNotFound(ref path) => write!(f, "path extension not found: {}", path.display()),
126            PathError::FailedToString(ref path) => write!(f, "failed to convert to string for path: {}", path.display()),
127            PathError::FileNameNotFound(ref path) => write!(f, "filename not found for path: {}", path.display()),
128            PathError::InvalidExpansion(ref path) => write!(f, "invalid expansion for path: {}", path.display()),
129            PathError::IsNotDir(ref path) => write!(f, "is not a directory: {}", path.display()),
130            PathError::IsNotExec(ref path) => write!(f, "is not an executable: {}", path.display()),
131            PathError::IsNotFile(ref path) => write!(f, "is not a file: {}", path.display()),
132            PathError::IsNotFileOrSymlinkToFile(ref path) => write!(f, "is not a file or a symlink to a file: {}", path.display()),
133            PathError::MultipleHomeSymbols(ref path) => write!(f, "multiple home symbols for path: {}", path.display()),
134            PathError::ParentNotFound(ref path) => write!(f, "parent not found for path: {}", path.display()),
135        }
136    }
137}
138
139#[cfg(test)]
140mod tests {
141    use crate::prelude::*;
142
143    fn path_empty() -> FuResult<PathBuf> {
144        Err(PathError::Empty)?
145    }
146
147    fn parent_not_found() -> FuResult<PathBuf> {
148        Err(PathError::parent_not_found("foo"))?
149    }
150
151    #[test]
152    fn test_new_path_empty() {
153        assert!(path_empty().is_err());
154        assert_eq!(path_empty().unwrap_err().downcast_ref::<PathError>(), Some(&PathError::Empty));
155    }
156
157    #[test]
158    fn test_parent_not_found() {
159        assert!(parent_not_found().is_err());
160        assert_ne!(parent_not_found().unwrap_err().downcast_ref::<PathError>(), Some(&PathError::parent_not_found("bar")));
161        assert_eq!(parent_not_found().unwrap_err().downcast_ref::<PathError>(), Some(&PathError::parent_not_found("foo")));
162        assert_eq!(format!("{}", parent_not_found().unwrap_err().downcast_ref::<PathError>().unwrap()), "parent not found for path: foo");
163    }
164
165    #[test]
166    fn test_other_errors() {
167        assert_eq!(PathError::does_not_exist(Path::new("foo")), PathError::DoesNotExist(PathBuf::from("foo")));
168        assert_eq!(format!("{}", PathError::DoesNotExist(PathBuf::from("foo"))), "path does not exist: foo");
169        assert_eq!(format!("{}", PathError::Empty), "path empty");
170        assert_eq!(PathError::exists_already(Path::new("foo")), PathError::ExistsAlready(PathBuf::from("foo")));
171        assert_eq!(format!("{}", PathError::ExistsAlready(PathBuf::from("foo"))), "path exists already: foo");
172        assert_eq!(PathError::extension_not_found(Path::new("foo")), PathError::ExtensionNotFound(PathBuf::from("foo")));
173        assert_eq!(format!("{}", PathError::ExtensionNotFound(PathBuf::from("foo"))), "path extension not found: foo");
174        assert_eq!(PathError::failed_to_string(Path::new("foo")), PathError::FailedToString(PathBuf::from("foo")));
175        assert_eq!(format!("{}", PathError::failed_to_string(PathBuf::from("foo"))), "failed to convert to string for path: foo");
176        assert_eq!(PathError::filename_not_found(Path::new("foo")), PathError::FileNameNotFound(PathBuf::from("foo")));
177        assert_eq!(format!("{}", PathError::filename_not_found(PathBuf::from("foo"))), "filename not found for path: foo");
178        assert_eq!(PathError::invalid_expansion(Path::new("foo")), PathError::InvalidExpansion(PathBuf::from("foo")));
179        assert_eq!(format!("{}", PathError::invalid_expansion(PathBuf::from("foo"))), "invalid expansion for path: foo");
180        assert_eq!(PathError::is_not_dir(Path::new("foo")), PathError::IsNotDir(PathBuf::from("foo")));
181        assert_eq!(format!("{}", PathError::is_not_dir(PathBuf::from("foo"))), "is not a directory: foo");
182        assert_eq!(PathError::is_not_exec(Path::new("foo")), PathError::IsNotExec(PathBuf::from("foo")));
183        assert_eq!(format!("{}", PathError::is_not_exec(PathBuf::from("foo"))), "is not an executable: foo");
184        assert_eq!(PathError::is_not_file(Path::new("foo")), PathError::IsNotFile(PathBuf::from("foo")));
185        assert_eq!(format!("{}", PathError::is_not_file(PathBuf::from("foo"))), "is not a file: foo");
186        assert_eq!(PathError::is_not_file_or_symlink_to_file(Path::new("foo")), PathError::IsNotFileOrSymlinkToFile(PathBuf::from("foo")));
187        assert_eq!(format!("{}", PathError::is_not_file_or_symlink_to_file(PathBuf::from("foo"))), "is not a file or a symlink to a file: foo");
188        assert_eq!(PathError::multiple_home_symbols(Path::new("foo")), PathError::MultipleHomeSymbols(PathBuf::from("foo")));
189        assert_eq!(format!("{}", PathError::multiple_home_symbols(PathBuf::from("foo"))), "multiple home symbols for path: foo");
190    }
191
192    #[test]
193    fn test_backtrace() {
194        let err = path_empty().unwrap_err();
195        println!("{:?}", err);
196    }
197}