Skip to main content

custom_codes/
anyhow_downcast.rs

1use std::error::Error;
2use std::fmt;
3use std::io::ErrorKind;
4
5/// Eenable downcasting to a borrowed string
6#[derive(Debug)]
7pub struct BorrowedStr<'se>(pub &'se str);
8
9impl<'se> fmt::Display for BorrowedStr<'se> {
10    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
11        write!(f, "{}", self.0)
12    }
13}
14
15impl<'se> Error for BorrowedStr<'se> {}
16
17/// Convert a `String`, `&'_ str`, `OsStr` or `OsString` into this type to enable downcasting to a string
18#[derive(Debug)]
19pub struct StringifyError(pub String);
20
21impl<'se> fmt::Display for StringifyError {
22    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23        write!(f, "{}", self.0)
24    }
25}
26
27impl<'se> Error for StringifyError {}
28
29/// All common errors for use in crates. They mirror std::io::ErrorKind;
30#[derive(Debug)]
31pub enum DownCastErrors<'se> {
32    /// An entity was not found, often a file.
33    NotFound,
34    /// The operation lacked the necessary privileges to complete.
35    PermissionDenied,
36    /// The connection was refused by the remote server.
37    ConnectionRefused,
38    /// The connection was reset by the remote server.
39    ConnectionReset,
40    /// The connection was aborted (terminated) by the remote server.
41    ConnectionAborted,
42    /// The network operation failed because it was not connected yet.
43    NotConnected,
44    /// A socket address could not be bound because the address is already in use elsewhere.
45    AddrInUse,
46    /// A nonexistent interface was requested or the requested address was not local.
47    AddrNotAvailable,
48    /// The operation failed because a pipe was closed.
49    BrokenPipe,
50    /// An entity already exists, often a file.
51    AlreadyExists,
52    /// The operation needs to block to complete, but the blocking operation was requested to not occur.
53    WouldBlock,
54    /// A parameter was incorrect.
55    InvalidInput,
56    ///Data not valid for the operation were encountered.
57    ///
58    ///Unlike `InvalidInput`, this typically means that the operation parameters were valid, however the error was caused by malformed input data.
59    ///
60    ///For example, a function that reads a file into a string will error with `InvalidData` if the file's contents are not valid UTF-8.
61    InvalidData,
62    /// The I/O operation's timeout expired, causing it to be canceled.
63    TimedOut,
64    /// An error returned when an operation could not be completed because a call to write returned `Ok(0)`.
65    ///
66    ///This typically means that an operation could only succeed if it wrote a particular number of bytes but only a smaller number of bytes could be written.
67    WriteZero,
68    /// This operation was interrupted.
69    ///
70    /// Interrupted operations can typically be retried.
71    Interrupted,
72    /// Any I/O error not part of this list.
73    Other,
74    /// An error returned when an operation could not be completed because an "end of file" was reached prematurely.
75    ///
76    ///This typically means that an operation could only succeed if it read a particular number of bytes but only a smaller number of bytes could be read.
77    UnexpectedEof,
78    /// This error is not specified yet
79    Unspecified,
80    /// Any `StripPrefix`  error
81    StripPrefixError(std::path::StripPrefixError),
82    /// An `OsString` Error
83    Stringify(String),
84    /// Returns an error as a borrowed string
85    BorrowedStr(&'se str),
86    /// The file is invalid
87    InvalidFile,
88    /// Name of a file is invalid
89    InvalidFileName,
90    /// Path is not a directory
91    InvalidFolder,
92    /// Path is not valid
93    InvalidPath,
94    /// No matches were found when downcasting the error to `std::io::Error` so it is not an `I/O` error
95    Unmatched(&'se anyhow::Error),
96}
97
98/// This method tries to downcast an `anyhow::Error` to return a `DownCastErrors` enum for common error handling
99pub fn try_downcast(error: &anyhow::Error) -> DownCastErrors {
100    if let Some(ioerror) = error.root_cause().downcast_ref::<std::io::Error>() {
101        let kind = ioerror.kind();
102
103        match kind {
104            ErrorKind::NotFound => DownCastErrors::NotFound,
105            ErrorKind::PermissionDenied => DownCastErrors::PermissionDenied,
106            ErrorKind::ConnectionRefused => DownCastErrors::ConnectionRefused,
107            ErrorKind::ConnectionReset => DownCastErrors::ConnectionReset,
108            ErrorKind::ConnectionAborted => DownCastErrors::ConnectionAborted,
109            ErrorKind::NotConnected => DownCastErrors::NotConnected,
110            ErrorKind::AddrInUse => DownCastErrors::AddrInUse,
111            ErrorKind::AddrNotAvailable => DownCastErrors::AddrNotAvailable,
112            ErrorKind::BrokenPipe => DownCastErrors::BrokenPipe,
113            ErrorKind::AlreadyExists => DownCastErrors::AlreadyExists,
114            ErrorKind::WouldBlock => DownCastErrors::WouldBlock,
115            ErrorKind::InvalidInput => DownCastErrors::InvalidInput,
116            ErrorKind::InvalidData => DownCastErrors::InvalidData,
117            ErrorKind::TimedOut => DownCastErrors::TimedOut,
118            ErrorKind::WriteZero => DownCastErrors::WriteZero,
119            ErrorKind::Interrupted => DownCastErrors::Interrupted,
120            ErrorKind::Other => DownCastErrors::Other,
121            ErrorKind::UnexpectedEof => DownCastErrors::UnexpectedEof,
122            _ => DownCastErrors::Unspecified,
123        }
124    } else if let Some(strip_prefix_error) = error
125        .root_cause()
126        .downcast_ref::<std::path::StripPrefixError>()
127    {
128        DownCastErrors::StripPrefixError(strip_prefix_error.clone())
129    } else if let Some(os_string_error) = error.root_cause().downcast_ref::<StringifyError>() {
130        DownCastErrors::Stringify(os_string_error.0.clone())
131    } else if let Some(borrowed_str) = error.root_cause().downcast_ref::<BorrowedStr>() {
132        DownCastErrors::BorrowedStr(borrowed_str.0)
133    } else if error.root_cause().downcast_ref::<InvalidFile>().is_some() {
134        DownCastErrors::InvalidFile
135    } else if error
136        .root_cause()
137        .downcast_ref::<InvalidFileName>()
138        .is_some()
139    {
140        DownCastErrors::InvalidFileName
141    } else if error.root_cause().downcast_ref::<InvalidFolder>().is_some() {
142        DownCastErrors::InvalidFolder
143    } else if error.root_cause().downcast_ref::<InvalidPath>().is_some() {
144        DownCastErrors::InvalidPath
145    } else {
146        DownCastErrors::Unmatched(error)
147    }
148}
149
150/// Enables downcasting an invalid file to produce `DownCastError`
151#[derive(Debug)]
152pub struct InvalidFile;
153
154impl fmt::Display for InvalidFile {
155    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
156        write!(f, "{}", self)
157    }
158}
159
160impl Error for InvalidFile {}
161
162/// Enables downcasting an invalid file name to produce `DownCastError`
163#[derive(Debug)]
164pub struct InvalidFileName;
165
166impl fmt::Display for InvalidFileName {
167    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
168        write!(f, "{}", self)
169    }
170}
171
172impl Error for InvalidFileName {}
173
174/// Enables downcasting an invalid folder to produce `DownCastError`
175#[derive(Debug)]
176pub struct InvalidFolder;
177
178impl fmt::Display for InvalidFolder {
179    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
180        write!(f, "{}", self)
181    }
182}
183
184impl Error for InvalidFolder {}
185/// Enables downcasting an invalid folder to produce `DownCastError`
186#[derive(Debug)]
187pub struct InvalidPath;
188
189impl fmt::Display for InvalidPath {
190    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
191        write!(f, "{}", self)
192    }
193}
194
195impl Error for InvalidPath {}