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 {
113 $(
114 $(#[$($attr)*])*
115 $kind
116 ),*
117 }
118
119 impl From<core::convert::Infallible> for ErrorKind {
120 fn from(never: core::convert::Infallible) -> Self { match never {} }
121 }
122
123 impl ErrorKind {
124 fn description(&self) -> &'static str {
125 match self {
126 $(Self::$kind => stringify!($kind)),*
127 }
128 }
129
130 #[cfg(feature = "std")]
131 fn to_std(self) -> std::io::ErrorKind {
132 match self {
133 $(Self::$kind => std::io::ErrorKind::$kind),*
134 }
135 }
136
137 #[cfg(feature = "std")]
138 fn from_std(o: std::io::ErrorKind) -> ErrorKind {
139 match o {
140 $(std::io::ErrorKind::$kind => ErrorKind::$kind),*,
141 _ => ErrorKind::Other
142 }
143 }
144 }
145 }
146}
147
148define_errorkind!(
149 NotFound,
151 PermissionDenied,
153 ConnectionRefused,
155 ConnectionReset,
157 ConnectionAborted,
159 NotConnected,
161 AddrInUse,
163 AddrNotAvailable,
165 BrokenPipe,
167 AlreadyExists,
169 WouldBlock,
171 InvalidInput,
173 InvalidData,
175 TimedOut,
177 WriteZero,
179 Interrupted,
181 UnexpectedEof,
183 Other
186);
187
188#[cfg(all(feature = "alloc", not(feature = "std")))]
189mod sealed {
190 use alloc::boxed::Box;
191 use alloc::string::String;
192 use core::fmt::Debug;
193
194 pub trait IntoBoxDynDebug {
195 fn into(self) -> Box<dyn Debug + Send + Sync + 'static>;
196 }
197
198 impl IntoBoxDynDebug for &str {
199 fn into(self) -> Box<dyn Debug + Send + Sync + 'static> { Box::new(String::from(self)) }
200 }
201
202 impl IntoBoxDynDebug for String {
203 fn into(self) -> Box<dyn Debug + Send + Sync + 'static> { Box::new(self) }
204 }
205}