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