1#[cfg(all(not(feature = "std"), feature = "alloc"))]
2use alloc::boxed::Box;
3use core::fmt::{Debug, Display, Formatter};
4
5#[derive(Debug)]
7pub struct Error {
8 kind: ErrorKind,
9
10 #[cfg(feature = "std")]
11 error: Option<Box<dyn std::error::Error + Send + Sync + 'static>>,
12 #[cfg(all(feature = "alloc", not(feature = "std")))]
13 error: Option<Box<dyn Debug + Send + Sync + 'static>>,
14}
15
16impl Error {
17 #[cfg(feature = "std")]
19 pub fn new<E>(kind: ErrorKind, error: E) -> Error
20 where
21 E: Into<Box<dyn std::error::Error + Send + Sync + 'static>>,
22 {
23 Self { kind, error: Some(error.into()) }
24 }
25
26 #[cfg(all(feature = "alloc", not(feature = "std")))]
28 pub fn new<E: sealed::IntoBoxDynDebug>(kind: ErrorKind, error: E) -> Error {
29 Self { kind, error: Some(error.into()) }
30 }
31
32 pub fn kind(&self) -> ErrorKind { self.kind }
34
35 #[cfg(feature = "std")]
37 pub fn get_ref(&self) -> Option<&(dyn std::error::Error + Send + Sync + 'static)> {
38 self.error.as_deref()
39 }
40
41 #[cfg(all(feature = "alloc", not(feature = "std")))]
43 pub fn get_ref(&self) -> Option<&(dyn Debug + Send + Sync + 'static)> { self.error.as_deref() }
44}
45
46impl From<ErrorKind> for Error {
47 fn from(kind: ErrorKind) -> Error {
48 Self {
49 kind,
50 #[cfg(any(feature = "std", feature = "alloc"))]
51 error: None,
52 }
53 }
54}
55
56impl Display for Error {
57 fn fmt(&self, fmt: &mut Formatter) -> core::result::Result<(), core::fmt::Error> {
58 fmt.write_fmt(format_args!("I/O Error: {}", self.kind.description()))?;
59 #[cfg(any(feature = "alloc", feature = "std"))]
60 if let Some(e) = &self.error {
61 fmt.write_fmt(format_args!(". {:?}", e))?;
62 }
63 Ok(())
64 }
65}
66
67#[cfg(feature = "std")]
68impl std::error::Error for Error {
69 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
70 self.error.as_ref().and_then(|e| e.as_ref().source())
71 }
72
73 #[allow(deprecated)]
74 fn description(&self) -> &str {
75 match self.error.as_ref() {
76 Some(e) => e.description(),
77 None => self.kind.description(),
78 }
79 }
80
81 #[allow(deprecated)]
82 fn cause(&self) -> Option<&dyn std::error::Error> {
83 self.error.as_ref().and_then(|e| e.as_ref().cause())
84 }
85}
86
87#[cfg(feature = "std")]
88impl From<std::io::Error> for Error {
89 fn from(o: std::io::Error) -> Error {
90 Self { kind: ErrorKind::from_std(o.kind()), error: o.into_inner() }
91 }
92}
93
94#[cfg(feature = "std")]
95impl From<Error> for std::io::Error {
96 fn from(o: Error) -> std::io::Error {
97 if let Some(err) = o.error {
98 std::io::Error::new(o.kind.to_std(), err)
99 } else {
100 o.kind.to_std().into()
101 }
102 }
103}
104
105macro_rules! define_errorkind {
106 ($($(#[$($attr:tt)*])* $kind:ident),*) => {
107 #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
108 pub enum ErrorKind {
114 $(
115 $(#[$($attr)*])*
116 $kind
117 ),*
118 }
119
120 impl From<core::convert::Infallible> for ErrorKind {
121 fn from(never: core::convert::Infallible) -> Self { match never {} }
122 }
123
124 impl ErrorKind {
125 fn description(&self) -> &'static str {
126 match self {
127 $(Self::$kind => stringify!($kind)),*
128 }
129 }
130
131 #[cfg(feature = "std")]
132 fn to_std(self) -> std::io::ErrorKind {
133 match self {
134 $(Self::$kind => std::io::ErrorKind::$kind),*
135 }
136 }
137
138 #[cfg(feature = "std")]
139 fn from_std(o: std::io::ErrorKind) -> ErrorKind {
140 match o {
141 $(std::io::ErrorKind::$kind => ErrorKind::$kind),*,
142 _ => ErrorKind::Other
143 }
144 }
145 }
146 }
147}
148
149define_errorkind!(
150 NotFound,
152 PermissionDenied,
154 ConnectionRefused,
156 ConnectionReset,
158 ConnectionAborted,
160 NotConnected,
162 AddrInUse,
164 AddrNotAvailable,
166 BrokenPipe,
168 AlreadyExists,
170 WouldBlock,
172 InvalidInput,
174 InvalidData,
176 TimedOut,
178 WriteZero,
180 Interrupted,
182 UnexpectedEof,
184 Other
187);
188
189#[cfg(all(feature = "alloc", not(feature = "std")))]
190mod sealed {
191 use alloc::boxed::Box;
192 use alloc::string::String;
193 use core::fmt::Debug;
194
195 pub trait IntoBoxDynDebug {
196 fn into(self) -> Box<dyn Debug + Send + Sync + 'static>;
197 }
198
199 impl IntoBoxDynDebug for &str {
200 fn into(self) -> Box<dyn Debug + Send + Sync + 'static> { Box::new(String::from(self)) }
201 }
202
203 impl IntoBoxDynDebug for String {
204 fn into(self) -> Box<dyn Debug + Send + Sync + 'static> { Box::new(self) }
205 }
206}