-
-
Notifications
You must be signed in to change notification settings - Fork 15k
Move std::io::Error into core
#155625
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
bushrat011899
wants to merge
12
commits into
rust-lang:main
Choose a base branch
from
bushrat011899:core_io_error
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Move std::io::Error into core
#155625
Changes from all commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
4bb8491
Adjust `std::io::Error` tests to only assess public API
bushrat011899 6b5e66c
Adjust `Error` documentation
bushrat011899 3fc80ca
Change `repr` module definition to use `path` attribute
bushrat011899 ebdd34e
Setup `alloc::io`
bushrat011899 1e4d5ad
Make common `Error` constants public and hidden
bushrat011899 7051740
Allow use of incoherence
bushrat011899 b12eab2
Make `Error::is_interrupted` public and hidden
bushrat011899 98fdd49
Remove usage of `Box` from `Error` internals
bushrat011899 be13aea
Delegate `RawOsError` functionality to `OsFunctions`
bushrat011899 b4b96de
Move `std::io::Error` and friends into `core` and `alloc`
bushrat011899 d1c58d4
Reduce usage of unstable public items
bushrat011899 4302863
Simplify `core::io` documentation links
bushrat011899 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,274 @@ | ||
| 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`]. | ||
| /// | ||
| /// [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`]. | ||
| /// | ||
| /// [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]. | ||
| /// | ||
| /// [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) } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| //! Traits, helpers, and type definitions for core I/O functionality. | ||
|
|
||
| mod error; | ||
|
|
||
| #[unstable(feature = "raw_os_error_ty", issue = "107792")] | ||
| pub use core::io::RawOsError; | ||
| #[unstable(feature = "io_const_error_internals", issue = "none")] | ||
| pub use core::io::SimpleMessage; | ||
| #[unstable(feature = "io_const_error", issue = "133448")] | ||
| pub use core::io::const_error; | ||
| #[unstable(feature = "core_io_borrowed_buf", issue = "117693")] | ||
| pub use core::io::{BorrowedBuf, BorrowedCursor}; | ||
| #[unstable(feature = "alloc_io", issue = "154046")] | ||
| pub use core::io::{ | ||
| Chain, Cursor, Empty, Error, ErrorKind, IoSlice, IoSliceMut, Repeat, Result, Sink, Take, empty, | ||
| repeat, sink, | ||
| }; | ||
| #[doc(hidden)] | ||
| #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] | ||
| pub use core::io::{OsFunctions, chain, take}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.