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