1#[cfg(all(not(feature = "std"), feature = "alloc"))]
2use alloc::boxed::Box;
3use core::fmt;
4
5#[derive(Debug)]
7pub struct Error {
8 kind: ErrorKind,
9 _not_unwind_safe: core::marker::PhantomData<(&'static mut (), core::cell::UnsafeCell<()>)>,
13
14 #[cfg(feature = "std")]
15 error: Option<Box<dyn std::error::Error + Send + Sync + 'static>>,
16 #[cfg(all(feature = "alloc", not(feature = "std")))]
17 error: Option<Box<dyn fmt::Debug + Send + Sync + 'static>>,
18}
19
20impl Error {
21 #[cfg(feature = "std")]
23 pub fn new<E>(kind: ErrorKind, error: E) -> Error
24 where
25 E: Into<Box<dyn std::error::Error + Send + Sync + 'static>>,
26 {
27 Self { kind, _not_unwind_safe: core::marker::PhantomData, error: Some(error.into()) }
28 }
29
30 #[cfg(all(feature = "alloc", not(feature = "std")))]
32 pub fn new<E: sealed::IntoBoxDynDebug>(kind: ErrorKind, error: E) -> Error {
33 Self { kind, _not_unwind_safe: core::marker::PhantomData, error: Some(error.into()) }
34 }
35
36 pub fn kind(&self) -> ErrorKind { self.kind }
38
39 #[cfg(feature = "std")]
41 pub fn get_ref(&self) -> Option<&(dyn std::error::Error + Send + Sync + 'static)> {
42 self.error.as_deref()
43 }
44
45 #[cfg(all(feature = "alloc", not(feature = "std")))]
47 pub fn get_ref(&self) -> Option<&(dyn fmt::Debug + Send + Sync + 'static)> {
48 self.error.as_deref()
49 }
50}
51
52impl From<ErrorKind> for Error {
53 fn from(kind: ErrorKind) -> Error {
54 Self {
55 kind,
56 _not_unwind_safe: core::marker::PhantomData,
57 #[cfg(any(feature = "std", feature = "alloc"))]
58 error: None,
59 }
60 }
61}
62
63impl fmt::Display for Error {
64 fn fmt(&self, fmt: &mut fmt::Formatter) -> core::result::Result<(), core::fmt::Error> {
65 fmt.write_fmt(format_args!("I/O Error: {}", self.kind.description()))?;
66 #[cfg(any(feature = "alloc", feature = "std"))]
67 if let Some(e) = &self.error {
68 fmt.write_fmt(format_args!(". {:?}", e))?;
69 }
70 Ok(())
71 }
72}
73
74#[cfg(feature = "std")]
75impl std::error::Error for Error {
76 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
77 self.error.as_ref().and_then(|e| e.as_ref().source())
78 }
79
80 #[allow(deprecated)]
81 fn description(&self) -> &str {
82 match self.error.as_ref() {
83 Some(e) => e.description(),
84 None => self.kind.description(),
85 }
86 }
87
88 #[allow(deprecated)]
89 fn cause(&self) -> Option<&dyn std::error::Error> {
90 self.error.as_ref().and_then(|e| e.as_ref().cause())
91 }
92}
93
94#[cfg(feature = "std")]
95impl From<std::io::Error> for Error {
96 fn from(o: std::io::Error) -> Error {
97 Self {
98 kind: ErrorKind::from_std(o.kind()),
99 _not_unwind_safe: core::marker::PhantomData,
100 error: o.into_inner(),
101 }
102 }
103}
104
105#[cfg(feature = "std")]
106impl From<Error> for std::io::Error {
107 fn from(o: Error) -> std::io::Error {
108 if let Some(err) = o.error {
109 std::io::Error::new(o.kind.to_std(), err)
110 } else {
111 o.kind.to_std().into()
112 }
113 }
114}
115
116macro_rules! define_errorkind {
117 ($($(#[$($attr:tt)*])* $kind:ident),*) => {
118 #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
119 pub enum ErrorKind {
125 $(
126 $(#[$($attr)*])*
127 $kind
128 ),*
129 }
130
131 impl From<core::convert::Infallible> for ErrorKind {
132 fn from(never: core::convert::Infallible) -> Self { match never {} }
133 }
134
135 impl ErrorKind {
136 fn description(&self) -> &'static str {
137 match self {
138 $(Self::$kind => stringify!($kind)),*
139 }
140 }
141
142 #[cfg(feature = "std")]
143 fn to_std(self) -> std::io::ErrorKind {
144 match self {
145 $(Self::$kind => std::io::ErrorKind::$kind),*
146 }
147 }
148
149 #[cfg(feature = "std")]
150 fn from_std(o: std::io::ErrorKind) -> ErrorKind {
151 match o {
152 $(std::io::ErrorKind::$kind => ErrorKind::$kind),*,
153 _ => ErrorKind::Other
154 }
155 }
156 }
157 }
158}
159
160define_errorkind!(
161 NotFound,
163 PermissionDenied,
165 ConnectionRefused,
167 ConnectionReset,
169 ConnectionAborted,
171 NotConnected,
173 AddrInUse,
175 AddrNotAvailable,
177 BrokenPipe,
179 AlreadyExists,
181 WouldBlock,
183 InvalidInput,
185 InvalidData,
187 TimedOut,
189 WriteZero,
191 Interrupted,
193 UnexpectedEof,
195 Other
198);
199
200#[cfg(all(feature = "alloc", not(feature = "std")))]
201mod sealed {
202 use alloc::boxed::Box;
203 use alloc::string::String;
204 use core::fmt;
205
206 pub trait IntoBoxDynDebug {
207 fn into(self) -> Box<dyn fmt::Debug + Send + Sync + 'static>;
208 }
209
210 impl IntoBoxDynDebug for &str {
211 fn into(self) -> Box<dyn fmt::Debug + Send + Sync + 'static> {
212 Box::new(String::from(self))
213 }
214 }
215
216 impl IntoBoxDynDebug for String {
217 fn into(self) -> Box<dyn fmt::Debug + Send + Sync + 'static> { Box::new(self) }
218 }
219}