distant_protocol/common/
error.rs

1use std::io;
2
3use derive_more::Display;
4use serde::{Deserialize, Serialize};
5
6/// General purpose error type that can be sent across the wire
7#[derive(Clone, Debug, Display, PartialEq, Eq, Serialize, Deserialize)]
8#[display(fmt = "{kind}: {description}")]
9#[serde(rename_all = "snake_case", deny_unknown_fields)]
10pub struct Error {
11    /// Label describing the kind of error
12    pub kind: ErrorKind,
13
14    /// Description of the error itself
15    pub description: String,
16}
17
18impl std::error::Error for Error {}
19
20impl Error {
21    /// Produces an [`io::Error`] from this error.
22    pub fn to_io_error(&self) -> io::Error {
23        io::Error::new(self.kind.into(), self.description.to_string())
24    }
25}
26
27impl<'a> From<&'a str> for Error {
28    fn from(x: &'a str) -> Self {
29        Self::from(x.to_string())
30    }
31}
32
33impl From<String> for Error {
34    fn from(x: String) -> Self {
35        Self {
36            kind: ErrorKind::Other,
37            description: x,
38        }
39    }
40}
41
42impl From<io::Error> for Error {
43    fn from(x: io::Error) -> Self {
44        Self {
45            kind: ErrorKind::from(x.kind()),
46            description: x.to_string(),
47        }
48    }
49}
50
51impl From<Error> for io::Error {
52    fn from(x: Error) -> Self {
53        Self::new(x.kind.into(), x.description)
54    }
55}
56
57/// All possible kinds of errors that can be returned
58#[derive(Copy, Clone, Debug, Display, PartialEq, Eq, Serialize, Deserialize)]
59#[serde(rename_all = "snake_case", deny_unknown_fields)]
60pub enum ErrorKind {
61    /// An entity was not found, often a file
62    NotFound,
63
64    /// The operation lacked the necessary privileges to complete
65    PermissionDenied,
66
67    /// The connection was refused by the remote server
68    ConnectionRefused,
69
70    /// The connection was reset by the remote server
71    ConnectionReset,
72
73    /// The connection was aborted (terminated) by the remote server
74    ConnectionAborted,
75
76    /// The network operation failed because it was not connected yet
77    NotConnected,
78
79    /// A socket address could not be bound because the address is already in use elsewhere
80    AddrInUse,
81
82    /// A nonexistent interface was requested or the requested address was not local
83    AddrNotAvailable,
84
85    /// The operation failed because a pipe was closed
86    BrokenPipe,
87
88    /// An entity already exists, often a file
89    AlreadyExists,
90
91    /// The operation needs to block to complete, but the blocking operation was requested to not
92    /// occur
93    WouldBlock,
94
95    /// A parameter was incorrect
96    InvalidInput,
97
98    /// Data not valid for the operation were encountered
99    InvalidData,
100
101    /// The I/O operation's timeout expired, causing it to be cancelled
102    TimedOut,
103
104    /// An error returned when an operation could not be completed because a
105    /// call to `write` returned `Ok(0)`
106    WriteZero,
107
108    /// This operation was interrupted
109    Interrupted,
110
111    /// Any I/O error not part of this list
112    Other,
113
114    /// An error returned when an operation could not be completed because an "end of file" was
115    /// reached prematurely
116    UnexpectedEof,
117
118    /// This operation is unsupported on this platform
119    Unsupported,
120
121    /// An operation could not be completed, because it failed to allocate enough memory
122    OutOfMemory,
123
124    /// When a loop is encountered when walking a directory
125    Loop,
126
127    /// When a task is cancelled
128    TaskCancelled,
129
130    /// When a task panics
131    TaskPanicked,
132
133    /// Catchall for an error that has no specific type
134    Unknown,
135}
136
137impl From<io::ErrorKind> for ErrorKind {
138    fn from(kind: io::ErrorKind) -> Self {
139        match kind {
140            io::ErrorKind::NotFound => Self::NotFound,
141            io::ErrorKind::PermissionDenied => Self::PermissionDenied,
142            io::ErrorKind::ConnectionRefused => Self::ConnectionRefused,
143            io::ErrorKind::ConnectionReset => Self::ConnectionReset,
144            io::ErrorKind::ConnectionAborted => Self::ConnectionAborted,
145            io::ErrorKind::NotConnected => Self::NotConnected,
146            io::ErrorKind::AddrInUse => Self::AddrInUse,
147            io::ErrorKind::AddrNotAvailable => Self::AddrNotAvailable,
148            io::ErrorKind::BrokenPipe => Self::BrokenPipe,
149            io::ErrorKind::AlreadyExists => Self::AlreadyExists,
150            io::ErrorKind::WouldBlock => Self::WouldBlock,
151            io::ErrorKind::InvalidInput => Self::InvalidInput,
152            io::ErrorKind::InvalidData => Self::InvalidData,
153            io::ErrorKind::TimedOut => Self::TimedOut,
154            io::ErrorKind::WriteZero => Self::WriteZero,
155            io::ErrorKind::Interrupted => Self::Interrupted,
156            io::ErrorKind::Other => Self::Other,
157            io::ErrorKind::OutOfMemory => Self::OutOfMemory,
158            io::ErrorKind::UnexpectedEof => Self::UnexpectedEof,
159            io::ErrorKind::Unsupported => Self::Unsupported,
160
161            // This exists because io::ErrorKind is non_exhaustive
162            _ => Self::Unknown,
163        }
164    }
165}
166
167impl From<ErrorKind> for io::ErrorKind {
168    fn from(kind: ErrorKind) -> Self {
169        match kind {
170            ErrorKind::NotFound => Self::NotFound,
171            ErrorKind::PermissionDenied => Self::PermissionDenied,
172            ErrorKind::ConnectionRefused => Self::ConnectionRefused,
173            ErrorKind::ConnectionReset => Self::ConnectionReset,
174            ErrorKind::ConnectionAborted => Self::ConnectionAborted,
175            ErrorKind::NotConnected => Self::NotConnected,
176            ErrorKind::AddrInUse => Self::AddrInUse,
177            ErrorKind::AddrNotAvailable => Self::AddrNotAvailable,
178            ErrorKind::BrokenPipe => Self::BrokenPipe,
179            ErrorKind::AlreadyExists => Self::AlreadyExists,
180            ErrorKind::WouldBlock => Self::WouldBlock,
181            ErrorKind::InvalidInput => Self::InvalidInput,
182            ErrorKind::InvalidData => Self::InvalidData,
183            ErrorKind::TimedOut => Self::TimedOut,
184            ErrorKind::WriteZero => Self::WriteZero,
185            ErrorKind::Interrupted => Self::Interrupted,
186            ErrorKind::Other => Self::Other,
187            ErrorKind::OutOfMemory => Self::OutOfMemory,
188            ErrorKind::UnexpectedEof => Self::UnexpectedEof,
189            ErrorKind::Unsupported => Self::Unsupported,
190            _ => Self::Other,
191        }
192    }
193}
194
195#[cfg(test)]
196mod tests {
197    use super::*;
198
199    mod error {
200        use super::*;
201
202        #[test]
203        fn should_be_able_to_serialize_to_json() {
204            let error = Error {
205                kind: ErrorKind::AddrInUse,
206                description: "some description".to_string(),
207            };
208
209            let value = serde_json::to_value(error).unwrap();
210            assert_eq!(
211                value,
212                serde_json::json!({
213                    "kind": "addr_in_use",
214                    "description": "some description",
215                })
216            );
217        }
218
219        #[test]
220        fn should_be_able_to_deserialize_from_json() {
221            let value = serde_json::json!({
222                "kind": "addr_in_use",
223                "description": "some description",
224            });
225
226            let error: Error = serde_json::from_value(value).unwrap();
227            assert_eq!(
228                error,
229                Error {
230                    kind: ErrorKind::AddrInUse,
231                    description: "some description".to_string(),
232                }
233            );
234        }
235
236        #[test]
237        fn should_be_able_to_serialize_to_msgpack() {
238            let error = Error {
239                kind: ErrorKind::AddrInUse,
240                description: "some description".to_string(),
241            };
242
243            // NOTE: We don't actually check the output here because it's an implementation detail
244            // and could change as we change how serialization is done. This is merely to verify
245            // that we can serialize since there are times when serde fails to serialize at
246            // runtime.
247            let _ = rmp_serde::encode::to_vec_named(&error).unwrap();
248        }
249
250        #[test]
251        fn should_be_able_to_deserialize_from_msgpack() {
252            // NOTE: It may seem odd that we are serializing just to deserialize, but this is to
253            // verify that we are not corrupting or preventing issues when serializing on a
254            // client/server and then trying to deserialize on the other side. This has happened
255            // enough times with minor changes that we need tests to verify.
256            let buf = rmp_serde::encode::to_vec_named(&Error {
257                kind: ErrorKind::AddrInUse,
258                description: "some description".to_string(),
259            })
260            .unwrap();
261
262            let error: Error = rmp_serde::decode::from_slice(&buf).unwrap();
263            assert_eq!(
264                error,
265                Error {
266                    kind: ErrorKind::AddrInUse,
267                    description: "some description".to_string(),
268                }
269            );
270        }
271    }
272
273    mod error_kind {
274        use super::*;
275
276        #[test]
277        fn should_be_able_to_serialize_to_json() {
278            let kind = ErrorKind::AddrInUse;
279
280            let value = serde_json::to_value(kind).unwrap();
281            assert_eq!(value, serde_json::json!("addr_in_use"));
282        }
283
284        #[test]
285        fn should_be_able_to_deserialize_from_json() {
286            let value = serde_json::json!("addr_in_use");
287
288            let kind: ErrorKind = serde_json::from_value(value).unwrap();
289            assert_eq!(kind, ErrorKind::AddrInUse);
290        }
291
292        #[test]
293        fn should_be_able_to_serialize_to_msgpack() {
294            let kind = ErrorKind::AddrInUse;
295
296            // NOTE: We don't actually check the output here because it's an implementation detail
297            // and could change as we change how serialization is done. This is merely to verify
298            // that we can serialize since there are times when serde fails to serialize at
299            // runtime.
300            let _ = rmp_serde::encode::to_vec_named(&kind).unwrap();
301        }
302
303        #[test]
304        fn should_be_able_to_deserialize_from_msgpack() {
305            // NOTE: It may seem odd that we are serializing just to deserialize, but this is to
306            // verify that we are not corrupting or causing issues when serializing on a
307            // client/server and then trying to deserialize on the other side. This has happened
308            // enough times with minor changes that we need tests to verify.
309            let buf = rmp_serde::encode::to_vec_named(&ErrorKind::AddrInUse).unwrap();
310
311            let kind: ErrorKind = rmp_serde::decode::from_slice(&buf).unwrap();
312            assert_eq!(kind, ErrorKind::AddrInUse);
313        }
314    }
315}