bitcoin_io/
error.rs

1#[cfg(all(not(feature = "std"), feature = "alloc"))]
2use alloc::boxed::Box;
3use core::fmt;
4
5/// The `io` crate error type.
6#[derive(Debug)]
7pub struct Error {
8    kind: ErrorKind,
9    /// Indicates that the `struct` can pretend to own a mutable static reference
10    /// and an [`UnsafeCell`](core::cell::UnsafeCell), which are not unwind safe.
11    /// This is so that it does not introduce non-additive cargo features.
12    _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    /// Creates a new I/O error.
22    #[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    /// Creates a new I/O error.
31    #[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    /// Returns the error kind for this error.
37    pub fn kind(&self) -> ErrorKind { self.kind }
38
39    /// Returns a reference to this error.
40    #[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    /// Returns a reference to this error.
46    #[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        /// A minimal subset of [`std::io::ErrorKind`] which is used for [`Error`].
120        ///
121        /// Note that, as with [`std::io`], only [`Self::Interrupted`] has defined semantics in this
122        /// crate, all other variants are provided here only to provide higher-fidelity conversions
123        /// to and from [`std::io::Error`].
124        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    /// An entity was not found, often a file.
162    NotFound,
163    /// The operation lacked the necessary privileges to complete.
164    PermissionDenied,
165    /// The connection was refused by the remote server.
166    ConnectionRefused,
167    /// The connection was reset by the remote server.
168    ConnectionReset,
169    /// The connection was aborted (terminated) by the remote server.
170    ConnectionAborted,
171    /// The network operation failed because it was not connected yet.
172    NotConnected,
173    /// A socket address could not be bound because the address is already in use elsewhere.
174    AddrInUse,
175    /// A nonexistent interface was requested or the requested address was not local.
176    AddrNotAvailable,
177    /// The operation failed because a pipe was closed.
178    BrokenPipe,
179    /// An entity already exists, often a file.
180    AlreadyExists,
181    /// The operation needs to block to complete, but the blocking operation was requested to not occur.
182    WouldBlock,
183    /// A parameter was incorrect.
184    InvalidInput,
185    /// Data not valid for the operation were encountered.
186    InvalidData,
187    /// The I/O operation’s timeout expired, causing it to be canceled.
188    TimedOut,
189    /// An error returned when an operation could not be completed because a call to `write` returned `Ok(0)`.
190    WriteZero,
191    /// This operation was interrupted.
192    Interrupted,
193    /// An error returned when an operation could not be completed because an “end of file” was reached prematurely.
194    UnexpectedEof,
195    // Note: Any time we bump the MSRV any new error kinds should be added here!
196    /// A custom error that does not fall under any other I/O error kind
197    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}