blob: eb02664ee7e46eab18604d10db31f6229d9ad2a6 [file] [edit]
use core::io::Custom;
#[cfg_attr(no_global_oom_handling, expect(unused_imports))]
use core::io::CustomOwner;
use core::{error, result};
use crate::boxed::Box;
#[cfg_attr(any(no_rc, no_sync, no_global_oom_handling), expect(unused_imports))]
use crate::io::const_error;
use crate::io::{Error, ErrorKind};
impl Error {
/// Creates a new I/O error from a known kind of error as well as an
/// arbitrary error payload.
///
/// This function is used to generically create I/O errors which do not
/// originate from the OS itself. The `error` argument is an arbitrary
/// payload which will be contained in this [`Error`].
///
/// Note that this function allocates memory on the heap.
/// If no extra payload is required, use the `From` conversion from
/// `ErrorKind`.
///
/// # Examples
///
/// ```
/// use std::io::{Error, ErrorKind};
///
/// // errors can be created from strings
/// let custom_error = Error::new(ErrorKind::Other, "oh no!");
///
/// // errors can also be created from other errors
/// let custom_error2 = Error::new(ErrorKind::Interrupted, custom_error);
///
/// // creating an error without payload (and without memory allocation)
/// let eof_error = Error::from(ErrorKind::UnexpectedEof);
/// ```
#[cfg(not(no_global_oom_handling))]
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(not(test), rustc_diagnostic_item = "io_error_new")]
#[inline(never)]
#[rustc_allow_incoherent_impl]
pub fn new<E>(kind: ErrorKind, error: E) -> Error
where
E: Into<Box<dyn error::Error + Send + Sync>>,
{
let custom = custom_owner_from_box(kind, error.into());
// SAFETY: `custom_owner` has been constructed from a `Box` from the `alloc` crate.
unsafe { Self::from_custom_owner(custom) }
}
/// Creates a new I/O error from an arbitrary error payload.
///
/// This function is used to generically create I/O errors which do not
/// originate from the OS itself. It is a shortcut for [`Error::new`][new]
/// with [`ErrorKind::Other`].
///
// FIXME(#74481): Hard-links required to link from `alloc` to `std` for incoherent method
/// [new]: struct.Error.html#method.new
///
/// # Examples
///
/// ```
/// use std::io::Error;
///
/// // errors can be created from strings
/// let custom_error = Error::other("oh no!");
///
/// // errors can also be created from other errors
/// let custom_error2 = Error::other(custom_error);
/// ```
#[cfg(not(no_global_oom_handling))]
#[stable(feature = "io_error_other", since = "1.74.0")]
#[rustc_allow_incoherent_impl]
pub fn other<E>(error: E) -> Error
where
E: Into<Box<dyn error::Error + Send + Sync>>,
{
Self::new(ErrorKind::Other, error)
}
/// Consumes the `Error`, returning its inner error (if any).
///
/// If this [`Error`] was constructed via [`new`][new] or [`other`][other],
/// then this function will return [`Some`],
/// otherwise it will return [`None`].
///
// FIXME(#74481): Hard-links required to link from `alloc` to `std` for incoherent method
/// [new]: struct.Error.html#method.new
/// [other]: struct.Error.html#method.other
///
/// # Examples
///
/// ```
/// use std::io::{Error, ErrorKind};
///
/// fn print_error(err: Error) {
/// if let Some(inner_err) = err.into_inner() {
/// println!("Inner error: {inner_err}");
/// } else {
/// println!("No inner error");
/// }
/// }
///
/// fn main() {
/// // Will print "No inner error".
/// print_error(Error::last_os_error());
/// // Will print "Inner error: ...".
/// print_error(Error::new(ErrorKind::Other, "oh no!"));
/// }
/// ```
#[stable(feature = "io_error_inner", since = "1.3.0")]
#[must_use = "`self` will be dropped if the result is not used"]
#[inline]
#[rustc_allow_incoherent_impl]
pub fn into_inner(self) -> Option<Box<dyn error::Error + Send + Sync>> {
let custom_owner = self.into_custom_owner().ok()?;
let ptr = custom_owner.into_raw().as_ptr();
// SAFETY:
// `Error` can only contain a `CustomOwner` if it was constructed using `Box::into_raw`.
let custom = unsafe { Box::<Custom>::from_raw(ptr) };
let ptr = custom.into_raw().as_ptr();
// SAFETY:
// Any `CustomOwner` from an `Error` was constructed by the `alloc` crate
// to contain a `Custom` which itself was constructed with `Box::into_raw`.
Some(unsafe { Box::from_raw(ptr) })
}
/// Attempts to downcast the custom boxed error to `E`.
///
/// If this [`Error`] contains a custom boxed error,
/// then it would attempt downcasting on the boxed error,
/// otherwise it will return [`Err`].
///
/// If the custom boxed error has the same type as `E`, it will return [`Ok`],
/// otherwise it will also return [`Err`].
///
/// This method is meant to be a convenience routine for calling
/// `Box<dyn Error + Sync + Send>::downcast` on the custom boxed error, returned by
/// [`Error::into_inner`][into_inner].
///
// FIXME(#74481): Hard-links required to link from `alloc` to `std` for incoherent method
/// [into_inner]: struct.Error.html#method.into_inner
///
/// # Examples
///
/// ```
/// use std::fmt;
/// use std::io;
/// use std::error::Error;
///
/// #[derive(Debug)]
/// enum E {
/// Io(io::Error),
/// SomeOtherVariant,
/// }
///
/// impl fmt::Display for E {
/// // ...
/// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
/// # todo!()
/// # }
/// }
/// impl Error for E {}
///
/// impl From<io::Error> for E {
/// fn from(err: io::Error) -> E {
/// err.downcast::<E>()
/// .unwrap_or_else(E::Io)
/// }
/// }
///
/// impl From<E> for io::Error {
/// fn from(err: E) -> io::Error {
/// match err {
/// E::Io(io_error) => io_error,
/// e => io::Error::new(io::ErrorKind::Other, e),
/// }
/// }
/// }
///
/// # fn main() {
/// let e = E::SomeOtherVariant;
/// // Convert it to an io::Error
/// let io_error = io::Error::from(e);
/// // Cast it back to the original variant
/// let e = E::from(io_error);
/// assert!(matches!(e, E::SomeOtherVariant));
///
/// let io_error = io::Error::from(io::ErrorKind::AlreadyExists);
/// // Convert it to E
/// let e = E::from(io_error);
/// // Cast it back to the original variant
/// let io_error = io::Error::from(e);
/// assert_eq!(io_error.kind(), io::ErrorKind::AlreadyExists);
/// assert!(io_error.get_ref().is_none());
/// assert!(io_error.raw_os_error().is_none());
/// # }
/// ```
#[stable(feature = "io_error_downcast", since = "1.79.0")]
#[rustc_allow_incoherent_impl]
pub fn downcast<E>(self) -> result::Result<E, Self>
where
E: error::Error + Send + Sync + 'static,
{
if let Some(e) = self.get_ref()
&& e.is::<E>()
{
if let Some(b) = self.into_inner()
&& let Ok(err) = b.downcast::<E>()
{
Ok(*err)
} else {
// Safety: We have just checked that the condition is true
unsafe { core::hint::unreachable_unchecked() }
}
} else {
Err(self)
}
}
}
#[cfg(all(not(no_rc), not(no_sync), not(no_global_oom_handling)))]
#[stable(feature = "rust1", since = "1.0.0")]
impl From<crate::ffi::NulError> for Error {
/// Converts a [`crate::ffi::NulError`] into a [`Error`].
fn from(_: crate::ffi::NulError) -> Error {
const_error!(ErrorKind::InvalidInput, "data provided contains a nul byte")
}
}
#[stable(feature = "io_error_from_try_reserve", since = "1.78.0")]
impl From<crate::collections::TryReserveError> for Error {
/// Converts `TryReserveError` to an error with [`ErrorKind::OutOfMemory`].
///
/// `TryReserveError` won't be available as the error `source()`,
/// but this may change in the future.
fn from(_: crate::collections::TryReserveError) -> Error {
// ErrorData::Custom allocates, which isn't great for handling OOM errors.
ErrorKind::OutOfMemory.into()
}
}
#[cfg(not(no_global_oom_handling))]
fn custom_owner_from_box(
kind: ErrorKind,
error: Box<dyn core::error::Error + Send + Sync>,
) -> CustomOwner {
/// # Safety
///
/// `ptr` must be valid to pass into `Box::from_raw`.
unsafe fn drop_box_raw<T: ?Sized>(ptr: *mut T) {
// SAFETY
// Caller ensures `ptr` is valid to pass into `Box::from_raw`.
drop(unsafe { Box::from_raw(ptr) })
}
// SAFETY: the pointer returned by Box::into_raw is non-null.
let error = unsafe { core::ptr::NonNull::new_unchecked(Box::into_raw(error)) };
// SAFETY:
// * `error` is valid up to a static lifetime, and owns its pointee.
// * `drop_box_raw` is safe to call for the pointer `error` exactly once.
// * `drop_box_raw` is safe to call on a pointer to this instance of `Custom`,
// and will be stored in a `CustomOwner`.
let custom = unsafe { Custom::from_raw(kind, error, drop_box_raw, drop_box_raw) };
// SAFETY: the pointer returned by Box::into_raw is non-null.
let custom = unsafe { core::ptr::NonNull::new_unchecked(Box::into_raw(Box::new(custom))) };
// SAFETY: the `outer_drop` provided to `custom` is valid for itself.
unsafe { CustomOwner::from_raw(custom) }
}