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