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}