portable_io/
error.rs

1#[cfg(test)]
2mod tests;
3
4use core::convert::From;
5use core::error;
6use core::fmt;
7use core::result;
8
9extern crate alloc;
10use alloc::boxed::Box;
11
12/// A specialized [`Result`] type for I/O operations.
13///
14/// <!-- TODO INCLUDE & ADAPT MORE DOC COMMENTS HERE -->
15///
16/// [`Result`]: core::result::Result
17///
18/// <!-- TODO ADD EXAMPLE CODE THAT DOES NOT USE FS -->
19pub type Result<T> = result::Result<T, Error>;
20
21/// The error type for I/O operations of the [`Read`], [`Write`], [`Seek`], and
22/// associated traits.
23///
24/// Errors mostly originate from the underlying OS, but custom instances of
25/// `Error` can be created with crafted error messages and a particular value of
26/// [`ErrorKind`].
27///
28/// [`Read`]: crate::Read
29/// [`Write`]: crate::Write
30/// [`Seek`]: crate::Seek
31pub struct Error {
32    repr: Repr,
33}
34
35impl fmt::Debug for Error {
36    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37        fmt::Debug::fmt(&self.repr, f)
38    }
39}
40
41enum Repr {
42    #[cfg(feature = "os-error")]
43    Os(i32),
44    Simple(ErrorKind),
45    // &str is a fat pointer, but &&str is a thin pointer.
46    SimpleMessage(ErrorKind, &'static &'static str),
47    Custom(Box<Custom>),
48}
49
50#[derive(Debug)]
51struct Custom {
52    kind: ErrorKind,
53    error: Box<dyn error::Error + Send + Sync>,
54}
55
56/// A list specifying general categories of I/O error.
57///
58/// This list is intended to grow over time and it is not recommended to
59/// exhaustively match against it.
60///
61/// (It is used with the [`portable_io::Error`] type.)
62///
63/// [`portable_io::Error`]: crate::Error
64#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
65#[allow(deprecated)]
66#[non_exhaustive]
67pub enum ErrorKind {
68    /// An entity was not found, often a file.
69    NotFound,
70    /// The operation lacked the necessary privileges to complete.
71    PermissionDenied,
72    /// The connection was refused by the remote server.
73    ConnectionRefused,
74    /// The connection was reset by the remote server.
75    ConnectionReset,
76    /// The remote host is not reachable.
77    HostUnreachable,
78    /// The network containing the remote host is not reachable.
79    NetworkUnreachable,
80    /// The connection was aborted (terminated) by the remote server.
81    ConnectionAborted,
82    /// The network operation failed because it was not connected yet.
83    NotConnected,
84    /// A socket address could not be bound because the address is already in
85    /// use elsewhere.
86    AddrInUse,
87    /// A nonexistent interface was requested or the requested address was not
88    /// local.
89    AddrNotAvailable,
90    /// The system's networking is down.
91    NetworkDown,
92    /// The operation failed because a pipe was closed.
93    BrokenPipe,
94    /// An entity already exists, often a file.
95    AlreadyExists,
96    /// The operation needs to block to complete, but the blocking operation was
97    /// requested to not occur.
98    WouldBlock,
99    /// A filesystem object is, unexpectedly, not a directory.
100    ///
101    /// For example, a filesystem path was specified where one of the intermediate directory
102    /// components was, in fact, a plain file.
103    NotADirectory,
104    /// The filesystem object is, unexpectedly, a directory.
105    ///
106    /// A directory was specified when a non-directory was expected.
107    IsADirectory,
108    /// A non-empty directory was specified where an empty directory was expected.
109    DirectoryNotEmpty,
110    /// The filesystem or storage medium is read-only, but a write operation was attempted.
111    ReadOnlyFilesystem,
112    /// Loop in the filesystem or IO subsystem; often, too many levels of symbolic links.
113    ///
114    /// There was a loop (or excessively long chain) resolving a filesystem object
115    /// or file IO object.
116    ///
117    /// On Unix this is usually the result of a symbolic link loop; or, of exceeding the
118    /// system-specific limit on the depth of symlink traversal.
119    FilesystemLoop,
120    /// Stale network file handle.
121    ///
122    /// With some network filesystems, notably NFS, an open file (or directory) can be invalidated
123    /// by problems with the network or server.
124    StaleNetworkFileHandle,
125    /// A parameter was incorrect.
126    InvalidInput,
127    /// Data not valid for the operation were encountered.
128    ///
129    /// Unlike [`InvalidInput`], this typically means that the operation
130    /// parameters were valid, however the error was caused by malformed
131    /// input data.
132    ///
133    /// For example, a function that reads a file into a string will error with
134    /// `InvalidData` if the file's contents are not valid UTF-8.
135    ///
136    /// [`InvalidInput`]: ErrorKind::InvalidInput
137    InvalidData,
138    /// The I/O operation's timeout expired, causing it to be canceled.
139    TimedOut,
140    /// An error returned when an operation could not be completed because a
141    /// call to [`write`] returned [`Ok(0)`].
142    ///
143    /// This typically means that an operation could only succeed if it wrote a
144    /// particular number of bytes but only a smaller number of bytes could be
145    /// written.
146    ///
147    /// [`write`]: crate::Write::write
148    /// [`Ok(0)`]: Ok
149    WriteZero,
150    /// The underlying storage (typically, a filesystem) is full.
151    ///
152    /// This does not include out of quota errors.
153    StorageFull,
154    /// Seek on unseekable file.
155    ///
156    /// Seeking was attempted on an open file handle which is not suitable for seeking - for
157    /// example, on Unix, a named pipe opened with `File::open`.
158    NotSeekable,
159    /// Filesystem quota was exceeded.
160    FilesystemQuotaExceeded,
161    /// File larger than allowed or supported.
162    ///
163    /// This might arise from a hard limit of the underlying filesystem or file access API, or from
164    /// an administratively imposed resource limitation.  Simple disk full, and out of quota, have
165    /// their own errors.
166    FileTooLarge,
167    /// Resource is busy.
168    ResourceBusy,
169    /// Executable file is busy.
170    ///
171    /// An attempt was made to write to a file which is also in use as a running program.  (Not all
172    /// operating systems detect this situation.)
173    ExecutableFileBusy,
174    /// Deadlock (avoided).
175    ///
176    /// A file locking operation would result in deadlock.  This situation is typically detected, if
177    /// at all, on a best-effort basis.
178    Deadlock,
179    /// Cross-device or cross-filesystem (hard) link or rename.
180    CrossesDevices,
181    /// Too many (hard) links to the same filesystem object.
182    ///
183    /// The filesystem does not support making so many hardlinks to the same file.
184    TooManyLinks,
185    /// Filename too long.
186    ///
187    /// The limit might be from the underlying filesystem or API, or an administratively imposed
188    /// resource limit.
189    FilenameTooLong,
190    /// Program argument list too long.
191    ///
192    /// When trying to run an external program, a system or process limit on the size of the
193    /// arguments would have been exceeded.
194    ArgumentListTooLong,
195    /// This operation was interrupted.
196    ///
197    /// Interrupted operations can typically be retried.
198    Interrupted,
199
200    /// This operation is unsupported on this platform.
201    ///
202    /// This means that the operation can never succeed.
203    Unsupported,
204
205    // ErrorKinds which are primarily categorisations for OS error
206    // codes should be added above.
207    //
208    /// An error returned when an operation could not be completed because an
209    /// "end of file" was reached prematurely.
210    ///
211    /// This typically means that an operation could only succeed if it read a
212    /// particular number of bytes but only a smaller number of bytes could be
213    /// read.
214    UnexpectedEof,
215
216    /// An operation could not be completed, because it failed
217    /// to allocate enough memory.
218    OutOfMemory,
219
220    // "Unusual" error kinds which do not correspond simply to (sets
221    // of) OS error codes, should be added just above this comment.
222    // `Other` and `Uncategorised` should remain at the end:
223    //
224    /// A custom error that does not fall under any other I/O error kind.
225    ///
226    /// This can be used to construct your own [`Error`]s that do not match any
227    /// [`ErrorKind`].
228    ///
229    /// This [`ErrorKind`] is not used by the standard library.
230    ///
231    /// Errors from the standard library that do not fall under any of the I/O
232    /// error kinds cannot be `match`ed on, and will only match a wildcard (`_`) pattern.
233    /// New [`ErrorKind`]s might be added in the future for some of those.
234    Other,
235
236    /// Any I/O error from the standard library that's not part of this list.
237    ///
238    /// Errors that are `Uncategorized` now may move to a different or a new
239    /// [`ErrorKind`] variant in the future. It is not recommended to match
240    /// an error against `Uncategorized`; use a wildcard match (`_`) instead.
241    #[doc(hidden)]
242    Uncategorized,
243}
244
245impl ErrorKind {
246    pub(crate) fn as_str(&self) -> &'static str {
247        use ErrorKind::*;
248        // Strictly alphabetical, please.  (Sadly rustfmt cannot do this yet.)
249        match *self {
250            AddrInUse => "address in use",
251            AddrNotAvailable => "address not available",
252            AlreadyExists => "entity already exists",
253            ArgumentListTooLong => "argument list too long",
254            BrokenPipe => "broken pipe",
255            ConnectionAborted => "connection aborted",
256            ConnectionRefused => "connection refused",
257            ConnectionReset => "connection reset",
258            CrossesDevices => "cross-device link or rename",
259            Deadlock => "deadlock",
260            DirectoryNotEmpty => "directory not empty",
261            ExecutableFileBusy => "executable file busy",
262            FileTooLarge => "file too large",
263            FilenameTooLong => "filename too long",
264            FilesystemLoop => "filesystem loop or indirection limit (e.g. symlink loop)",
265            FilesystemQuotaExceeded => "filesystem quota exceeded",
266            HostUnreachable => "host unreachable",
267            Interrupted => "operation interrupted",
268            InvalidData => "invalid data",
269            InvalidInput => "invalid input parameter",
270            IsADirectory => "is a directory",
271            NetworkDown => "network down",
272            NetworkUnreachable => "network unreachable",
273            NotADirectory => "not a directory",
274            NotConnected => "not connected",
275            NotFound => "entity not found",
276            NotSeekable => "seek on unseekable file",
277            Other => "other error",
278            OutOfMemory => "out of memory",
279            PermissionDenied => "permission denied",
280            ReadOnlyFilesystem => "read-only filesystem or storage medium",
281            ResourceBusy => "resource busy",
282            StaleNetworkFileHandle => "stale network file handle",
283            StorageFull => "no storage space",
284            TimedOut => "timed out",
285            TooManyLinks => "too many links",
286            Uncategorized => "uncategorized error",
287            UnexpectedEof => "unexpected end of file",
288            Unsupported => "unsupported",
289            WouldBlock => "operation would block",
290            WriteZero => "write zero",
291        }
292    }
293}
294
295/// Intended for use for errors not exposed to the user, where allocating onto
296/// the heap (for normal construction via Error::new) is too costly.
297impl From<ErrorKind> for Error {
298    /// Converts an [`ErrorKind`] into an [`Error`].
299    ///
300    /// This conversion allocates a new error with a simple representation of error kind.
301    ///
302    /// <!-- UPDATED TITLE in this fork to avoid singular vs plural issue - TODO PROPOSE UPDATE IN UPSTREAM RUST -->
303    /// # Example code
304    ///
305    /// ```
306    /// use portable_io::{Error, ErrorKind};
307    ///
308    /// let not_found = ErrorKind::NotFound;
309    /// let error = Error::from(not_found);
310    /// assert_eq!("entity not found", format!("{}", error));
311    /// ```
312    #[inline]
313    fn from(kind: ErrorKind) -> Error {
314        Error { repr: Repr::Simple(kind) }
315    }
316}
317
318impl Error {
319    /// Creates a new I/O error from a known kind of error as well as an
320    /// arbitrary error payload.
321    ///
322    /// This function is used to generically create I/O errors which do not
323    /// originate from the OS itself. The `error` argument is an arbitrary
324    /// payload which will be contained in this [`Error`].
325    ///
326    /// If no extra payload is required, use the `From` conversion from
327    /// `ErrorKind`.
328    ///
329    /// <!-- UPDATED TITLE in this fork to avoid singular vs plural issue - TODO PROPOSE UPDATE IN UPSTREAM RUST -->
330    /// # Example code
331    ///
332    /// ```
333    /// use portable_io::{Error, ErrorKind};
334    ///
335    /// // errors can be created from strings
336    /// let custom_error = Error::new(ErrorKind::Other, "oh no!");
337    ///
338    /// // errors can also be created from other errors
339    /// let custom_error2 = Error::new(ErrorKind::Interrupted, custom_error);
340    ///
341    /// // creating an error without payload
342    /// let eof_error = Error::from(ErrorKind::UnexpectedEof);
343    /// ```
344    pub fn new<E>(kind: ErrorKind, error: E) -> Error
345    where
346        E: Into<Box<dyn error::Error + Send + Sync>>,
347    {
348        Self::_new(kind, error.into())
349    }
350
351    /// Creates a new I/O error from an arbitrary error payload.
352    ///
353    /// This function is used to generically create I/O errors which do not
354    /// originate from the OS itself. It is a shortcut for [`Error::new`]
355    /// with [`ErrorKind::Other`].
356    ///
357    /// <!-- UPDATED TITLE in this fork to avoid singular vs plural issue - TODO PROPOSE UPDATE IN UPSTREAM RUST -->
358    /// # Example code
359    ///
360    /// ```
361    /// use portable_io::Error;
362    ///
363    /// // errors can be created from strings
364    /// let custom_error = Error::other("oh no!");
365    ///
366    /// // errors can also be created from other errors
367    /// let custom_error2 = Error::other(custom_error);
368    /// ```
369    pub fn other<E>(error: E) -> Error
370    where
371        E: Into<Box<dyn error::Error + Send + Sync>>,
372    {
373        Self::_new(ErrorKind::Other, error.into())
374    }
375
376    fn _new(kind: ErrorKind, error: Box<dyn error::Error + Send + Sync>) -> Error {
377        Error { repr: Repr::Custom(Box::new(Custom { kind, error })) }
378    }
379
380    /// Creates a new I/O error from a known kind of error as well as a
381    /// constant message.
382    ///
383    /// This function does not allocate.
384    ///
385    /// This function should maybe change to
386    /// `new_const<const MSG: &'static str>(kind: ErrorKind)`
387    /// in the future, when const generics allow that.
388    #[inline]
389    pub(crate) const fn new_const(kind: ErrorKind, message: &'static &'static str) -> Error {
390        Self { repr: Repr::SimpleMessage(kind, message) }
391    }
392
393    /// <!-- (using compile_fail "code block" to show this message as a failure block) -->
394    /// ```compile_fail
395    /// NOT IMPLEMENTED - WILL PANIC WITH "MISSING FUNCTIONALITY" MESSAGE
396    /// ```
397    ///
398    /// <!-- UPDATED TITLE in this fork to avoid singular vs plural issue - TODO PROPOSE UPDATE IN UPSTREAM RUST -->
399    /// # Example code
400    ///
401    /// <!-- TODO FIX & REMOVE no_run here -->
402    /// ```no_run
403    /// use portable_io::Error;
404    ///
405    /// let os_error = Error::last_os_error();
406    /// println!("last OS error: {:?}", os_error);
407    /// ```
408    ///
409    /// <!-- TODO: use Rust (nightly) doc_cfg feature to document feature & cfg option requirements (if possible) -->
410    /// <div class="warning">REQUIRES feature to be enabled: <code>os-error</code></div>
411    #[cfg(feature = "os-error")]
412    #[must_use]
413    #[inline]
414    pub fn last_os_error() -> Error {
415        // TODO ADD MISSING FUNCTIONALITY
416        panic!("MISSING FUNCTIONALITY")
417    }
418
419    /// Creates a new instance of an [`Error`] from a particular OS error code.
420    ///
421    /// <!-- TODO ADD EXAMPLE CODE -->
422    ///
423    /// <!-- TODO: use Rust (nightly) doc_cfg feature to document feature & cfg option requirements (if possible) -->
424    /// <div class="warning">REQUIRES feature to be enabled: <code>os-error</code></div>
425    #[cfg(feature = "os-error")]
426    #[must_use]
427    #[inline]
428    pub fn from_raw_os_error(code: i32) -> Error {
429        Error { repr: Repr::Os(code) }
430    }
431
432    /// Returns the OS error that this error represents (if any).
433    ///
434    /// If this [`Error`] was constructed via [`last_os_error`] or
435    /// [`from_raw_os_error`], then this function will return [`Some`], otherwise
436    /// it will return [`None`].
437    ///
438    /// [`last_os_error`]: Error::last_os_error
439    /// [`from_raw_os_error`]: Error::from_raw_os_error
440    ///
441    /// <!-- UPDATED TITLE in this fork to avoid singular vs plural issue - TODO PROPOSE UPDATE IN UPSTREAM RUST -->
442    /// # Example code
443    ///
444    /// ```
445    /// use portable_io::{Error, ErrorKind};
446    ///
447    /// fn print_os_error(err: &Error) {
448    ///     if let Some(raw_os_err) = err.raw_os_error() {
449    ///         println!("raw OS error: {:?}", raw_os_err);
450    ///     } else {
451    ///         println!("Not an OS error");
452    ///     }
453    /// }
454    ///
455    /// fn main() {
456    ///     // Will print "raw OS error: ...".
457    ///     // (only compiles with `os-error` feature enabled)
458    ///     // print_os_error(&Error::last_os_error());
459    ///     // Will print "Not an OS error".
460    ///     print_os_error(&Error::new(ErrorKind::Other, "oh no!"));
461    /// }
462    /// ```
463    #[must_use]
464    #[inline]
465    pub fn raw_os_error(&self) -> Option<i32> {
466        match self.repr {
467            #[cfg(feature = "os-error")]
468            Repr::Os(i) => Some(i),
469            Repr::Custom(..) => None,
470            Repr::Simple(..) => None,
471            Repr::SimpleMessage(..) => None,
472        }
473    }
474
475    /// Returns a reference to the inner error wrapped by this error (if any).
476    ///
477    /// If this [`Error`] was constructed via [`new`] then this function will
478    /// return [`Some`], otherwise it will return [`None`].
479    ///
480    /// [`new`]: Error::new
481    ///
482    /// <!-- UPDATED TITLE in this fork to avoid singular vs plural issue - TODO PROPOSE UPDATE IN UPSTREAM RUST -->
483    /// # Example code
484    ///
485    /// ```
486    /// use portable_io::{Error, ErrorKind};
487    ///
488    /// fn print_error(err: &Error) {
489    ///     if let Some(inner_err) = err.get_ref() {
490    ///         println!("Inner error: {:?}", inner_err);
491    ///     } else {
492    ///         println!("No inner error");
493    ///     }
494    /// }
495    ///
496    /// fn main() {
497    ///     // Will print "No inner error".
498    ///     // (only compiles with `os-error` feature enabled)
499    ///     // print_error(&Error::last_os_error());
500    ///     // Will print "Inner error: ...".
501    ///     print_error(&Error::new(ErrorKind::Other, "oh no!"));
502    /// }
503    /// ```
504    #[must_use]
505    #[inline]
506    pub fn get_ref(&self) -> Option<&(dyn error::Error + Send + Sync + 'static)> {
507        match self.repr {
508            #[cfg(feature = "os-error")]
509            Repr::Os(..) => None,
510            Repr::Simple(..) => None,
511            Repr::SimpleMessage(..) => None,
512            Repr::Custom(ref c) => Some(&*c.error),
513        }
514    }
515
516    /// Returns a mutable reference to the inner error wrapped by this error
517    /// (if any).
518    ///
519    /// If this [`Error`] was constructed via [`new`] then this function will
520    /// return [`Some`], otherwise it will return [`None`].
521    ///
522    /// [`new`]: Error::new
523    ///
524    /// <!-- UPDATED TITLE in this fork to avoid singular vs plural issue - TODO PROPOSE UPDATE IN UPSTREAM RUST -->
525    /// # Example code
526    ///
527    /// ```
528    /// use portable_io::{Error, ErrorKind};
529    /// use core::{error, fmt};
530    /// use core::fmt::Display;
531    ///
532    /// #[derive(Debug)]
533    /// struct MyError {
534    ///     v: String,
535    /// }
536    ///
537    /// impl MyError {
538    ///     fn new() -> MyError {
539    ///         MyError {
540    ///             v: "oh no!".to_string()
541    ///         }
542    ///     }
543    ///
544    ///     fn change_message(&mut self, new_message: &str) {
545    ///         self.v = new_message.to_string();
546    ///     }
547    /// }
548    ///
549    /// impl error::Error for MyError {}
550    ///
551    /// impl Display for MyError {
552    ///     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
553    ///         write!(f, "MyError: {}", &self.v)
554    ///     }
555    /// }
556    ///
557    /// fn change_error(mut err: Error) -> Error {
558    ///     if let Some(inner_err) = err.get_mut() {
559    ///         inner_err.downcast_mut::<MyError>().unwrap().change_message("I've been changed!");
560    ///     }
561    ///     err
562    /// }
563    ///
564    /// fn print_error(err: &Error) {
565    ///     if let Some(inner_err) = err.get_ref() {
566    ///         println!("Inner error: {}", inner_err);
567    ///     } else {
568    ///         println!("No inner error");
569    ///     }
570    /// }
571    ///
572    /// fn main() {
573    ///     // Will print "No inner error".
574    ///     // (only compiles with `os-error` feature enabled)
575    ///     // print_error(&change_error(Error::last_os_error()));
576    ///     // Will print "Inner error: ...".
577    ///     print_error(&change_error(Error::new(ErrorKind::Other, MyError::new())));
578    /// }
579    /// ```
580    #[must_use]
581    #[inline]
582    pub fn get_mut(&mut self) -> Option<&mut (dyn error::Error + Send + Sync + 'static)> {
583        match self.repr {
584            #[cfg(feature = "os-error")]
585            Repr::Os(..) => None,
586            Repr::Simple(..) => None,
587            Repr::SimpleMessage(..) => None,
588            Repr::Custom(ref mut c) => Some(&mut *c.error),
589        }
590    }
591
592    /// Consumes the `Error`, returning its inner error (if any).
593    ///
594    /// If this [`Error`] was constructed via [`new`] then this function will
595    /// return [`Some`], otherwise it will return [`None`].
596    ///
597    /// [`new`]: Error::new
598    ///
599    /// <!-- UPDATED TITLE in this fork to avoid singular vs plural issue - TODO PROPOSE UPDATE IN UPSTREAM RUST -->
600    /// # Example code
601    ///
602    /// ```
603    /// use portable_io::{Error, ErrorKind};
604    ///
605    /// fn print_error(err: Error) {
606    ///     if let Some(inner_err) = err.into_inner() {
607    ///         println!("Inner error: {}", inner_err);
608    ///     } else {
609    ///         println!("No inner error");
610    ///     }
611    /// }
612    ///
613    /// fn main() {
614    ///     // Will print "No inner error".
615    ///     // (only compiles with `os-error` feature enabled)
616    ///     // print_error(Error::last_os_error());
617    ///     // Will print "Inner error: ...".
618    ///     print_error(Error::new(ErrorKind::Other, "oh no!"));
619    /// }
620    /// ```
621    #[must_use = "`self` will be dropped if the result is not used"]
622    #[inline]
623    pub fn into_inner(self) -> Option<Box<dyn error::Error + Send + Sync>> {
624        match self.repr {
625            #[cfg(feature = "os-error")]
626            Repr::Os(..) => None,
627            Repr::Simple(..) => None,
628            Repr::SimpleMessage(..) => None,
629            Repr::Custom(c) => Some(c.error),
630        }
631    }
632
633    /// Returns the corresponding [`ErrorKind`] for this error.
634    ///
635    /// <!-- UPDATED TITLE in this fork to avoid singular vs plural issue - TODO PROPOSE UPDATE IN UPSTREAM RUST -->
636    /// # Example code
637    ///
638    /// <!-- TODO ADD ANOTHER print_error() example in the code below -->
639    /// ```
640    /// use portable_io::{Error, ErrorKind};
641    ///
642    /// fn print_error(err: Error) {
643    ///     println!("{:?}", err.kind());
644    /// }
645    ///
646    /// fn main() {
647    ///     // Will panic (MISSING FUNCTIONALITY) - SHOULD print "Uncategorized".
648    ///     // (only compiles with `os-error` feature enabled)
649    ///     // print_error(Error::last_os_error());
650    ///     // Will print "AddrInUse".
651    ///     print_error(Error::new(ErrorKind::AddrInUse, "oh no!"));
652    /// }
653    /// ```
654    #[must_use]
655    #[inline]
656    pub fn kind(&self) -> ErrorKind {
657        match self.repr {
658            // TODO ADD MISSING FUNCTIONALITY
659            #[cfg(feature = "os-error")]
660            Repr::Os(_) => panic!("MISSING FUNCTIONALITY"),
661            Repr::Custom(ref c) => c.kind,
662            Repr::Simple(kind) => kind,
663            Repr::SimpleMessage(kind, _) => kind,
664        }
665    }
666}
667
668impl fmt::Debug for Repr {
669    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
670        match *self {
671            // TODO ADD MISSING FUNCTIONALITY
672            #[cfg(feature = "os-error")]
673            Repr::Os(_) => panic!("MISSING FUNCTIONALITY"),
674            Repr::Custom(ref c) => fmt::Debug::fmt(&c, fmt),
675            Repr::Simple(kind) => fmt.debug_tuple("Kind").field(&kind).finish(),
676            Repr::SimpleMessage(kind, &message) => {
677                fmt.debug_struct("Error").field("kind", &kind).field("message", &message).finish()
678            }
679        }
680    }
681}
682
683impl fmt::Display for Error {
684    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
685        match self.repr {
686            #[cfg(feature = "os-error")]
687            Repr::Os(code) => {
688                // TODO ADD MISSING FUNCTIONALITY
689                // (ignore unused argument for now)
690                _ = code;
691                panic!("MISSING FUNCTIONALITY")
692            }
693            Repr::Custom(ref c) => c.error.fmt(fmt),
694            Repr::Simple(kind) => write!(fmt, "{}", kind.as_str()),
695            Repr::SimpleMessage(_, &msg) => msg.fmt(fmt),
696        }
697    }
698}
699
700impl error::Error for Error {
701    #[allow(deprecated, deprecated_in_future)]
702    fn description(&self) -> &str {
703        match self.repr {
704            #[cfg(feature = "os-error")]
705            Repr::Os(..) => self.kind().as_str(),
706            Repr::Simple(..) => self.kind().as_str(),
707            Repr::SimpleMessage(_, &msg) => msg,
708            Repr::Custom(ref c) => c.error.description(),
709        }
710    }
711
712    #[allow(deprecated)]
713    fn cause(&self) -> Option<&dyn error::Error> {
714        match self.repr {
715            #[cfg(feature = "os-error")]
716            Repr::Os(..) => None,
717            Repr::Simple(..) => None,
718            Repr::SimpleMessage(..) => None,
719            Repr::Custom(ref c) => c.error.cause(),
720        }
721    }
722
723    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
724        match self.repr {
725            #[cfg(feature = "os-error")]
726            Repr::Os(..) => None,
727            Repr::Simple(..) => None,
728            Repr::SimpleMessage(..) => None,
729            Repr::Custom(ref c) => c.error.source(),
730        }
731    }
732}
733
734fn _assert_error_is_sync_send() {
735    fn _is_sync_send<T: Sync + Send>() {}
736    _is_sync_send::<Error>();
737}