1#[cfg(feature = "alloc")]
6#[cfg(not(feature = "std"))]
7use alloc::boxed::Box;
8use core::fmt;
9#[cfg(feature = "std")]
10use std::boxed::Box;
11
12#[derive(Debug)]
14pub struct Error {
15 kind: ErrorKind,
16 _not_unwind_safe: core::marker::PhantomData<NotUnwindSafe>,
22
23 #[cfg(feature = "std")]
24 error: Option<Box<dyn std::error::Error + Send + Sync + 'static>>,
25 #[cfg(feature = "alloc")]
26 #[cfg(not(feature = "std"))]
27 error: Option<Box<dyn fmt::Debug + Send + Sync + 'static>>,
28}
29
30impl Error {
31 #[cfg(feature = "std")]
33 pub fn new<E>(kind: ErrorKind, error: E) -> Self
34 where
35 E: Into<Box<dyn std::error::Error + Send + Sync + 'static>>,
36 {
37 Self { kind, _not_unwind_safe: core::marker::PhantomData, error: Some(error.into()) }
38 }
39
40 #[cfg(feature = "alloc")]
42 #[cfg(not(feature = "std"))]
43 pub fn new<E: sealed::IntoBoxDynDebug>(kind: ErrorKind, error: E) -> Self {
44 Self { kind, _not_unwind_safe: core::marker::PhantomData, error: Some(error.into()) }
45 }
46
47 pub fn kind(&self) -> ErrorKind { self.kind }
49
50 #[cfg(feature = "std")]
52 pub fn get_ref(&self) -> Option<&(dyn std::error::Error + Send + Sync + 'static)> {
53 self.error.as_deref()
54 }
55
56 #[cfg(feature = "alloc")]
58 #[cfg(not(feature = "std"))]
59 pub fn get_ref(&self) -> Option<&(dyn fmt::Debug + Send + Sync + 'static)> {
60 self.error.as_deref()
61 }
62}
63
64impl From<ErrorKind> for Error {
65 fn from(kind: ErrorKind) -> Self {
66 Self {
67 kind,
68 _not_unwind_safe: core::marker::PhantomData,
69 #[cfg(any(feature = "std", feature = "alloc"))]
70 error: None,
71 }
72 }
73}
74
75impl fmt::Display for Error {
76 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
77 fmt.write_fmt(format_args!("I/O Error: {}", self.kind.description()))?;
78 #[cfg(any(feature = "alloc", feature = "std"))]
79 if let Some(e) = &self.error {
80 fmt.write_fmt(format_args!(". {:?}", e))?;
81 }
82 Ok(())
83 }
84}
85
86#[cfg(feature = "std")]
87impl std::error::Error for Error {
88 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
89 self.error.as_ref().and_then(|e| e.as_ref().source())
90 }
91}
92
93#[cfg(feature = "std")]
94impl From<std::io::Error> for Error {
95 fn from(o: std::io::Error) -> Self {
96 Self {
97 kind: ErrorKind::from_std(o.kind()),
98 _not_unwind_safe: core::marker::PhantomData,
99 error: o.into_inner(),
100 }
101 }
102}
103
104#[cfg(feature = "std")]
105impl From<Error> for std::io::Error {
106 fn from(o: Error) -> Self {
107 if let Some(err) = o.error {
108 Self::new(o.kind.to_std(), err)
109 } else {
110 o.kind.to_std().into()
111 }
112 }
113}
114
115struct NotUnwindSafe {
117 _not_unwind_safe: core::marker::PhantomData<(&'static mut (), core::cell::UnsafeCell<()>)>,
118}
119
120unsafe impl Sync for NotUnwindSafe {}
121
122macro_rules! define_errorkind {
123 ($($(#[$($attr:tt)*])* $kind:ident),*) => {
124 #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
125 pub enum ErrorKind {
131 $(
132 $(#[$($attr)*])*
133 $kind
134 ),*
135 }
136
137 impl From<core::convert::Infallible> for ErrorKind {
138 fn from(never: core::convert::Infallible) -> Self { match never {} }
139 }
140
141 impl ErrorKind {
142 fn description(&self) -> &'static str {
143 match self {
144 $(Self::$kind => stringify!($kind)),*
145 }
146 }
147
148 #[cfg(feature = "std")]
149 fn to_std(self) -> std::io::ErrorKind {
150 match self {
151 $(Self::$kind => std::io::ErrorKind::$kind),*
152 }
153 }
154
155 #[cfg(feature = "std")]
156 fn from_std(o: std::io::ErrorKind) -> ErrorKind {
157 match o {
158 $(std::io::ErrorKind::$kind => ErrorKind::$kind),*,
159 _ => ErrorKind::Other
160 }
161 }
162 }
163 }
164}
165
166define_errorkind!(
167 NotFound,
169 PermissionDenied,
171 ConnectionRefused,
173 ConnectionReset,
175 ConnectionAborted,
177 NotConnected,
179 AddrInUse,
181 AddrNotAvailable,
183 BrokenPipe,
185 AlreadyExists,
187 WouldBlock,
189 InvalidInput,
191 InvalidData,
193 TimedOut,
195 WriteZero,
197 Interrupted,
199 UnexpectedEof,
201 Other
204);
205
206#[derive(Debug)]
208pub enum ReadError<D> {
209 Io(Error),
211 Decode(D),
213}
214
215impl<D: fmt::Display> fmt::Display for ReadError<D> {
216 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
217 match self {
218 Self::Io(e) => write!(f, "I/O error: {}", e),
219 Self::Decode(e) => write!(f, "decode error: {}", e),
220 }
221 }
222}
223
224#[cfg(feature = "std")]
225impl<D> std::error::Error for ReadError<D>
226where
227 D: fmt::Debug + fmt::Display + std::error::Error + 'static,
228{
229 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
230 match self {
231 Self::Io(e) => Some(e),
232 Self::Decode(e) => Some(e),
233 }
234 }
235}
236
237#[cfg(feature = "std")]
238impl<D> From<Error> for ReadError<D> {
239 fn from(e: Error) -> Self { Self::Io(e) }
240}
241
242#[cfg(feature = "alloc")]
243#[cfg(not(feature = "std"))]
244mod sealed {
245 use alloc::boxed::Box;
246 use alloc::string::String;
247 use core::fmt;
248
249 pub trait IntoBoxDynDebug {
250 fn into(self) -> Box<dyn fmt::Debug + Send + Sync + 'static>;
251 }
252
253 impl IntoBoxDynDebug for &str {
254 fn into(self) -> Box<dyn fmt::Debug + Send + Sync + 'static> {
255 Box::new(String::from(self))
256 }
257 }
258
259 impl IntoBoxDynDebug for String {
260 fn into(self) -> Box<dyn fmt::Debug + Send + Sync + 'static> { Box::new(self) }
261 }
262}