Skip to main content

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}