alloc/io/error.rs
1use core::io::Custom;
2#[cfg_attr(no_global_oom_handling, expect(unused_imports))]
3use core::io::CustomOwner;
4use core::{error, result};
5
6use crate::boxed::Box;
7#[cfg_attr(any(no_rc, no_sync, no_global_oom_handling), expect(unused_imports))]
8use crate::io::const_error;
9use crate::io::{Error, ErrorKind};
10
11impl Error {
12 /// Creates a new I/O error from a known kind of error as well as an
13 /// arbitrary error payload.
14 ///
15 /// This function is used to generically create I/O errors which do not
16 /// originate from the OS itself. The `error` argument is an arbitrary
17 /// payload which will be contained in this [`Error`].
18 ///
19 /// Note that this function allocates memory on the heap.
20 /// If no extra payload is required, use the `From` conversion from
21 /// `ErrorKind`.
22 ///
23 /// # Examples
24 ///
25 /// ```
26 /// use std::io::{Error, ErrorKind};
27 ///
28 /// // errors can be created from strings
29 /// let custom_error = Error::new(ErrorKind::Other, "oh no!");
30 ///
31 /// // errors can also be created from other errors
32 /// let custom_error2 = Error::new(ErrorKind::Interrupted, custom_error);
33 ///
34 /// // creating an error without payload (and without memory allocation)
35 /// let eof_error = Error::from(ErrorKind::UnexpectedEof);
36 /// ```
37 #[cfg(not(no_global_oom_handling))]
38 #[stable(feature = "rust1", since = "1.0.0")]
39 #[cfg_attr(not(test), rustc_diagnostic_item = "io_error_new")]
40 #[inline(never)]
41 #[rustc_allow_incoherent_impl]
42 pub fn new<E>(kind: ErrorKind, error: E) -> Error
43 where
44 E: Into<Box<dyn error::Error + Send + Sync>>,
45 {
46 let custom = custom_owner_from_box(kind, error.into());
47
48 // SAFETY: `custom_owner` has been constructed from a `Box` from the `alloc` crate.
49 unsafe { Self::from_custom_owner(custom) }
50 }
51
52 /// Creates a new I/O error from an arbitrary error payload.
53 ///
54 /// This function is used to generically create I/O errors which do not
55 /// originate from the OS itself. It is a shortcut for [`Error::new`][new]
56 /// with [`ErrorKind::Other`].
57 ///
58 // FIXME(#74481): Hard-links required to link from `alloc` to `std` for incoherent method
59 /// [new]: struct.Error.html#method.new
60 ///
61 /// # Examples
62 ///
63 /// ```
64 /// use std::io::Error;
65 ///
66 /// // errors can be created from strings
67 /// let custom_error = Error::other("oh no!");
68 ///
69 /// // errors can also be created from other errors
70 /// let custom_error2 = Error::other(custom_error);
71 /// ```
72 #[cfg(not(no_global_oom_handling))]
73 #[stable(feature = "io_error_other", since = "1.74.0")]
74 #[rustc_allow_incoherent_impl]
75 pub fn other<E>(error: E) -> Error
76 where
77 E: Into<Box<dyn error::Error + Send + Sync>>,
78 {
79 Self::new(ErrorKind::Other, error)
80 }
81
82 /// Consumes the `Error`, returning its inner error (if any).
83 ///
84 /// If this [`Error`] was constructed via [`new`][new] or [`other`][other],
85 /// then this function will return [`Some`],
86 /// otherwise it will return [`None`].
87 ///
88 // FIXME(#74481): Hard-links required to link from `alloc` to `std` for incoherent method
89 /// [new]: struct.Error.html#method.new
90 /// [other]: struct.Error.html#method.other
91 ///
92 /// # Examples
93 ///
94 /// ```
95 /// use std::io::{Error, ErrorKind};
96 ///
97 /// fn print_error(err: Error) {
98 /// if let Some(inner_err) = err.into_inner() {
99 /// println!("Inner error: {inner_err}");
100 /// } else {
101 /// println!("No inner error");
102 /// }
103 /// }
104 ///
105 /// fn main() {
106 /// // Will print "No inner error".
107 /// print_error(Error::last_os_error());
108 /// // Will print "Inner error: ...".
109 /// print_error(Error::new(ErrorKind::Other, "oh no!"));
110 /// }
111 /// ```
112 #[stable(feature = "io_error_inner", since = "1.3.0")]
113 #[must_use = "`self` will be dropped if the result is not used"]
114 #[inline]
115 #[rustc_allow_incoherent_impl]
116 pub fn into_inner(self) -> Option<Box<dyn error::Error + Send + Sync>> {
117 let custom_owner = self.into_custom_owner().ok()?;
118
119 let ptr = custom_owner.into_raw().as_ptr();
120
121 // SAFETY:
122 // `Error` can only contain a `CustomOwner` if it was constructed using `Box::into_raw`.
123 let custom = unsafe { Box::<Custom>::from_raw(ptr) };
124
125 let ptr = custom.into_raw().as_ptr();
126
127 // SAFETY:
128 // Any `CustomOwner` from an `Error` was constructed by the `alloc` crate
129 // to contain a `Custom` which itself was constructed with `Box::into_raw`.
130 Some(unsafe { Box::from_raw(ptr) })
131 }
132
133 /// Attempts to downcast the custom boxed error to `E`.
134 ///
135 /// If this [`Error`] contains a custom boxed error,
136 /// then it would attempt downcasting on the boxed error,
137 /// otherwise it will return [`Err`].
138 ///
139 /// If the custom boxed error has the same type as `E`, it will return [`Ok`],
140 /// otherwise it will also return [`Err`].
141 ///
142 /// This method is meant to be a convenience routine for calling
143 /// `Box<dyn Error + Sync + Send>::downcast` on the custom boxed error, returned by
144 /// [`Error::into_inner`][into_inner].
145 ///
146 // FIXME(#74481): Hard-links required to link from `alloc` to `std` for incoherent method
147 /// [into_inner]: struct.Error.html#method.into_inner
148 ///
149 /// # Examples
150 ///
151 /// ```
152 /// use std::fmt;
153 /// use std::io;
154 /// use std::error::Error;
155 ///
156 /// #[derive(Debug)]
157 /// enum E {
158 /// Io(io::Error),
159 /// SomeOtherVariant,
160 /// }
161 ///
162 /// impl fmt::Display for E {
163 /// // ...
164 /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
165 /// # todo!()
166 /// # }
167 /// }
168 /// impl Error for E {}
169 ///
170 /// impl From<io::Error> for E {
171 /// fn from(err: io::Error) -> E {
172 /// err.downcast::<E>()
173 /// .unwrap_or_else(E::Io)
174 /// }
175 /// }
176 ///
177 /// impl From<E> for io::Error {
178 /// fn from(err: E) -> io::Error {
179 /// match err {
180 /// E::Io(io_error) => io_error,
181 /// e => io::Error::new(io::ErrorKind::Other, e),
182 /// }
183 /// }
184 /// }
185 ///
186 /// # fn main() {
187 /// let e = E::SomeOtherVariant;
188 /// // Convert it to an io::Error
189 /// let io_error = io::Error::from(e);
190 /// // Cast it back to the original variant
191 /// let e = E::from(io_error);
192 /// assert!(matches!(e, E::SomeOtherVariant));
193 ///
194 /// let io_error = io::Error::from(io::ErrorKind::AlreadyExists);
195 /// // Convert it to E
196 /// let e = E::from(io_error);
197 /// // Cast it back to the original variant
198 /// let io_error = io::Error::from(e);
199 /// assert_eq!(io_error.kind(), io::ErrorKind::AlreadyExists);
200 /// assert!(io_error.get_ref().is_none());
201 /// assert!(io_error.raw_os_error().is_none());
202 /// # }
203 /// ```
204 #[stable(feature = "io_error_downcast", since = "1.79.0")]
205 #[rustc_allow_incoherent_impl]
206 pub fn downcast<E>(self) -> result::Result<E, Self>
207 where
208 E: error::Error + Send + Sync + 'static,
209 {
210 if let Some(e) = self.get_ref()
211 && e.is::<E>()
212 {
213 if let Some(b) = self.into_inner()
214 && let Ok(err) = b.downcast::<E>()
215 {
216 Ok(*err)
217 } else {
218 // Safety: We have just checked that the condition is true
219 unsafe { core::hint::unreachable_unchecked() }
220 }
221 } else {
222 Err(self)
223 }
224 }
225}
226
227#[cfg(all(not(no_rc), not(no_sync), not(no_global_oom_handling)))]
228#[stable(feature = "rust1", since = "1.0.0")]
229impl From<crate::ffi::NulError> for Error {
230 /// Converts a [`crate::ffi::NulError`] into a [`Error`].
231 fn from(_: crate::ffi::NulError) -> Error {
232 const_error!(ErrorKind::InvalidInput, "data provided contains a nul byte")
233 }
234}
235
236#[stable(feature = "io_error_from_try_reserve", since = "1.78.0")]
237impl From<crate::collections::TryReserveError> for Error {
238 /// Converts `TryReserveError` to an error with [`ErrorKind::OutOfMemory`].
239 ///
240 /// `TryReserveError` won't be available as the error `source()`,
241 /// but this may change in the future.
242 fn from(_: crate::collections::TryReserveError) -> Error {
243 // ErrorData::Custom allocates, which isn't great for handling OOM errors.
244 ErrorKind::OutOfMemory.into()
245 }
246}
247
248#[cfg(not(no_global_oom_handling))]
249fn custom_owner_from_box(
250 kind: ErrorKind,
251 error: Box<dyn core::error::Error + Send + Sync>,
252) -> CustomOwner {
253 /// # Safety
254 ///
255 /// `ptr` must be valid to pass into `Box::from_raw`.
256 unsafe fn drop_box_raw<T: ?Sized>(ptr: *mut T) {
257 // SAFETY
258 // Caller ensures `ptr` is valid to pass into `Box::from_raw`.
259 drop(unsafe { Box::from_raw(ptr) })
260 }
261
262 // SAFETY: the pointer returned by Box::into_raw is non-null.
263 let error = unsafe { core::ptr::NonNull::new_unchecked(Box::into_raw(error)) };
264
265 // SAFETY:
266 // * `error` is valid up to a static lifetime, and owns its pointee.
267 // * `drop_box_raw` is safe to call for the pointer `error` exactly once.
268 // * `drop_box_raw` is safe to call on a pointer to this instance of `Custom`,
269 // and will be stored in a `CustomOwner`.
270 let custom = unsafe { Custom::from_raw(kind, error, drop_box_raw, drop_box_raw) };
271
272 // SAFETY: the pointer returned by Box::into_raw is non-null.
273 let custom = unsafe { core::ptr::NonNull::new_unchecked(Box::into_raw(Box::new(custom))) };
274
275 // SAFETY: the `outer_drop` provided to `custom` is valid for itself.
276 unsafe { CustomOwner::from_raw(custom) }
277}