| author | bors <bors@rust-lang.org> 2026-06-29 00:40:20 UTC |
| committer | bors <bors@rust-lang.org> 2026-06-29 00:40:20 UTC |
| log | 7fb284d9037fa54f6a9b24261c82b394472cbfd7 |
| tree | 538b8d54cec93c05e9ff4187624db4c4562543ab |
| parent | df6ee909ef35c75aa58aa45af6ac071a9b8285c2 |
| parent | 3fa872ca7932853d12ef66a37c39988cd7bec92b |
Move `std::io::Error` into `core`
ACP: https://github.com/rust-lang/libs-team/issues/755
Tracking issue: https://github.com/rust-lang/rust/issues/154046
Related: https://github.com/rust-lang/rust/pull/155574
Related: https://github.com/rust-lang/rust/pull/152918
## Description
Moves `std::io::Error` into `core`, deferring `Box`-adjacent methods to incoherent implementations in `alloc`, and `RawOsError` methods to `std`. This requires some substantial changes to the internals of `Error`, but none of them are breaking changes or externally visible.
Notably, I've replaced usage of `Box` with a wrapper around a pointer and an appropriate drop function. This requires the addition of quite a few lines of unsafe, but is required to work around `Box` only being accessible from `alloc`. Additionally, an atomic pointer to a VTable is used for working with `RawOsError` in `core`, since we cannot know the required implementations without `std`.
As mention in [this comment](https://github.com/rust-lang/rust/pull/155625#issuecomment-4744932682), there may be concern around having a static `AtomicPtr` in `core` for certain users. I've added a configuration option `no_io_statics` which (similar to `no_sync`/etc. in `alloc`) can be used to prevent their inclusion in `core`. When active, the fallback default implementation will always be used.
---
## Notes
* This PR adopts the VTable technique from rust-lang/rust#152918
* This PR builds on my previous PR rust-lang/rust#155574
* No AI tooling of any kind was used during the creation of this PR.
21 files changed, 1592 insertions(+), 1164 deletions(-)
library/alloc/src/io/error.rs created+274| ... | ... | @@ -0,0 +1,274 @@ |
| 1 | use core::io::Custom; | |
| 2 | #[cfg_attr(no_global_oom_handling, expect(unused_imports))] | |
| 3 | use core::io::CustomOwner; | |
| 4 | use core::{error, result}; | |
| 5 | ||
| 6 | use crate::boxed::Box; | |
| 7 | #[cfg_attr(any(no_rc, no_sync, no_global_oom_handling), expect(unused_imports))] | |
| 8 | use crate::io::const_error; | |
| 9 | use crate::io::{Error, ErrorKind}; | |
| 10 | ||
| 11 | impl 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")] | |
| 226 | impl 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")] | |
| 234 | impl 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))] | |
| 246 | fn 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 | } |
library/alloc/src/io/mod.rs created+20| ... | ... | @@ -0,0 +1,20 @@ |
| 1 | //! Traits, helpers, and type definitions for core I/O functionality. | |
| 2 | ||
| 3 | mod error; | |
| 4 | ||
| 5 | #[unstable(feature = "raw_os_error_ty", issue = "107792")] | |
| 6 | pub use core::io::RawOsError; | |
| 7 | #[unstable(feature = "io_const_error_internals", issue = "none")] | |
| 8 | pub use core::io::SimpleMessage; | |
| 9 | #[unstable(feature = "io_const_error", issue = "133448")] | |
| 10 | pub use core::io::const_error; | |
| 11 | #[unstable(feature = "core_io_borrowed_buf", issue = "117693")] | |
| 12 | pub use core::io::{BorrowedBuf, BorrowedCursor}; | |
| 13 | #[unstable(feature = "alloc_io", issue = "154046")] | |
| 14 | pub use core::io::{ | |
| 15 | Chain, Cursor, Empty, Error, ErrorKind, IoSlice, IoSliceMut, Repeat, Result, Sink, Take, empty, | |
| 16 | repeat, sink, | |
| 17 | }; | |
| 18 | #[doc(hidden)] | |
| 19 | #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] | |
| 20 | pub use core::io::{OsFunctions, chain, take}; |
library/alloc/src/lib.rs+8| ... | ... | @@ -116,6 +116,9 @@ |
| 116 | 116 | #![feature(const_try)] |
| 117 | 117 | #![feature(copied_into_inner)] |
| 118 | 118 | #![feature(core_intrinsics)] |
| 119 | #![feature(core_io)] | |
| 120 | #![feature(core_io_borrowed_buf)] | |
| 121 | #![feature(core_io_internals)] | |
| 119 | 122 | #![feature(deprecated_suggestion)] |
| 120 | 123 | #![feature(deref_pure_trait)] |
| 121 | 124 | #![feature(diagnostic_on_move)] |
| ... | ... | @@ -133,6 +136,8 @@ |
| 133 | 136 | #![feature(generic_atomic)] |
| 134 | 137 | #![feature(hasher_prefixfree_extras)] |
| 135 | 138 | #![feature(inplace_iteration)] |
| 139 | #![feature(io_const_error)] | |
| 140 | #![feature(io_const_error_internals)] | |
| 136 | 141 | #![feature(iter_advance_by)] |
| 137 | 142 | #![feature(iter_next_chunk)] |
| 138 | 143 | #![feature(layout_for_ptr)] |
| ... | ... | @@ -147,6 +152,7 @@ |
| 147 | 152 | #![feature(ptr_cast_slice)] |
| 148 | 153 | #![feature(ptr_internals)] |
| 149 | 154 | #![feature(ptr_metadata)] |
| 155 | #![feature(raw_os_error_ty)] | |
| 150 | 156 | #![feature(rev_into_inner)] |
| 151 | 157 | #![feature(set_ptr_value)] |
| 152 | 158 | #![feature(share_trait)] |
| ... | ... | @@ -236,6 +242,8 @@ pub mod collections; |
| 236 | 242 | pub mod ffi; |
| 237 | 243 | pub mod fmt; |
| 238 | 244 | pub mod intrinsics; |
| 245 | #[unstable(feature = "alloc_io", issue = "154046")] | |
| 246 | pub mod io; | |
| 239 | 247 | #[cfg(not(no_rc))] |
| 240 | 248 | pub mod rc; |
| 241 | 249 | pub mod slice; |
library/core/Cargo.toml+3| ... | ... | @@ -40,5 +40,8 @@ check-cfg = [ |
| 40 | 40 | 'cfg(target_has_reliable_f128)', |
| 41 | 41 | 'cfg(target_has_reliable_f128_math)', |
| 42 | 42 | 'cfg(llvm_enzyme)', |
| 43 | # Prevents use of a static variable for providing platform specific RawOsError | |
| 44 | # functionality | |
| 45 | 'cfg(no_io_statics)', | |
| 43 | 46 | |
| 44 | 47 | ] |
library/core/src/io/error.rs+708-7| ... | ... | @@ -1,6 +1,708 @@ |
| 1 | 1 | #![unstable(feature = "core_io", issue = "154046")] |
| 2 | 2 | |
| 3 | use crate::fmt; | |
| 3 | // On 64-bit platforms, `io::Error` may use a bit-packed representation to | |
| 4 | // reduce size. However, this representation assumes that error codes are | |
| 5 | // always 32-bit wide. | |
| 6 | // | |
| 7 | // This assumption is invalid on 64-bit UEFI, where error codes are 64-bit. | |
| 8 | // Therefore, the packed representation is explicitly disabled for UEFI | |
| 9 | // targets, and the unpacked representation must be used instead. | |
| 10 | #[cfg_attr( | |
| 11 | all(target_pointer_width = "64", not(target_os = "uefi")), | |
| 12 | path = "error/repr_bitpacked.rs" | |
| 13 | )] | |
| 14 | #[cfg_attr( | |
| 15 | not(all(target_pointer_width = "64", not(target_os = "uefi"))), | |
| 16 | path = "error/repr_unpacked.rs" | |
| 17 | )] | |
| 18 | mod repr; | |
| 19 | ||
| 20 | #[cfg_attr( | |
| 21 | all(target_has_atomic_load_store = "ptr", not(no_io_statics)), | |
| 22 | path = "error/os_functions_atomic.rs" | |
| 23 | )] | |
| 24 | #[cfg_attr( | |
| 25 | not(all(target_has_atomic_load_store = "ptr", not(no_io_statics))), | |
| 26 | path = "error/os_functions.rs" | |
| 27 | )] | |
| 28 | mod os_functions; | |
| 29 | ||
| 30 | use self::os_functions::{decode_error_kind, format_os_error, is_interrupted, set_functions}; | |
| 31 | use self::repr::Repr; | |
| 32 | use crate::{error, fmt, result}; | |
| 33 | ||
| 34 | /// A specialized [`Result`] type for I/O operations. | |
| 35 | /// | |
| 36 | /// This type is broadly used across [`std::io`] for any operation which may | |
| 37 | /// produce an error. | |
| 38 | /// | |
| 39 | /// This type alias is generally used to avoid writing out [`io::Error`] directly and | |
| 40 | /// is otherwise a direct mapping to [`Result`]. | |
| 41 | /// | |
| 42 | /// While usual Rust style is to import types directly, aliases of [`Result`] | |
| 43 | /// often are not, to make it easier to distinguish between them. [`Result`] is | |
| 44 | /// generally assumed to be [`core::result::Result`][`Result`], and so users of this alias | |
| 45 | /// will generally use `io::Result` instead of shadowing the [prelude]'s import | |
| 46 | /// of [`core::result::Result`][`Result`]. | |
| 47 | /// | |
| 48 | /// [`std::io`]: ../../std/io/index.html | |
| 49 | /// [`io::Error`]: Error | |
| 50 | /// [`Result`]: crate::result::Result | |
| 51 | /// [prelude]: crate::prelude | |
| 52 | /// | |
| 53 | /// # Examples | |
| 54 | /// | |
| 55 | /// A convenience function that bubbles an `io::Result` to its caller: | |
| 56 | /// | |
| 57 | /// ``` | |
| 58 | /// use std::io; | |
| 59 | /// | |
| 60 | /// fn get_string() -> io::Result<String> { | |
| 61 | /// let mut buffer = String::new(); | |
| 62 | /// | |
| 63 | /// io::stdin().read_line(&mut buffer)?; | |
| 64 | /// | |
| 65 | /// Ok(buffer) | |
| 66 | /// } | |
| 67 | /// ``` | |
| 68 | #[stable(feature = "rust1", since = "1.0.0")] | |
| 69 | #[doc(search_unbox)] | |
| 70 | pub type Result<T> = result::Result<T, Error>; | |
| 71 | ||
| 72 | /// The error type for I/O operations of the [`Read`][Read], [`Write`][Write], [`Seek`][Seek], and | |
| 73 | /// associated traits. | |
| 74 | /// | |
| 75 | /// Errors mostly originate from the underlying OS, but custom instances of | |
| 76 | /// `Error` can be created with crafted error messages and a particular value of | |
| 77 | /// [`ErrorKind`]. | |
| 78 | /// | |
| 79 | /// [Read]: ../../std/io/trait.Read.html | |
| 80 | /// [Write]: ../../std/io/trait.Write.html | |
| 81 | /// [Seek]: ../../std/io/trait.Seek.html | |
| 82 | #[stable(feature = "rust1", since = "1.0.0")] | |
| 83 | #[rustc_has_incoherent_inherent_impls] | |
| 84 | pub struct Error { | |
| 85 | repr: Repr, | |
| 86 | } | |
| 87 | ||
| 88 | #[stable(feature = "rust1", since = "1.0.0")] | |
| 89 | impl fmt::Debug for Error { | |
| 90 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
| 91 | fmt::Debug::fmt(&self.repr, f) | |
| 92 | } | |
| 93 | } | |
| 94 | ||
| 95 | /// Common errors constants for use in std | |
| 96 | #[doc(hidden)] | |
| 97 | impl Error { | |
| 98 | #[doc(hidden)] | |
| 99 | #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] | |
| 100 | pub const INVALID_UTF8: Self = | |
| 101 | const_error!(ErrorKind::InvalidData, "stream did not contain valid UTF-8"); | |
| 102 | ||
| 103 | #[doc(hidden)] | |
| 104 | #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] | |
| 105 | pub const READ_EXACT_EOF: Self = | |
| 106 | const_error!(ErrorKind::UnexpectedEof, "failed to fill whole buffer"); | |
| 107 | ||
| 108 | #[doc(hidden)] | |
| 109 | #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] | |
| 110 | pub const UNKNOWN_THREAD_COUNT: Self = const_error!( | |
| 111 | ErrorKind::NotFound, | |
| 112 | "the number of hardware threads is not known for the target platform", | |
| 113 | ); | |
| 114 | ||
| 115 | #[doc(hidden)] | |
| 116 | #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] | |
| 117 | pub const UNSUPPORTED_PLATFORM: Self = | |
| 118 | const_error!(ErrorKind::Unsupported, "operation not supported on this platform"); | |
| 119 | ||
| 120 | #[doc(hidden)] | |
| 121 | #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] | |
| 122 | pub const WRITE_ALL_EOF: Self = | |
| 123 | const_error!(ErrorKind::WriteZero, "failed to write whole buffer"); | |
| 124 | ||
| 125 | #[doc(hidden)] | |
| 126 | #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] | |
| 127 | pub const ZERO_TIMEOUT: Self = | |
| 128 | const_error!(ErrorKind::InvalidInput, "cannot set a 0 duration timeout"); | |
| 129 | ||
| 130 | #[doc(hidden)] | |
| 131 | #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] | |
| 132 | pub const NO_ADDRESSES: Self = | |
| 133 | const_error!(ErrorKind::InvalidInput, "could not resolve to any addresses"); | |
| 134 | } | |
| 135 | ||
| 136 | // Only derive debug in tests, to make sure it | |
| 137 | // doesn't accidentally get printed. | |
| 138 | #[cfg_attr(test, derive(Debug))] | |
| 139 | enum ErrorData<C> { | |
| 140 | Os(RawOsError), | |
| 141 | Simple(ErrorKind), | |
| 142 | SimpleMessage(&'static SimpleMessage), | |
| 143 | Custom(C), | |
| 144 | } | |
| 145 | ||
| 146 | // `#[repr(align(4))]` is probably redundant, it should have that value or | |
| 147 | // higher already. We include it just because repr_bitpacked.rs's encoding | |
| 148 | // requires an alignment >= 4 (note that `#[repr(align)]` will not reduce the | |
| 149 | // alignment required by the struct, only increase it). | |
| 150 | // | |
| 151 | // If we add more variants to ErrorData, this can be increased to 8, but it | |
| 152 | // should probably be behind `#[cfg_attr(target_pointer_width = "64", ...)]` or | |
| 153 | // whatever cfg we're using to enable the `repr_bitpacked` code, since only the | |
| 154 | // that version needs the alignment, and 8 is higher than the alignment we'll | |
| 155 | // have on 32 bit platforms. | |
| 156 | // | |
| 157 | // (For the sake of being explicit: the alignment requirement here only matters | |
| 158 | // if `error/repr_bitpacked.rs` is in use — for the unpacked repr it doesn't | |
| 159 | // matter at all) | |
| 160 | #[doc(hidden)] | |
| 161 | #[unstable(feature = "io_const_error_internals", issue = "none")] | |
| 162 | #[repr(align(4))] | |
| 163 | #[derive(Debug)] | |
| 164 | pub struct SimpleMessage { | |
| 165 | pub kind: ErrorKind, | |
| 166 | pub message: &'static str, | |
| 167 | } | |
| 168 | ||
| 169 | /// Creates a new I/O error from a known kind of error and a string literal. | |
| 170 | /// | |
| 171 | /// Contrary to [`Error::new`][new], this macro does not allocate and can be used in | |
| 172 | /// `const` contexts. | |
| 173 | /// | |
| 174 | /// [new]: ../../alloc/io/struct.Error.html#method.new | |
| 175 | /// | |
| 176 | /// # Example | |
| 177 | /// ``` | |
| 178 | /// #![feature(io_const_error)] | |
| 179 | /// use std::io::{const_error, Error, ErrorKind}; | |
| 180 | /// | |
| 181 | /// const FAIL: Error = const_error!(ErrorKind::Unsupported, "tried something that never works"); | |
| 182 | /// | |
| 183 | /// fn not_here() -> Result<(), Error> { | |
| 184 | /// Err(FAIL) | |
| 185 | /// } | |
| 186 | /// ``` | |
| 187 | #[rustc_macro_transparency = "semiopaque"] | |
| 188 | #[unstable(feature = "io_const_error", issue = "133448")] | |
| 189 | #[allow_internal_unstable(core_io, hint_must_use, io_const_error_internals)] | |
| 190 | pub macro const_error($kind:expr, $message:expr $(,)?) { | |
| 191 | $crate::hint::must_use($crate::io::Error::from_static_message( | |
| 192 | const { &$crate::io::SimpleMessage { kind: $kind, message: $message } }, | |
| 193 | )) | |
| 194 | } | |
| 195 | ||
| 196 | /// Intended for use for errors not exposed to the user, where allocating onto | |
| 197 | /// the heap (for normal construction via Error::new) is too costly. | |
| 198 | #[stable(feature = "io_error_from_errorkind", since = "1.14.0")] | |
| 199 | impl From<ErrorKind> for Error { | |
| 200 | /// Converts an [`ErrorKind`] into an [`Error`]. | |
| 201 | /// | |
| 202 | /// This conversion creates a new error with a simple representation of error kind. | |
| 203 | /// | |
| 204 | /// # Examples | |
| 205 | /// | |
| 206 | /// ``` | |
| 207 | /// use std::io::{Error, ErrorKind}; | |
| 208 | /// | |
| 209 | /// let not_found = ErrorKind::NotFound; | |
| 210 | /// let error = Error::from(not_found); | |
| 211 | /// assert_eq!("entity not found", format!("{error}")); | |
| 212 | /// ``` | |
| 213 | #[inline] | |
| 214 | fn from(kind: ErrorKind) -> Error { | |
| 215 | Error { repr: Repr::new_simple(kind) } | |
| 216 | } | |
| 217 | } | |
| 218 | ||
| 219 | impl Error { | |
| 220 | /// # Safety | |
| 221 | /// | |
| 222 | /// The provided `CustomOwner` must have been constructed from a `Box` from the `alloc` crate. | |
| 223 | #[doc(hidden)] | |
| 224 | #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] | |
| 225 | #[must_use] | |
| 226 | #[inline] | |
| 227 | pub unsafe fn from_custom_owner(custom: CustomOwner) -> Error { | |
| 228 | Error { repr: Repr::new_custom(custom) } | |
| 229 | } | |
| 230 | ||
| 231 | #[doc(hidden)] | |
| 232 | #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] | |
| 233 | #[must_use] | |
| 234 | #[inline] | |
| 235 | pub fn into_custom_owner(self) -> result::Result<CustomOwner, Self> { | |
| 236 | if matches!(self.repr.data(), ErrorData::Custom(..)) { | |
| 237 | let ErrorData::Custom(c) = self.repr.into_data() else { | |
| 238 | // SAFETY: Checked above using `matches!`. | |
| 239 | unsafe { crate::hint::unreachable_unchecked() } | |
| 240 | }; | |
| 241 | Ok(c) | |
| 242 | } else { | |
| 243 | Err(self) | |
| 244 | } | |
| 245 | } | |
| 246 | ||
| 247 | /// Creates a new I/O error from a known kind of error as well as a constant | |
| 248 | /// message. | |
| 249 | /// | |
| 250 | /// This function does not allocate. | |
| 251 | /// | |
| 252 | /// You should not use this directly, and instead use the `const_error!` | |
| 253 | /// macro: `io::const_error!(ErrorKind::Something, "some_message")`. | |
| 254 | /// | |
| 255 | /// This function should maybe change to `from_static_message<const MSG: &'static | |
| 256 | /// str>(kind: ErrorKind)` in the future, when const generics allow that. | |
| 257 | #[inline] | |
| 258 | #[doc(hidden)] | |
| 259 | #[unstable(feature = "io_const_error_internals", issue = "none")] | |
| 260 | pub const fn from_static_message(msg: &'static SimpleMessage) -> Error { | |
| 261 | Self { repr: Repr::new_simple_message(msg) } | |
| 262 | } | |
| 263 | ||
| 264 | /// # Safety | |
| 265 | /// | |
| 266 | /// `functions` must point to data that is entirely constant; it must | |
| 267 | /// not be created during runtime. | |
| 268 | #[doc(hidden)] | |
| 269 | #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] | |
| 270 | #[must_use] | |
| 271 | #[inline] | |
| 272 | pub unsafe fn from_raw_os_error_with_functions( | |
| 273 | code: RawOsError, | |
| 274 | functions: &'static OsFunctions, | |
| 275 | ) -> Error { | |
| 276 | // SAFETY: Caller ensures `functions` is a constant not created at runtime. | |
| 277 | unsafe { | |
| 278 | set_functions(functions); | |
| 279 | } | |
| 280 | Error { repr: Repr::new_os(code) } | |
| 281 | } | |
| 282 | ||
| 283 | /// Returns the OS error that this error represents (if any). | |
| 284 | /// | |
| 285 | /// If this [`Error`] was constructed via [`last_os_error`][last_os_error] or | |
| 286 | /// [`from_raw_os_error`][from_raw_os_error], then this function will return [`Some`], otherwise | |
| 287 | /// it will return [`None`]. | |
| 288 | /// | |
| 289 | /// [last_os_error]: ../../std/io/struct.Error.html#method.last_os_error | |
| 290 | /// [from_raw_os_error]: ../../std/io/struct.Error.html#method.from_raw_os_error | |
| 291 | /// | |
| 292 | /// # Examples | |
| 293 | /// | |
| 294 | /// ``` | |
| 295 | /// use std::io::{Error, ErrorKind}; | |
| 296 | /// | |
| 297 | /// fn print_os_error(err: &Error) { | |
| 298 | /// if let Some(raw_os_err) = err.raw_os_error() { | |
| 299 | /// println!("raw OS error: {raw_os_err:?}"); | |
| 300 | /// } else { | |
| 301 | /// println!("Not an OS error"); | |
| 302 | /// } | |
| 303 | /// } | |
| 304 | /// | |
| 305 | /// fn main() { | |
| 306 | /// // Will print "raw OS error: ...". | |
| 307 | /// print_os_error(&Error::last_os_error()); | |
| 308 | /// // Will print "Not an OS error". | |
| 309 | /// print_os_error(&Error::new(ErrorKind::Other, "oh no!")); | |
| 310 | /// } | |
| 311 | /// ``` | |
| 312 | #[stable(feature = "rust1", since = "1.0.0")] | |
| 313 | #[must_use] | |
| 314 | #[inline] | |
| 315 | pub fn raw_os_error(&self) -> Option<RawOsError> { | |
| 316 | match self.repr.data() { | |
| 317 | ErrorData::Os(i) => Some(i), | |
| 318 | ErrorData::Custom(..) => None, | |
| 319 | ErrorData::Simple(..) => None, | |
| 320 | ErrorData::SimpleMessage(..) => None, | |
| 321 | } | |
| 322 | } | |
| 323 | ||
| 324 | /// Returns a reference to the inner error wrapped by this error (if any). | |
| 325 | /// | |
| 326 | /// If this [`Error`] was constructed via [`new`][new] then this function will | |
| 327 | /// return [`Some`], otherwise it will return [`None`]. | |
| 328 | /// | |
| 329 | /// [new]: ../../alloc/io/struct.Error.html#method.new | |
| 330 | /// | |
| 331 | /// # Examples | |
| 332 | /// | |
| 333 | /// ``` | |
| 334 | /// use std::io::{Error, ErrorKind}; | |
| 335 | /// | |
| 336 | /// fn print_error(err: &Error) { | |
| 337 | /// if let Some(inner_err) = err.get_ref() { | |
| 338 | /// println!("Inner error: {inner_err:?}"); | |
| 339 | /// } else { | |
| 340 | /// println!("No inner error"); | |
| 341 | /// } | |
| 342 | /// } | |
| 343 | /// | |
| 344 | /// fn main() { | |
| 345 | /// // Will print "No inner error". | |
| 346 | /// print_error(&Error::last_os_error()); | |
| 347 | /// // Will print "Inner error: ...". | |
| 348 | /// print_error(&Error::new(ErrorKind::Other, "oh no!")); | |
| 349 | /// } | |
| 350 | /// ``` | |
| 351 | #[stable(feature = "io_error_inner", since = "1.3.0")] | |
| 352 | #[must_use] | |
| 353 | #[inline] | |
| 354 | pub fn get_ref(&self) -> Option<&(dyn error::Error + Send + Sync + 'static)> { | |
| 355 | match self.repr.data() { | |
| 356 | ErrorData::Os(..) => None, | |
| 357 | ErrorData::Simple(..) => None, | |
| 358 | ErrorData::SimpleMessage(..) => None, | |
| 359 | ErrorData::Custom(c) => Some(c.error_ref()), | |
| 360 | } | |
| 361 | } | |
| 362 | ||
| 363 | /// Returns a mutable reference to the inner error wrapped by this error | |
| 364 | /// (if any). | |
| 365 | /// | |
| 366 | /// If this [`Error`] was constructed via [`new`][new] then this function will | |
| 367 | /// return [`Some`], otherwise it will return [`None`]. | |
| 368 | /// | |
| 369 | /// [new]: ../../alloc/io/struct.Error.html#method.new | |
| 370 | /// | |
| 371 | /// # Examples | |
| 372 | /// | |
| 373 | /// ``` | |
| 374 | /// use std::io::{Error, ErrorKind}; | |
| 375 | /// use std::{error, fmt}; | |
| 376 | /// use std::fmt::Display; | |
| 377 | /// | |
| 378 | /// #[derive(Debug)] | |
| 379 | /// struct MyError { | |
| 380 | /// v: String, | |
| 381 | /// } | |
| 382 | /// | |
| 383 | /// impl MyError { | |
| 384 | /// fn new() -> MyError { | |
| 385 | /// MyError { | |
| 386 | /// v: "oh no!".to_string() | |
| 387 | /// } | |
| 388 | /// } | |
| 389 | /// | |
| 390 | /// fn change_message(&mut self, new_message: &str) { | |
| 391 | /// self.v = new_message.to_string(); | |
| 392 | /// } | |
| 393 | /// } | |
| 394 | /// | |
| 395 | /// impl error::Error for MyError {} | |
| 396 | /// | |
| 397 | /// impl Display for MyError { | |
| 398 | /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
| 399 | /// write!(f, "MyError: {}", self.v) | |
| 400 | /// } | |
| 401 | /// } | |
| 402 | /// | |
| 403 | /// fn change_error(mut err: Error) -> Error { | |
| 404 | /// if let Some(inner_err) = err.get_mut() { | |
| 405 | /// inner_err.downcast_mut::<MyError>().unwrap().change_message("I've been changed!"); | |
| 406 | /// } | |
| 407 | /// err | |
| 408 | /// } | |
| 409 | /// | |
| 410 | /// fn print_error(err: &Error) { | |
| 411 | /// if let Some(inner_err) = err.get_ref() { | |
| 412 | /// println!("Inner error: {inner_err}"); | |
| 413 | /// } else { | |
| 414 | /// println!("No inner error"); | |
| 415 | /// } | |
| 416 | /// } | |
| 417 | /// | |
| 418 | /// fn main() { | |
| 419 | /// // Will print "No inner error". | |
| 420 | /// print_error(&change_error(Error::last_os_error())); | |
| 421 | /// // Will print "Inner error: ...". | |
| 422 | /// print_error(&change_error(Error::new(ErrorKind::Other, MyError::new()))); | |
| 423 | /// } | |
| 424 | /// ``` | |
| 425 | #[stable(feature = "io_error_inner", since = "1.3.0")] | |
| 426 | #[must_use] | |
| 427 | #[inline] | |
| 428 | pub fn get_mut(&mut self) -> Option<&mut (dyn error::Error + Send + Sync + 'static)> { | |
| 429 | match self.repr.data_mut() { | |
| 430 | ErrorData::Os(..) => None, | |
| 431 | ErrorData::Simple(..) => None, | |
| 432 | ErrorData::SimpleMessage(..) => None, | |
| 433 | ErrorData::Custom(c) => Some(c.error_mut()), | |
| 434 | } | |
| 435 | } | |
| 436 | ||
| 437 | /// Returns the corresponding [`ErrorKind`] for this error. | |
| 438 | /// | |
| 439 | /// This may be a value set by Rust code constructing custom `io::Error`s, | |
| 440 | /// or if this `io::Error` was sourced from the operating system, | |
| 441 | /// it will be a value inferred from the system's error encoding. | |
| 442 | /// See [`last_os_error`][last_os_error] for more details. | |
| 443 | /// | |
| 444 | /// [last_os_error]: ../../std/io/struct.Error.html#method.last_os_error | |
| 445 | /// | |
| 446 | /// # Examples | |
| 447 | /// | |
| 448 | /// ``` | |
| 449 | /// use std::io::{Error, ErrorKind}; | |
| 450 | /// | |
| 451 | /// fn print_error(err: Error) { | |
| 452 | /// println!("{:?}", err.kind()); | |
| 453 | /// } | |
| 454 | /// | |
| 455 | /// fn main() { | |
| 456 | /// // As no error has (visibly) occurred, this may print anything! | |
| 457 | /// // It likely prints a placeholder for unidentified (non-)errors. | |
| 458 | /// print_error(Error::last_os_error()); | |
| 459 | /// // Will print "AddrInUse". | |
| 460 | /// print_error(Error::new(ErrorKind::AddrInUse, "oh no!")); | |
| 461 | /// } | |
| 462 | /// ``` | |
| 463 | #[stable(feature = "rust1", since = "1.0.0")] | |
| 464 | #[must_use] | |
| 465 | #[inline] | |
| 466 | pub fn kind(&self) -> ErrorKind { | |
| 467 | match self.repr.data() { | |
| 468 | ErrorData::Os(code) => decode_error_kind(code), | |
| 469 | ErrorData::Custom(c) => c.kind, | |
| 470 | ErrorData::Simple(kind) => kind, | |
| 471 | ErrorData::SimpleMessage(m) => m.kind, | |
| 472 | } | |
| 473 | } | |
| 474 | ||
| 475 | #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] | |
| 476 | #[doc(hidden)] | |
| 477 | #[inline] | |
| 478 | pub fn is_interrupted(&self) -> bool { | |
| 479 | match self.repr.data() { | |
| 480 | ErrorData::Os(code) => is_interrupted(code), | |
| 481 | ErrorData::Custom(c) => c.kind == ErrorKind::Interrupted, | |
| 482 | ErrorData::Simple(kind) => kind == ErrorKind::Interrupted, | |
| 483 | ErrorData::SimpleMessage(m) => m.kind == ErrorKind::Interrupted, | |
| 484 | } | |
| 485 | } | |
| 486 | } | |
| 487 | ||
| 488 | impl fmt::Debug for Repr { | |
| 489 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { | |
| 490 | match self.data() { | |
| 491 | ErrorData::Os(code) => fmt | |
| 492 | .debug_struct("Os") | |
| 493 | .field("code", &code) | |
| 494 | .field("kind", &decode_error_kind(code)) | |
| 495 | .field( | |
| 496 | "message", | |
| 497 | &fmt::from_fn(|fmt| { | |
| 498 | write!(fmt, "\"{}\"", fmt::from_fn(|fmt| format_os_error(code, fmt))) | |
| 499 | }), | |
| 500 | ) | |
| 501 | .finish(), | |
| 502 | ErrorData::Custom(c) => fmt::Debug::fmt(&c, fmt), | |
| 503 | ErrorData::Simple(kind) => fmt.debug_tuple("Kind").field(&kind).finish(), | |
| 504 | ErrorData::SimpleMessage(msg) => fmt | |
| 505 | .debug_struct("Error") | |
| 506 | .field("kind", &msg.kind) | |
| 507 | .field("message", &msg.message) | |
| 508 | .finish(), | |
| 509 | } | |
| 510 | } | |
| 511 | } | |
| 512 | ||
| 513 | #[stable(feature = "rust1", since = "1.0.0")] | |
| 514 | impl fmt::Display for Error { | |
| 515 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { | |
| 516 | match self.repr.data() { | |
| 517 | ErrorData::Os(code) => { | |
| 518 | let detail = fmt::from_fn(|fmt| format_os_error(code, fmt)); | |
| 519 | write!(fmt, "{detail} (os error {code})") | |
| 520 | } | |
| 521 | ErrorData::Custom(c) => fmt::Display::fmt(c.error_ref(), fmt), | |
| 522 | ErrorData::Simple(kind) => kind.fmt(fmt), | |
| 523 | ErrorData::SimpleMessage(msg) => msg.message.fmt(fmt), | |
| 524 | } | |
| 525 | } | |
| 526 | } | |
| 527 | ||
| 528 | #[stable(feature = "rust1", since = "1.0.0")] | |
| 529 | impl error::Error for Error { | |
| 530 | #[allow(deprecated)] | |
| 531 | fn cause(&self) -> Option<&dyn error::Error> { | |
| 532 | match self.repr.data() { | |
| 533 | ErrorData::Os(..) => None, | |
| 534 | ErrorData::Simple(..) => None, | |
| 535 | ErrorData::SimpleMessage(..) => None, | |
| 536 | ErrorData::Custom(c) => c.error_ref().cause(), | |
| 537 | } | |
| 538 | } | |
| 539 | ||
| 540 | fn source(&self) -> Option<&(dyn error::Error + 'static)> { | |
| 541 | match self.repr.data() { | |
| 542 | ErrorData::Os(..) => None, | |
| 543 | ErrorData::Simple(..) => None, | |
| 544 | ErrorData::SimpleMessage(..) => None, | |
| 545 | ErrorData::Custom(c) => c.error_ref().source(), | |
| 546 | } | |
| 547 | } | |
| 548 | } | |
| 549 | ||
| 550 | fn _assert_error_is_sync_send() { | |
| 551 | fn _is_sync_send<T: Sync + Send>() {} | |
| 552 | _is_sync_send::<Error>(); | |
| 553 | } | |
| 554 | ||
| 555 | #[doc(hidden)] | |
| 556 | #[derive(Debug)] | |
| 557 | #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] | |
| 558 | pub struct OsFunctions { | |
| 559 | pub format_os_error: fn(_: RawOsError, _: &mut fmt::Formatter<'_>) -> fmt::Result, | |
| 560 | pub decode_error_kind: fn(_: RawOsError) -> ErrorKind, | |
| 561 | pub is_interrupted: fn(_: RawOsError) -> bool, | |
| 562 | } | |
| 563 | ||
| 564 | impl OsFunctions { | |
| 565 | const DEFAULT: &'static OsFunctions = &OsFunctions { | |
| 566 | format_os_error: |_, _| Ok(()), | |
| 567 | decode_error_kind: |_| ErrorKind::Uncategorized, | |
| 568 | is_interrupted: |_| false, | |
| 569 | }; | |
| 570 | } | |
| 571 | ||
| 572 | // As with `SimpleMessage`: `#[repr(align(4))]` here is just because | |
| 573 | // repr_bitpacked's encoding requires it. In practice it almost certainly be | |
| 574 | // already be this high or higher. | |
| 575 | #[doc(hidden)] | |
| 576 | #[repr(align(4))] | |
| 577 | #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] | |
| 578 | pub struct Custom { | |
| 579 | kind: ErrorKind, | |
| 580 | error: crate::ptr::NonNull<dyn error::Error + Send + Sync>, | |
| 581 | error_drop: unsafe fn(*mut (dyn error::Error + Send + Sync)), | |
| 582 | outer_drop: unsafe fn(*mut Self), | |
| 583 | } | |
| 584 | ||
| 585 | // SAFETY: All members of `Custom` are `Send` | |
| 586 | #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] | |
| 587 | unsafe impl Send for Custom {} | |
| 588 | ||
| 589 | // SAFETY: All members of `Custom` are `Sync` | |
| 590 | #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] | |
| 591 | unsafe impl Sync for Custom {} | |
| 592 | ||
| 593 | #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] | |
| 594 | impl fmt::Debug for Custom { | |
| 595 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
| 596 | f.debug_struct("Custom").field("kind", &self.kind).field("error", self.error_ref()).finish() | |
| 597 | } | |
| 598 | } | |
| 599 | ||
| 600 | #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] | |
| 601 | impl Drop for Custom { | |
| 602 | fn drop(&mut self) { | |
| 603 | // SAFETY: `Custom::from_raw` ensures this call is safe. | |
| 604 | unsafe { | |
| 605 | (self.error_drop)(self.error.as_ptr()); | |
| 606 | } | |
| 607 | } | |
| 608 | } | |
| 609 | ||
| 610 | impl Custom { | |
| 611 | /// # Safety | |
| 612 | /// | |
| 613 | /// * `error` must be valid for up to a static lifetime, and own its pointee. | |
| 614 | /// * `error_drop` must be safe to call for the pointer `error` exactly once. | |
| 615 | /// * `outer_drop` must be safe to call on a pointer to this instance of `Custom` | |
| 616 | /// if it were stored within a [`CustomOwner`]. | |
| 617 | #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] | |
| 618 | pub unsafe fn from_raw( | |
| 619 | kind: ErrorKind, | |
| 620 | error: crate::ptr::NonNull<dyn error::Error + Send + Sync>, | |
| 621 | error_drop: unsafe fn(*mut (dyn error::Error + Send + Sync)), | |
| 622 | outer_drop: unsafe fn(*mut Self), | |
| 623 | ) -> Custom { | |
| 624 | Custom { kind, error, error_drop, outer_drop } | |
| 625 | } | |
| 626 | ||
| 627 | #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] | |
| 628 | pub fn into_raw(self) -> crate::ptr::NonNull<dyn error::Error + Send + Sync> { | |
| 629 | let ptr = self.error; | |
| 630 | core::mem::forget(self); | |
| 631 | ptr | |
| 632 | } | |
| 633 | ||
| 634 | fn error_ref(&self) -> &(dyn error::Error + Send + Sync + 'static) { | |
| 635 | // SAFETY: | |
| 636 | // `from_raw` ensures `error` is a valid pointer up to a static lifetime | |
| 637 | // and is owned by `self` | |
| 638 | unsafe { self.error.as_ref() } | |
| 639 | } | |
| 640 | ||
| 641 | fn error_mut(&mut self) -> &mut (dyn error::Error + Send + Sync + 'static) { | |
| 642 | // SAFETY: | |
| 643 | // `from_raw` ensures `error` is a valid pointer up to a static lifetime | |
| 644 | // and is owned by `self` | |
| 645 | unsafe { self.error.as_mut() } | |
| 646 | } | |
| 647 | } | |
| 648 | ||
| 649 | #[derive(Debug)] | |
| 650 | #[repr(transparent)] | |
| 651 | #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] | |
| 652 | #[doc(hidden)] | |
| 653 | pub struct CustomOwner(crate::ptr::NonNull<Custom>); | |
| 654 | ||
| 655 | // SAFETY: Custom is `Send` | |
| 656 | #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] | |
| 657 | unsafe impl Send for CustomOwner {} | |
| 658 | ||
| 659 | // SAFETY: Custom is `Sync` | |
| 660 | #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] | |
| 661 | unsafe impl Sync for CustomOwner {} | |
| 662 | ||
| 663 | #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] | |
| 664 | impl Drop for CustomOwner { | |
| 665 | fn drop(&mut self) { | |
| 666 | // SAFETY: `CustomOwner::from_raw` ensures this call is safe. | |
| 667 | unsafe { | |
| 668 | (self.0.as_ref().outer_drop)(self.0.as_ptr()); | |
| 669 | } | |
| 670 | } | |
| 671 | } | |
| 672 | ||
| 673 | impl CustomOwner { | |
| 674 | /// # Safety | |
| 675 | /// | |
| 676 | /// * The `outer_drop` of the provided `custom` must be safe to call exactly once. | |
| 677 | #[doc(hidden)] | |
| 678 | #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] | |
| 679 | pub unsafe fn from_raw(custom: crate::ptr::NonNull<Custom>) -> CustomOwner { | |
| 680 | CustomOwner(custom) | |
| 681 | } | |
| 682 | ||
| 683 | #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] | |
| 684 | pub fn into_raw(self) -> crate::ptr::NonNull<Custom> { | |
| 685 | let ptr = self.0; | |
| 686 | core::mem::forget(self); | |
| 687 | ptr | |
| 688 | } | |
| 689 | ||
| 690 | #[allow(dead_code, reason = "only used for unpacked representation")] | |
| 691 | fn custom_ref(&self) -> &Custom { | |
| 692 | // SAFETY: | |
| 693 | // `from_raw` ensures `0` is a valid pointer up to a static lifetime | |
| 694 | // and is owned by `self` | |
| 695 | unsafe { self.0.as_ref() } | |
| 696 | } | |
| 697 | ||
| 698 | #[allow(dead_code, reason = "only used for unpacked representation")] | |
| 699 | fn custom_mut(&mut self) -> &mut Custom { | |
| 700 | // SAFETY: | |
| 701 | // `from_raw` ensures `0` is a valid pointer up to a static lifetime | |
| 702 | // and is owned by `self` | |
| 703 | unsafe { self.0.as_mut() } | |
| 704 | } | |
| 705 | } | |
| 4 | 706 | |
| 5 | 707 | /// The type of raw OS error codes. |
| 6 | 708 | /// |
| ... | ... | @@ -23,7 +725,7 @@ pub type RawOsError = cfg_select! { |
| 23 | 725 | /// |
| 24 | 726 | /// It is used with the [`io::Error`][error] type. |
| 25 | 727 | /// |
| 26 | /// [error]: ../../std/io/struct.Error.html | |
| 728 | /// [error]: Error | |
| 27 | 729 | /// |
| 28 | 730 | /// # Handling errors and matching on `ErrorKind` |
| 29 | 731 | /// |
| ... | ... | @@ -258,7 +960,7 @@ pub enum ErrorKind { |
| 258 | 960 | /// error kinds cannot be `match`ed on, and will only match a wildcard (`_`) pattern. |
| 259 | 961 | /// New [`ErrorKind`]s might be added in the future for some of those. |
| 260 | 962 | /// |
| 261 | /// [error]: ../../std/io/struct.Error.html | |
| 963 | /// [error]: Error | |
| 262 | 964 | #[stable(feature = "rust1", since = "1.0.0")] |
| 263 | 965 | Other, |
| 264 | 966 | |
| ... | ... | @@ -273,7 +975,7 @@ pub enum ErrorKind { |
| 273 | 975 | } |
| 274 | 976 | |
| 275 | 977 | impl ErrorKind { |
| 276 | pub(crate) const fn as_str(&self) -> &'static str { | |
| 978 | const fn as_str(&self) -> &'static str { | |
| 277 | 979 | use ErrorKind::*; |
| 278 | 980 | match *self { |
| 279 | 981 | // tidy-alphabetical-start |
| ... | ... | @@ -328,9 +1030,8 @@ impl ErrorKind { |
| 328 | 1030 | // unsafe, or to hard-code max ErrorKind or its size in a way the compiler |
| 329 | 1031 | // couldn't verify. |
| 330 | 1032 | #[inline] |
| 331 | #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] | |
| 332 | #[doc(hidden)] | |
| 333 | pub const fn from_prim(ek: u32) -> Option<Self> { | |
| 1033 | #[allow(dead_code, reason = "only used for packed representation")] | |
| 1034 | const fn from_prim(ek: u32) -> Option<Self> { | |
| 334 | 1035 | macro_rules! from_prim { |
| 335 | 1036 | ($prim:expr => $Enum:ident { $($Variant:ident),* $(,)? }) => {{ |
| 336 | 1037 | // Force a compile error if the list gets out of date. |
library/core/src/io/error/os_functions.rs created+30| ... | ... | @@ -0,0 +1,30 @@ |
| 1 | use super::{ErrorKind, OsFunctions, RawOsError}; | |
| 2 | use crate::fmt; | |
| 3 | ||
| 4 | /// # Safety | |
| 5 | /// | |
| 6 | /// The provided reference must point to data that is entirely constant; it must | |
| 7 | /// not be created during runtime. | |
| 8 | #[inline] | |
| 9 | pub(super) unsafe fn set_functions(f: &'static OsFunctions) { | |
| 10 | // FIXME: externally implementable items may allow for weak linkage, allowing | |
| 11 | // these methods to be overridden even when atomic pointers are not supported. | |
| 12 | } | |
| 13 | ||
| 14 | #[inline] | |
| 15 | pub(super) fn format_os_error(errno: RawOsError, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { | |
| 16 | let f = OsFunctions::DEFAULT; | |
| 17 | (f.format_os_error)(errno, fmt) | |
| 18 | } | |
| 19 | ||
| 20 | #[inline] | |
| 21 | pub(super) fn decode_error_kind(errno: RawOsError) -> ErrorKind { | |
| 22 | let f = OsFunctions::DEFAULT; | |
| 23 | (f.decode_error_kind)(errno) | |
| 24 | } | |
| 25 | ||
| 26 | #[inline] | |
| 27 | pub(super) fn is_interrupted(errno: RawOsError) -> bool { | |
| 28 | let f = OsFunctions::DEFAULT; | |
| 29 | (f.is_interrupted)(errno) | |
| 30 | } |
library/core/src/io/error/os_functions_atomic.rs created+61| ... | ... | @@ -0,0 +1,61 @@ |
| 1 | //! OS-dependent functions | |
| 2 | //! | |
| 3 | //! `Error` needs OS functionalities to work interpret raw OS errors, but | |
| 4 | //! we can't link to anythink here in `alloc`. Therefore, we restrict | |
| 5 | //! creation of `Error` from raw OS errors in `std`, and require providing | |
| 6 | //! a vtable of operations when creating one. | |
| 7 | ||
| 8 | // FIXME: replace this with externally implementable items once they are more stable | |
| 9 | ||
| 10 | use super::{ErrorKind, OsFunctions, RawOsError}; | |
| 11 | use crate::fmt; | |
| 12 | use crate::sync::atomic; | |
| 13 | ||
| 14 | /// These default functions are not reachable, but have them just to be safe. | |
| 15 | static OS_FUNCTIONS: atomic::AtomicPtr<OsFunctions> = | |
| 16 | atomic::AtomicPtr::new(OsFunctions::DEFAULT as *const _ as *mut _); | |
| 17 | ||
| 18 | fn get_os_functions() -> &'static OsFunctions { | |
| 19 | // SAFETY: | |
| 20 | // * `OS_FUNCTIONS` is initially a pointer to `OsFunctions::DEFAULT`, which is valid for a static lifetime. | |
| 21 | // * `OS_FUNCTIONS` can only be changed by `set_functions`, which only accepts `&'static OsFunctions`. | |
| 22 | // * Therefore, `OS_FUNCTIONS` must always contain a valid non-null pointer with a static lifetime. | |
| 23 | // * `Relaxed` ordering is sufficient as the only way to write to `OS_FUNCTIONS` is through | |
| 24 | // `set_functions`, which has as a safety precondition that any value passed in must | |
| 25 | // be constant and not created during runtime. | |
| 26 | unsafe { &*OS_FUNCTIONS.load(atomic::Ordering::Relaxed) } | |
| 27 | } | |
| 28 | ||
| 29 | /// # Safety | |
| 30 | /// | |
| 31 | /// The provided reference must point to data that is entirely constant; it must | |
| 32 | /// not be created during runtime. | |
| 33 | #[inline] | |
| 34 | pub(super) unsafe fn set_functions(f: &'static OsFunctions) { | |
| 35 | #[cold] | |
| 36 | fn set_functions_inner(f: &'static OsFunctions) { | |
| 37 | OS_FUNCTIONS.store(f as *const _ as *mut _, atomic::Ordering::Relaxed); | |
| 38 | } | |
| 39 | ||
| 40 | if OS_FUNCTIONS.load(atomic::Ordering::Relaxed) != f as *const _ as *mut _ { | |
| 41 | set_functions_inner(f); | |
| 42 | } | |
| 43 | } | |
| 44 | ||
| 45 | #[inline] | |
| 46 | pub(super) fn format_os_error(errno: RawOsError, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { | |
| 47 | let f = get_os_functions(); | |
| 48 | (f.format_os_error)(errno, fmt) | |
| 49 | } | |
| 50 | ||
| 51 | #[inline] | |
| 52 | pub(super) fn decode_error_kind(errno: RawOsError) -> ErrorKind { | |
| 53 | let f = get_os_functions(); | |
| 54 | (f.decode_error_kind)(errno) | |
| 55 | } | |
| 56 | ||
| 57 | #[inline] | |
| 58 | pub(super) fn is_interrupted(errno: RawOsError) -> bool { | |
| 59 | let f = get_os_functions(); | |
| 60 | (f.is_interrupted)(errno) | |
| 61 | } |
library/core/src/io/error/repr_bitpacked.rs created+351| ... | ... | @@ -0,0 +1,351 @@ |
| 1 | //! This is a densely packed error representation which is used on targets with | |
| 2 | //! 64-bit pointers. | |
| 3 | //! | |
| 4 | //! (Note that `bitpacked` vs `unpacked` here has no relationship to | |
| 5 | //! `#[repr(packed)]`, it just refers to attempting to use any available bits in | |
| 6 | //! a more clever manner than `rustc`'s default layout algorithm would). | |
| 7 | //! | |
| 8 | //! Conceptually, it stores the same data as the "unpacked" equivalent we use on | |
| 9 | //! other targets. Specifically, you can imagine it as an optimized version of | |
| 10 | //! the following enum (which is roughly equivalent to what's stored by | |
| 11 | //! `repr_unpacked::Repr`, e.g. `super::ErrorData<Box<Custom>>`): | |
| 12 | //! | |
| 13 | //! ```ignore (exposition-only) | |
| 14 | //! enum ErrorData { | |
| 15 | //! Os(i32), | |
| 16 | //! Simple(ErrorKind), | |
| 17 | //! SimpleMessage(&'static SimpleMessage), | |
| 18 | //! Custom(Box<Custom>), | |
| 19 | //! } | |
| 20 | //! ``` | |
| 21 | //! | |
| 22 | //! However, it packs this data into a 64bit non-zero value. | |
| 23 | //! | |
| 24 | //! This optimization not only allows `io::Error` to occupy a single pointer, | |
| 25 | //! but improves `io::Result` as well, especially for situations like | |
| 26 | //! `io::Result<()>` (which is now 64 bits) or `io::Result<u64>` (which is now | |
| 27 | //! 128 bits), which are quite common. | |
| 28 | //! | |
| 29 | //! # Layout | |
| 30 | //! Tagged values are 64 bits, with the 2 least significant bits used for the | |
| 31 | //! tag. This means there are 4 "variants": | |
| 32 | //! | |
| 33 | //! - **Tag 0b00**: The first variant is equivalent to | |
| 34 | //! `ErrorData::SimpleMessage`, and holds a `&'static SimpleMessage` directly. | |
| 35 | //! | |
| 36 | //! `SimpleMessage` has an alignment >= 4 (which is requested with | |
| 37 | //! `#[repr(align)]` and checked statically at the bottom of this file), which | |
| 38 | //! means every `&'static SimpleMessage` should have the both tag bits as 0, | |
| 39 | //! meaning its tagged and untagged representation are equivalent. | |
| 40 | //! | |
| 41 | //! This means we can skip tagging it, which is necessary as this variant can | |
| 42 | //! be constructed from a `const fn`, which probably cannot tag pointers (or | |
| 43 | //! at least it would be difficult). | |
| 44 | //! | |
| 45 | //! - **Tag 0b01**: The other pointer variant holds the data for | |
| 46 | //! `ErrorData::Custom` and the remaining 62 bits are used to store a | |
| 47 | //! `Box<Custom>`. `Custom` also has alignment >= 4, so the bottom two bits | |
| 48 | //! are free to use for the tag. | |
| 49 | //! | |
| 50 | //! The only important thing to note is that `ptr::wrapping_add` and | |
| 51 | //! `ptr::wrapping_sub` are used to tag the pointer, rather than bitwise | |
| 52 | //! operations. This should preserve the pointer's provenance, which would | |
| 53 | //! otherwise be lost. | |
| 54 | //! | |
| 55 | //! - **Tag 0b10**: Holds the data for `ErrorData::Os(i32)`. We store the `i32` | |
| 56 | //! in the pointer's most significant 32 bits, and don't use the bits `2..32` | |
| 57 | //! for anything. Using the top 32 bits is just to let us easily recover the | |
| 58 | //! `i32` code with the correct sign. | |
| 59 | //! | |
| 60 | //! - **Tag 0b11**: Holds the data for `ErrorData::Simple(ErrorKind)`. This | |
| 61 | //! stores the `ErrorKind` in the top 32 bits as well, although it doesn't | |
| 62 | //! occupy nearly that many. Most of the bits are unused here, but it's not | |
| 63 | //! like we need them for anything else yet. | |
| 64 | //! | |
| 65 | //! # Use of `NonNull<()>` | |
| 66 | //! | |
| 67 | //! Everything is stored in a `NonNull<()>`, which is odd, but actually serves a | |
| 68 | //! purpose. | |
| 69 | //! | |
| 70 | //! Conceptually you might think of this more like: | |
| 71 | //! | |
| 72 | //! ```ignore (exposition-only) | |
| 73 | //! union Repr { | |
| 74 | //! // holds integer (Simple/Os) variants, and | |
| 75 | //! // provides access to the tag bits. | |
| 76 | //! bits: NonZero<u64>, | |
| 77 | //! // Tag is 0, so this is stored untagged. | |
| 78 | //! msg: &'static SimpleMessage, | |
| 79 | //! // Tagged (offset) `Box<Custom>` pointer. | |
| 80 | //! tagged_custom: NonNull<()>, | |
| 81 | //! } | |
| 82 | //! ``` | |
| 83 | //! | |
| 84 | //! But there are a few problems with this: | |
| 85 | //! | |
| 86 | //! 1. Union access is equivalent to a transmute, so this representation would | |
| 87 | //! require we transmute between integers and pointers in at least one | |
| 88 | //! direction, which may be UB (and even if not, it is likely harder for a | |
| 89 | //! compiler to reason about than explicit ptr->int operations). | |
| 90 | //! | |
| 91 | //! 2. Even if all fields of a union have a niche, the union itself doesn't, | |
| 92 | //! although this may change in the future. This would make things like | |
| 93 | //! `io::Result<()>` and `io::Result<usize>` larger, which defeats part of | |
| 94 | //! the motivation of this bitpacking. | |
| 95 | //! | |
| 96 | //! Storing everything in a `NonZero<usize>` (or some other integer) would be a | |
| 97 | //! bit more traditional for pointer tagging, but it would lose provenance | |
| 98 | //! information, couldn't be constructed from a `const fn`, and would probably | |
| 99 | //! run into other issues as well. | |
| 100 | //! | |
| 101 | //! The `NonNull<()>` seems like the only alternative, even if it's fairly odd | |
| 102 | //! to use a pointer type to store something that may hold an integer, some of | |
| 103 | //! the time. | |
| 104 | ||
| 105 | use core::marker::PhantomData; | |
| 106 | use core::num::NonZeroUsize; | |
| 107 | use core::ptr::NonNull; | |
| 108 | ||
| 109 | use super::{Custom, CustomOwner, ErrorData, ErrorKind, RawOsError, SimpleMessage}; | |
| 110 | ||
| 111 | // The 2 least-significant bits are used as tag. | |
| 112 | const TAG_MASK: usize = 0b11; | |
| 113 | const TAG_SIMPLE_MESSAGE: usize = 0b00; | |
| 114 | const TAG_CUSTOM: usize = 0b01; | |
| 115 | const TAG_OS: usize = 0b10; | |
| 116 | const TAG_SIMPLE: usize = 0b11; | |
| 117 | ||
| 118 | /// The internal representation. | |
| 119 | /// | |
| 120 | /// See the module docs for more, this is just a way to hack in a check that we | |
| 121 | /// indeed are not unwind-safe. | |
| 122 | /// | |
| 123 | /// ```compile_fail,E0277 | |
| 124 | /// fn is_unwind_safe<T: core::panic::UnwindSafe>() {} | |
| 125 | /// is_unwind_safe::<std::io::Error>(); | |
| 126 | /// ``` | |
| 127 | #[repr(transparent)] | |
| 128 | #[rustc_insignificant_dtor] | |
| 129 | pub(super) struct Repr(NonNull<()>, PhantomData<ErrorData<CustomOwner>>); | |
| 130 | ||
| 131 | // All the types `Repr` stores internally are Send + Sync, and so is it. | |
| 132 | unsafe impl Send for Repr {} | |
| 133 | unsafe impl Sync for Repr {} | |
| 134 | ||
| 135 | impl Repr { | |
| 136 | pub(super) fn new_custom(b: CustomOwner) -> Self { | |
| 137 | let p = b.into_raw().as_ptr().cast::<u8>(); | |
| 138 | // Should only be possible if an allocator handed out a pointer with | |
| 139 | // wrong alignment. | |
| 140 | debug_assert_eq!(p.addr() & TAG_MASK, 0); | |
| 141 | // Note: We know `TAG_CUSTOM <= size_of::<Custom>()` (static_assert at | |
| 142 | // end of file), and both the start and end of the expression must be | |
| 143 | // valid without address space wraparound due to `Box`'s semantics. | |
| 144 | // | |
| 145 | // This means it would be correct to implement this using `ptr::add` | |
| 146 | // (rather than `ptr::wrapping_add`), but it's unclear this would give | |
| 147 | // any benefit, so we just use `wrapping_add` instead. | |
| 148 | let tagged = p.wrapping_add(TAG_CUSTOM).cast::<()>(); | |
| 149 | // SAFETY: | |
| 150 | // `TAG_CUSTOM + p` is the same as `TAG_CUSTOM | p`, | |
| 151 | // because `p`'s alignment means it isn't allowed to have any of the | |
| 152 | // `TAG_BITS` set (you can verify that addition and bitwise-or are the | |
| 153 | // same when the operands have no bits in common using a truth table). | |
| 154 | // | |
| 155 | // Then, `TAG_CUSTOM | p` is not zero, as that would require | |
| 156 | // `TAG_CUSTOM` and `p` both be zero, and neither is (as `p` came from a | |
| 157 | // box, and `TAG_CUSTOM` just... isn't zero -- it's `0b01`). Therefore, | |
| 158 | // `TAG_CUSTOM + p` isn't zero and so `tagged` can't be, and the | |
| 159 | // `new_unchecked` is safe. | |
| 160 | let ptr = unsafe { NonNull::new_unchecked(tagged) }; | |
| 161 | let res = Self(ptr, PhantomData); | |
| 162 | // quickly smoke-check we encoded the right thing (This generally will | |
| 163 | // only run in std's tests, unless the user uses -Zbuild-std) | |
| 164 | debug_assert!(matches!(res.data(), ErrorData::Custom(_)), "repr(custom) encoding failed"); | |
| 165 | res | |
| 166 | } | |
| 167 | ||
| 168 | #[inline] | |
| 169 | pub(super) fn new_os(code: RawOsError) -> Self { | |
| 170 | let utagged = ((code as usize) << 32) | TAG_OS; | |
| 171 | // SAFETY: `TAG_OS` is not zero, so the result of the `|` is not 0. | |
| 172 | let utagged = unsafe { NonZeroUsize::new_unchecked(utagged) }; | |
| 173 | let res = Self(NonNull::without_provenance(utagged), PhantomData); | |
| 174 | // quickly smoke-check we encoded the right thing (This generally will | |
| 175 | // only run in std's tests, unless the user uses -Zbuild-std) | |
| 176 | debug_assert!( | |
| 177 | matches!(res.data(), ErrorData::Os(c) if c == code), | |
| 178 | "repr(os) encoding failed for {code}" | |
| 179 | ); | |
| 180 | res | |
| 181 | } | |
| 182 | ||
| 183 | #[inline] | |
| 184 | pub(super) fn new_simple(kind: ErrorKind) -> Self { | |
| 185 | let utagged = ((kind as usize) << 32) | TAG_SIMPLE; | |
| 186 | // SAFETY: `TAG_SIMPLE` is not zero, so the result of the `|` is not 0. | |
| 187 | let utagged = unsafe { NonZeroUsize::new_unchecked(utagged) }; | |
| 188 | let res = Self(NonNull::without_provenance(utagged), PhantomData); | |
| 189 | // quickly smoke-check we encoded the right thing (This generally will | |
| 190 | // only run in std's tests, unless the user uses -Zbuild-std) | |
| 191 | debug_assert!( | |
| 192 | matches!(res.data(), ErrorData::Simple(k) if k == kind), | |
| 193 | "repr(simple) encoding failed {:?}", | |
| 194 | kind, | |
| 195 | ); | |
| 196 | res | |
| 197 | } | |
| 198 | ||
| 199 | #[inline] | |
| 200 | pub(super) const fn new_simple_message(m: &'static SimpleMessage) -> Self { | |
| 201 | // SAFETY: References are never null. | |
| 202 | let ptr = unsafe { NonNull::new_unchecked(m as *const _ as *mut ()) }; | |
| 203 | Self(ptr, PhantomData) | |
| 204 | } | |
| 205 | ||
| 206 | #[inline] | |
| 207 | pub(super) fn data(&self) -> ErrorData<&Custom> { | |
| 208 | // SAFETY: We're a Repr, decode_repr is fine. | |
| 209 | unsafe { decode_repr(self.0, |c| &*c) } | |
| 210 | } | |
| 211 | ||
| 212 | #[inline] | |
| 213 | pub(super) fn data_mut(&mut self) -> ErrorData<&mut Custom> { | |
| 214 | // SAFETY: We're a Repr, decode_repr is fine. | |
| 215 | unsafe { decode_repr(self.0, |c| &mut *c) } | |
| 216 | } | |
| 217 | ||
| 218 | #[inline] | |
| 219 | pub(super) fn into_data(self) -> ErrorData<CustomOwner> { | |
| 220 | let this = core::mem::ManuallyDrop::new(self); | |
| 221 | // SAFETY: We're a Repr, decode_repr is fine. The `Box::from_raw` is | |
| 222 | // safe because we prevent double-drop using `ManuallyDrop`. | |
| 223 | unsafe { | |
| 224 | decode_repr(this.0, |p| CustomOwner::from_raw(core::ptr::NonNull::new_unchecked(p))) | |
| 225 | } | |
| 226 | } | |
| 227 | } | |
| 228 | ||
| 229 | impl Drop for Repr { | |
| 230 | #[inline] | |
| 231 | fn drop(&mut self) { | |
| 232 | // SAFETY: We're a Repr, decode_repr is fine. The `Box::from_raw` is | |
| 233 | // safe because we're being dropped. | |
| 234 | unsafe { | |
| 235 | let _ = decode_repr(self.0, |p| { | |
| 236 | CustomOwner::from_raw(core::ptr::NonNull::new_unchecked(p)) | |
| 237 | }); | |
| 238 | } | |
| 239 | } | |
| 240 | } | |
| 241 | ||
| 242 | // Shared helper to decode a `Repr`'s internal pointer into an ErrorData. | |
| 243 | // | |
| 244 | // Safety: `ptr`'s bits should be encoded as described in the document at the | |
| 245 | // top (it should `some_repr.0`) | |
| 246 | #[inline] | |
| 247 | unsafe fn decode_repr<C, F>(ptr: NonNull<()>, make_custom: F) -> ErrorData<C> | |
| 248 | where | |
| 249 | F: FnOnce(*mut Custom) -> C, | |
| 250 | { | |
| 251 | let bits = ptr.as_ptr().addr(); | |
| 252 | match bits & TAG_MASK { | |
| 253 | TAG_OS => { | |
| 254 | let code = ((bits as i64) >> 32) as RawOsError; | |
| 255 | ErrorData::Os(code) | |
| 256 | } | |
| 257 | TAG_SIMPLE => { | |
| 258 | let kind_bits = (bits >> 32) as u32; | |
| 259 | let kind = ErrorKind::from_prim(kind_bits).unwrap_or_else(|| { | |
| 260 | debug_assert!(false, "Invalid io::error::Repr bits: `Repr({:#018x})`", bits); | |
| 261 | // SAFETY: This means the `ptr` passed in was not valid, which violates | |
| 262 | // the unsafe contract of `decode_repr`. | |
| 263 | // | |
| 264 | // Using this rather than unwrap meaningfully improves the code | |
| 265 | // for callers which only care about one variant (usually | |
| 266 | // `Custom`) | |
| 267 | unsafe { core::hint::unreachable_unchecked() }; | |
| 268 | }); | |
| 269 | ErrorData::Simple(kind) | |
| 270 | } | |
| 271 | TAG_SIMPLE_MESSAGE => { | |
| 272 | // SAFETY: per tag | |
| 273 | unsafe { ErrorData::SimpleMessage(&*ptr.cast::<SimpleMessage>().as_ptr()) } | |
| 274 | } | |
| 275 | TAG_CUSTOM => { | |
| 276 | // It would be correct for us to use `ptr::byte_sub` here (see the | |
| 277 | // comment above the `wrapping_add` call in `new_custom` for why), | |
| 278 | // but it isn't clear that it makes a difference, so we don't. | |
| 279 | let custom = ptr.as_ptr().wrapping_byte_sub(TAG_CUSTOM).cast::<Custom>(); | |
| 280 | ErrorData::Custom(make_custom(custom)) | |
| 281 | } | |
| 282 | _ => { | |
| 283 | // Can't happen, and compiler can tell | |
| 284 | unreachable!(); | |
| 285 | } | |
| 286 | } | |
| 287 | } | |
| 288 | ||
| 289 | // Some static checking to alert us if a change breaks any of the assumptions | |
| 290 | // that our encoding relies on for correctness and soundness. (Some of these are | |
| 291 | // a bit overly thorough/cautious, admittedly) | |
| 292 | // | |
| 293 | // If any of these are hit on a platform that std supports, we should likely | |
| 294 | // just use `repr_unpacked.rs` there instead (unless the fix is easy). | |
| 295 | macro_rules! static_assert { | |
| 296 | ($condition:expr) => { | |
| 297 | const _: () = assert!($condition); | |
| 298 | }; | |
| 299 | (@usize_eq: $lhs:expr, $rhs:expr) => { | |
| 300 | const _: [(); $lhs] = [(); $rhs]; | |
| 301 | }; | |
| 302 | } | |
| 303 | ||
| 304 | // The bitpacking we use requires pointers be exactly 64 bits. | |
| 305 | static_assert!(@usize_eq: size_of::<NonNull<()>>(), 8); | |
| 306 | ||
| 307 | // We also require pointers and usize be the same size. | |
| 308 | static_assert!(@usize_eq: size_of::<NonNull<()>>(), size_of::<usize>()); | |
| 309 | ||
| 310 | // `Custom` and `SimpleMessage` need to be thin pointers. | |
| 311 | static_assert!(@usize_eq: size_of::<&'static SimpleMessage>(), 8); | |
| 312 | static_assert!(@usize_eq: size_of::<CustomOwner>(), 8); | |
| 313 | ||
| 314 | static_assert!((TAG_MASK + 1).is_power_of_two()); | |
| 315 | // And they must have sufficient alignment. | |
| 316 | static_assert!(align_of::<SimpleMessage>() >= TAG_MASK + 1); | |
| 317 | static_assert!(align_of::<Custom>() >= TAG_MASK + 1); | |
| 318 | ||
| 319 | static_assert!(@usize_eq: TAG_MASK & TAG_SIMPLE_MESSAGE, TAG_SIMPLE_MESSAGE); | |
| 320 | static_assert!(@usize_eq: TAG_MASK & TAG_CUSTOM, TAG_CUSTOM); | |
| 321 | static_assert!(@usize_eq: TAG_MASK & TAG_OS, TAG_OS); | |
| 322 | static_assert!(@usize_eq: TAG_MASK & TAG_SIMPLE, TAG_SIMPLE); | |
| 323 | ||
| 324 | // This is obviously true (`TAG_CUSTOM` is `0b01`), but in `Repr::new_custom` we | |
| 325 | // offset a pointer by this value, and expect it to both be within the same | |
| 326 | // object, and to not wrap around the address space. See the comment in that | |
| 327 | // function for further details. | |
| 328 | // | |
| 329 | // Actually, at the moment we use `ptr::wrapping_add`, not `ptr::add`, so this | |
| 330 | // check isn't needed for that one, although the assertion that we don't | |
| 331 | // actually wrap around in that wrapping_add does simplify the safety reasoning | |
| 332 | // elsewhere considerably. | |
| 333 | static_assert!(size_of::<Custom>() >= TAG_CUSTOM); | |
| 334 | ||
| 335 | // These two store a payload which is allowed to be zero, so they must be | |
| 336 | // non-zero to preserve the `NonNull`'s range invariant. | |
| 337 | static_assert!(TAG_OS != 0); | |
| 338 | static_assert!(TAG_SIMPLE != 0); | |
| 339 | // We can't tag `SimpleMessage`s, the tag must be 0. | |
| 340 | static_assert!(@usize_eq: TAG_SIMPLE_MESSAGE, 0); | |
| 341 | ||
| 342 | // Check that the point of all of this still holds. | |
| 343 | // | |
| 344 | // We'd check against `io::Error`, but *technically* it's allowed to vary, | |
| 345 | // as it's not `#[repr(transparent)]`/`#[repr(C)]`. We could add that, but | |
| 346 | // the `#[repr()]` would show up in rustdoc, which might be seen as a stable | |
| 347 | // commitment. | |
| 348 | static_assert!(@usize_eq: size_of::<Repr>(), 8); | |
| 349 | static_assert!(@usize_eq: size_of::<Option<Repr>>(), 8); | |
| 350 | static_assert!(@usize_eq: size_of::<Result<(), Repr>>(), 8); | |
| 351 | static_assert!(@usize_eq: size_of::<Result<usize, Repr>>(), 16); |
library/core/src/io/error/repr_unpacked.rs created+50| ... | ... | @@ -0,0 +1,50 @@ |
| 1 | //! This is a fairly simple unpacked error representation that's used on | |
| 2 | //! non-64bit targets, where the packed 64 bit representation wouldn't work, and | |
| 3 | //! would have no benefit. | |
| 4 | ||
| 5 | use super::{Custom, CustomOwner, ErrorData, ErrorKind, RawOsError, SimpleMessage}; | |
| 6 | ||
| 7 | type Inner = ErrorData<CustomOwner>; | |
| 8 | ||
| 9 | pub(super) struct Repr(Inner); | |
| 10 | ||
| 11 | impl Repr { | |
| 12 | #[inline] | |
| 13 | pub(super) fn new_custom(b: CustomOwner) -> Self { | |
| 14 | Self(Inner::Custom(b)) | |
| 15 | } | |
| 16 | #[inline] | |
| 17 | pub(super) fn new_os(code: RawOsError) -> Self { | |
| 18 | Self(Inner::Os(code)) | |
| 19 | } | |
| 20 | #[inline] | |
| 21 | pub(super) fn new_simple(kind: ErrorKind) -> Self { | |
| 22 | Self(Inner::Simple(kind)) | |
| 23 | } | |
| 24 | #[inline] | |
| 25 | pub(super) const fn new_simple_message(m: &'static SimpleMessage) -> Self { | |
| 26 | Self(Inner::SimpleMessage(m)) | |
| 27 | } | |
| 28 | #[inline] | |
| 29 | pub(super) fn into_data(self) -> ErrorData<CustomOwner> { | |
| 30 | self.0 | |
| 31 | } | |
| 32 | #[inline] | |
| 33 | pub(super) fn data(&self) -> ErrorData<&Custom> { | |
| 34 | match &self.0 { | |
| 35 | Inner::Os(c) => ErrorData::Os(*c), | |
| 36 | Inner::Simple(k) => ErrorData::Simple(*k), | |
| 37 | Inner::SimpleMessage(m) => ErrorData::SimpleMessage(*m), | |
| 38 | Inner::Custom(m) => ErrorData::Custom(m.custom_ref()), | |
| 39 | } | |
| 40 | } | |
| 41 | #[inline] | |
| 42 | pub(super) fn data_mut(&mut self) -> ErrorData<&mut Custom> { | |
| 43 | match &mut self.0 { | |
| 44 | Inner::Os(c) => ErrorData::Os(*c), | |
| 45 | Inner::Simple(k) => ErrorData::Simple(*k), | |
| 46 | Inner::SimpleMessage(m) => ErrorData::SimpleMessage(*m), | |
| 47 | Inner::Custom(m) => ErrorData::Custom(m.custom_mut()), | |
| 48 | } | |
| 49 | } | |
| 50 | } |
library/core/src/io/mod.rs+14-8| ... | ... | @@ -8,16 +8,22 @@ mod util; |
| 8 | 8 | |
| 9 | 9 | #[unstable(feature = "core_io_borrowed_buf", issue = "117693")] |
| 10 | 10 | pub use self::borrowed_buf::{BorrowedBuf, BorrowedCursor}; |
| 11 | #[unstable(feature = "core_io", issue = "154046")] | |
| 12 | pub use self::cursor::Cursor; | |
| 13 | #[unstable(feature = "core_io", issue = "154046")] | |
| 14 | pub use self::error::ErrorKind; | |
| 15 | 11 | #[unstable(feature = "raw_os_error_ty", issue = "107792")] |
| 16 | 12 | pub use self::error::RawOsError; |
| 13 | #[unstable(feature = "io_const_error_internals", issue = "none")] | |
| 14 | pub use self::error::SimpleMessage; | |
| 15 | #[unstable(feature = "io_const_error", issue = "133448")] | |
| 16 | pub use self::error::const_error; | |
| 17 | 17 | #[unstable(feature = "core_io", issue = "154046")] |
| 18 | pub use self::io_slice::{IoSlice, IoSliceMut}; | |
| 19 | #[unstable(feature = "core_io", issue = "154046")] | |
| 20 | pub use self::util::{Chain, Empty, Repeat, Sink, Take, empty, repeat, sink}; | |
| 18 | pub use self::{ | |
| 19 | cursor::Cursor, | |
| 20 | error::{Error, ErrorKind, Result}, | |
| 21 | io_slice::{IoSlice, IoSliceMut}, | |
| 22 | util::{Chain, Empty, Repeat, Sink, Take, empty, repeat, sink}, | |
| 23 | }; | |
| 21 | 24 | #[doc(hidden)] |
| 22 | 25 | #[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")] |
| 23 | pub use self::util::{chain, take}; | |
| 26 | pub use self::{ | |
| 27 | error::{Custom, CustomOwner, OsFunctions}, | |
| 28 | util::{chain, take}, | |
| 29 | }; |
library/core/src/lib.rs+1| ... | ... | @@ -96,6 +96,7 @@ |
| 96 | 96 | #![feature(core_intrinsics)] |
| 97 | 97 | #![feature(coverage_attribute)] |
| 98 | 98 | #![feature(disjoint_bitor)] |
| 99 | #![feature(io_const_error)] | |
| 99 | 100 | #![feature(offset_of_enum)] |
| 100 | 101 | #![feature(panic_internals)] |
| 101 | 102 | #![feature(pattern_type_macro)] |
library/std/src/io/error.rs+23-699| ... | ... | @@ -1,310 +1,20 @@ |
| 1 | 1 | #[cfg(test)] |
| 2 | 2 | mod tests; |
| 3 | 3 | |
| 4 | #[stable(feature = "rust1", since = "1.0.0")] | |
| 5 | pub use core::io::ErrorKind; | |
| 6 | #[unstable(feature = "raw_os_error_ty", issue = "107792")] | |
| 7 | pub use core::io::RawOsError; | |
| 8 | ||
| 9 | // On 64-bit platforms, `io::Error` may use a bit-packed representation to | |
| 10 | // reduce size. However, this representation assumes that error codes are | |
| 11 | // always 32-bit wide. | |
| 12 | // | |
| 13 | // This assumption is invalid on 64-bit UEFI, where error codes are 64-bit. | |
| 14 | // Therefore, the packed representation is explicitly disabled for UEFI | |
| 15 | // targets, and the unpacked representation must be used instead. | |
| 16 | #[cfg(all(target_pointer_width = "64", not(target_os = "uefi")))] | |
| 17 | mod repr_bitpacked; | |
| 18 | #[cfg(all(target_pointer_width = "64", not(target_os = "uefi")))] | |
| 19 | use repr_bitpacked::Repr; | |
| 20 | ||
| 21 | #[cfg(any(not(target_pointer_width = "64"), target_os = "uefi"))] | |
| 22 | mod repr_unpacked; | |
| 23 | #[cfg(any(not(target_pointer_width = "64"), target_os = "uefi"))] | |
| 24 | use repr_unpacked::Repr; | |
| 25 | ||
| 26 | use crate::{error, fmt, result, sys}; | |
| 27 | ||
| 28 | /// A specialized [`Result`] type for I/O operations. | |
| 29 | /// | |
| 30 | /// This type is broadly used across [`std::io`] for any operation which may | |
| 31 | /// produce an error. | |
| 32 | /// | |
| 33 | /// This type alias is generally used to avoid writing out [`io::Error`] directly and | |
| 34 | /// is otherwise a direct mapping to [`Result`]. | |
| 35 | /// | |
| 36 | /// While usual Rust style is to import types directly, aliases of [`Result`] | |
| 37 | /// often are not, to make it easier to distinguish between them. [`Result`] is | |
| 38 | /// generally assumed to be [`std::result::Result`][`Result`], and so users of this alias | |
| 39 | /// will generally use `io::Result` instead of shadowing the [prelude]'s import | |
| 40 | /// of [`std::result::Result`][`Result`]. | |
| 41 | /// | |
| 42 | /// [`std::io`]: crate::io | |
| 43 | /// [`io::Error`]: Error | |
| 44 | /// [`Result`]: crate::result::Result | |
| 45 | /// [prelude]: crate::prelude | |
| 46 | /// | |
| 47 | /// # Examples | |
| 48 | /// | |
| 49 | /// A convenience function that bubbles an `io::Result` to its caller: | |
| 50 | /// | |
| 51 | /// ``` | |
| 52 | /// use std::io; | |
| 53 | /// | |
| 54 | /// fn get_string() -> io::Result<String> { | |
| 55 | /// let mut buffer = String::new(); | |
| 56 | /// | |
| 57 | /// io::stdin().read_line(&mut buffer)?; | |
| 58 | /// | |
| 59 | /// Ok(buffer) | |
| 60 | /// } | |
| 61 | /// ``` | |
| 62 | #[stable(feature = "rust1", since = "1.0.0")] | |
| 63 | #[doc(search_unbox)] | |
| 64 | pub type Result<T> = result::Result<T, Error>; | |
| 65 | ||
| 66 | /// The error type for I/O operations of the [`Read`], [`Write`], [`Seek`], and | |
| 67 | /// associated traits. | |
| 68 | /// | |
| 69 | /// Errors mostly originate from the underlying OS, but custom instances of | |
| 70 | /// `Error` can be created with crafted error messages and a particular value of | |
| 71 | /// [`ErrorKind`]. | |
| 72 | /// | |
| 73 | /// [`Read`]: crate::io::Read | |
| 74 | /// [`Write`]: crate::io::Write | |
| 75 | /// [`Seek`]: crate::io::Seek | |
| 76 | #[stable(feature = "rust1", since = "1.0.0")] | |
| 77 | pub struct Error { | |
| 78 | repr: Repr, | |
| 79 | } | |
| 80 | ||
| 81 | #[stable(feature = "rust1", since = "1.0.0")] | |
| 82 | impl fmt::Debug for Error { | |
| 83 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
| 84 | fmt::Debug::fmt(&self.repr, f) | |
| 85 | } | |
| 86 | } | |
| 87 | ||
| 88 | /// Common errors constants for use in std | |
| 89 | #[allow(dead_code)] | |
| 90 | impl Error { | |
| 91 | pub(crate) const INVALID_UTF8: Self = | |
| 92 | const_error!(ErrorKind::InvalidData, "stream did not contain valid UTF-8"); | |
| 93 | ||
| 94 | pub(crate) const READ_EXACT_EOF: Self = | |
| 95 | const_error!(ErrorKind::UnexpectedEof, "failed to fill whole buffer"); | |
| 96 | ||
| 97 | pub(crate) const UNKNOWN_THREAD_COUNT: Self = const_error!( | |
| 98 | ErrorKind::NotFound, | |
| 99 | "the number of hardware threads is not known for the target platform", | |
| 100 | ); | |
| 101 | ||
| 102 | pub(crate) const UNSUPPORTED_PLATFORM: Self = | |
| 103 | const_error!(ErrorKind::Unsupported, "operation not supported on this platform"); | |
| 104 | ||
| 105 | pub(crate) const WRITE_ALL_EOF: Self = | |
| 106 | const_error!(ErrorKind::WriteZero, "failed to write whole buffer"); | |
| 107 | ||
| 108 | pub(crate) const ZERO_TIMEOUT: Self = | |
| 109 | const_error!(ErrorKind::InvalidInput, "cannot set a 0 duration timeout"); | |
| 110 | ||
| 111 | pub(crate) const NO_ADDRESSES: Self = | |
| 112 | const_error!(ErrorKind::InvalidInput, "could not resolve to any addresses"); | |
| 113 | } | |
| 114 | ||
| 115 | #[stable(feature = "rust1", since = "1.0.0")] | |
| 116 | impl From<alloc::ffi::NulError> for Error { | |
| 117 | /// Converts a [`alloc::ffi::NulError`] into a [`Error`]. | |
| 118 | fn from(_: alloc::ffi::NulError) -> Error { | |
| 119 | const_error!(ErrorKind::InvalidInput, "data provided contains a nul byte") | |
| 120 | } | |
| 121 | } | |
| 122 | ||
| 123 | #[stable(feature = "io_error_from_try_reserve", since = "1.78.0")] | |
| 124 | impl From<alloc::collections::TryReserveError> for Error { | |
| 125 | /// Converts `TryReserveError` to an error with [`ErrorKind::OutOfMemory`]. | |
| 126 | /// | |
| 127 | /// `TryReserveError` won't be available as the error `source()`, | |
| 128 | /// but this may change in the future. | |
| 129 | fn from(_: alloc::collections::TryReserveError) -> Error { | |
| 130 | // ErrorData::Custom allocates, which isn't great for handling OOM errors. | |
| 131 | ErrorKind::OutOfMemory.into() | |
| 132 | } | |
| 133 | } | |
| 134 | ||
| 135 | // Only derive debug in tests, to make sure it | |
| 136 | // doesn't accidentally get printed. | |
| 137 | #[cfg_attr(test, derive(Debug))] | |
| 138 | enum ErrorData<C> { | |
| 139 | Os(RawOsError), | |
| 140 | Simple(ErrorKind), | |
| 141 | SimpleMessage(&'static SimpleMessage), | |
| 142 | Custom(C), | |
| 143 | } | |
| 144 | ||
| 145 | // `#[repr(align(4))]` is probably redundant, it should have that value or | |
| 146 | // higher already. We include it just because repr_bitpacked.rs's encoding | |
| 147 | // requires an alignment >= 4 (note that `#[repr(align)]` will not reduce the | |
| 148 | // alignment required by the struct, only increase it). | |
| 149 | // | |
| 150 | // If we add more variants to ErrorData, this can be increased to 8, but it | |
| 151 | // should probably be behind `#[cfg_attr(target_pointer_width = "64", ...)]` or | |
| 152 | // whatever cfg we're using to enable the `repr_bitpacked` code, since only the | |
| 153 | // that version needs the alignment, and 8 is higher than the alignment we'll | |
| 154 | // have on 32 bit platforms. | |
| 155 | // | |
| 156 | // (For the sake of being explicit: the alignment requirement here only matters | |
| 157 | // if `error/repr_bitpacked.rs` is in use — for the unpacked repr it doesn't | |
| 158 | // matter at all) | |
| 159 | #[doc(hidden)] | |
| 160 | #[unstable(feature = "io_const_error_internals", issue = "none")] | |
| 161 | #[repr(align(4))] | |
| 162 | #[derive(Debug)] | |
| 163 | pub struct SimpleMessage { | |
| 164 | pub kind: ErrorKind, | |
| 165 | pub message: &'static str, | |
| 166 | } | |
| 167 | ||
| 168 | /// Creates a new I/O error from a known kind of error and a string literal. | |
| 169 | /// | |
| 170 | /// Contrary to [`Error::new`], this macro does not allocate and can be used in | |
| 171 | /// `const` contexts. | |
| 172 | /// | |
| 173 | /// # Example | |
| 174 | /// ``` | |
| 175 | /// #![feature(io_const_error)] | |
| 176 | /// use std::io::{const_error, Error, ErrorKind}; | |
| 177 | /// | |
| 178 | /// const FAIL: Error = const_error!(ErrorKind::Unsupported, "tried something that never works"); | |
| 179 | /// | |
| 180 | /// fn not_here() -> Result<(), Error> { | |
| 181 | /// Err(FAIL) | |
| 182 | /// } | |
| 183 | /// ``` | |
| 184 | #[rustc_macro_transparency = "semiopaque"] | |
| 185 | #[unstable(feature = "io_const_error", issue = "133448")] | |
| 186 | #[allow_internal_unstable(hint_must_use, io_const_error_internals)] | |
| 187 | pub macro const_error($kind:expr, $message:expr $(,)?) { | |
| 188 | $crate::hint::must_use($crate::io::Error::from_static_message( | |
| 189 | const { &$crate::io::SimpleMessage { kind: $kind, message: $message } }, | |
| 190 | )) | |
| 191 | } | |
| 192 | ||
| 193 | // As with `SimpleMessage`: `#[repr(align(4))]` here is just because | |
| 194 | // repr_bitpacked's encoding requires it. In practice it almost certainly be | |
| 195 | // already be this high or higher. | |
| 196 | #[derive(Debug)] | |
| 197 | #[repr(align(4))] | |
| 198 | struct Custom { | |
| 199 | kind: ErrorKind, | |
| 200 | error: Box<dyn error::Error + Send + Sync>, | |
| 201 | } | |
| 202 | ||
| 203 | /// Intended for use for errors not exposed to the user, where allocating onto | |
| 204 | /// the heap (for normal construction via Error::new) is too costly. | |
| 205 | #[stable(feature = "io_error_from_errorkind", since = "1.14.0")] | |
| 206 | impl From<ErrorKind> for Error { | |
| 207 | /// Converts an [`ErrorKind`] into an [`Error`]. | |
| 208 | /// | |
| 209 | /// This conversion creates a new error with a simple representation of error kind. | |
| 210 | /// | |
| 211 | /// # Examples | |
| 212 | /// | |
| 213 | /// ``` | |
| 214 | /// use std::io::{Error, ErrorKind}; | |
| 215 | /// | |
| 216 | /// let not_found = ErrorKind::NotFound; | |
| 217 | /// let error = Error::from(not_found); | |
| 218 | /// assert_eq!("entity not found", format!("{error}")); | |
| 219 | /// ``` | |
| 220 | #[inline] | |
| 221 | fn from(kind: ErrorKind) -> Error { | |
| 222 | Error { repr: Repr::new_simple(kind) } | |
| 223 | } | |
| 224 | } | |
| 225 | ||
| 4 | #[cfg_attr( | |
| 5 | test, | |
| 6 | expect(unused, reason = "only used in implementation for non-test compilation") | |
| 7 | )] | |
| 8 | use crate::{ | |
| 9 | io::{Error, OsFunctions, RawOsError}, | |
| 10 | sys::io::{decode_error_kind, errno, error_string, is_interrupted}, | |
| 11 | }; | |
| 12 | ||
| 13 | // Because std is linked in during testing, these incoherent implementations would | |
| 14 | // be duplicated if this was unconditionally included. | |
| 15 | // See #2912 for details. | |
| 16 | #[cfg(not(test))] | |
| 226 | 17 | impl Error { |
| 227 | /// Creates a new I/O error from a known kind of error as well as an | |
| 228 | /// arbitrary error payload. | |
| 229 | /// | |
| 230 | /// This function is used to generically create I/O errors which do not | |
| 231 | /// originate from the OS itself. The `error` argument is an arbitrary | |
| 232 | /// payload which will be contained in this [`Error`]. | |
| 233 | /// | |
| 234 | /// Note that this function allocates memory on the heap. | |
| 235 | /// If no extra payload is required, use the `From` conversion from | |
| 236 | /// `ErrorKind`. | |
| 237 | /// | |
| 238 | /// # Examples | |
| 239 | /// | |
| 240 | /// ``` | |
| 241 | /// use std::io::{Error, ErrorKind}; | |
| 242 | /// | |
| 243 | /// // errors can be created from strings | |
| 244 | /// let custom_error = Error::new(ErrorKind::Other, "oh no!"); | |
| 245 | /// | |
| 246 | /// // errors can also be created from other errors | |
| 247 | /// let custom_error2 = Error::new(ErrorKind::Interrupted, custom_error); | |
| 248 | /// | |
| 249 | /// // creating an error without payload (and without memory allocation) | |
| 250 | /// let eof_error = Error::from(ErrorKind::UnexpectedEof); | |
| 251 | /// ``` | |
| 252 | #[stable(feature = "rust1", since = "1.0.0")] | |
| 253 | #[cfg_attr(not(test), rustc_diagnostic_item = "io_error_new")] | |
| 254 | #[inline(never)] | |
| 255 | pub fn new<E>(kind: ErrorKind, error: E) -> Error | |
| 256 | where | |
| 257 | E: Into<Box<dyn error::Error + Send + Sync>>, | |
| 258 | { | |
| 259 | Self::_new(kind, error.into()) | |
| 260 | } | |
| 261 | ||
| 262 | /// Creates a new I/O error from an arbitrary error payload. | |
| 263 | /// | |
| 264 | /// This function is used to generically create I/O errors which do not | |
| 265 | /// originate from the OS itself. It is a shortcut for [`Error::new`] | |
| 266 | /// with [`ErrorKind::Other`]. | |
| 267 | /// | |
| 268 | /// # Examples | |
| 269 | /// | |
| 270 | /// ``` | |
| 271 | /// use std::io::Error; | |
| 272 | /// | |
| 273 | /// // errors can be created from strings | |
| 274 | /// let custom_error = Error::other("oh no!"); | |
| 275 | /// | |
| 276 | /// // errors can also be created from other errors | |
| 277 | /// let custom_error2 = Error::other(custom_error); | |
| 278 | /// ``` | |
| 279 | #[stable(feature = "io_error_other", since = "1.74.0")] | |
| 280 | pub fn other<E>(error: E) -> Error | |
| 281 | where | |
| 282 | E: Into<Box<dyn error::Error + Send + Sync>>, | |
| 283 | { | |
| 284 | Self::_new(ErrorKind::Other, error.into()) | |
| 285 | } | |
| 286 | ||
| 287 | fn _new(kind: ErrorKind, error: Box<dyn error::Error + Send + Sync>) -> Error { | |
| 288 | Error { repr: Repr::new_custom(Box::new(Custom { kind, error })) } | |
| 289 | } | |
| 290 | ||
| 291 | /// Creates a new I/O error from a known kind of error as well as a constant | |
| 292 | /// message. | |
| 293 | /// | |
| 294 | /// This function does not allocate. | |
| 295 | /// | |
| 296 | /// You should not use this directly, and instead use the `const_error!` | |
| 297 | /// macro: `io::const_error!(ErrorKind::Something, "some_message")`. | |
| 298 | /// | |
| 299 | /// This function should maybe change to `from_static_message<const MSG: &'static | |
| 300 | /// str>(kind: ErrorKind)` in the future, when const generics allow that. | |
| 301 | #[inline] | |
| 302 | #[doc(hidden)] | |
| 303 | #[unstable(feature = "io_const_error_internals", issue = "none")] | |
| 304 | pub const fn from_static_message(msg: &'static SimpleMessage) -> Error { | |
| 305 | Self { repr: Repr::new_simple_message(msg) } | |
| 306 | } | |
| 307 | ||
| 308 | 18 | /// Returns an error representing the last OS error which occurred. |
| 309 | 19 | /// |
| 310 | 20 | /// This function reads the value of `errno` for the target platform (e.g. |
| ... | ... | @@ -324,13 +34,14 @@ impl Error { |
| 324 | 34 | /// let os_error = Error::last_os_error(); |
| 325 | 35 | /// println!("last OS error: {os_error:?}"); |
| 326 | 36 | /// ``` |
| 37 | #[rustc_allow_incoherent_impl] | |
| 327 | 38 | #[stable(feature = "rust1", since = "1.0.0")] |
| 328 | 39 | #[doc(alias = "GetLastError")] |
| 329 | 40 | #[doc(alias = "errno")] |
| 330 | 41 | #[must_use] |
| 331 | 42 | #[inline] |
| 332 | 43 | pub fn last_os_error() -> Error { |
| 333 | Error::from_raw_os_error(sys::io::errno()) | |
| 44 | Error::from_raw_os_error(errno()) | |
| 334 | 45 | } |
| 335 | 46 | |
| 336 | 47 | /// Creates a new instance of an [`Error`] from a particular OS error code. |
| ... | ... | @@ -358,405 +69,18 @@ impl Error { |
| 358 | 69 | /// assert_eq!(error.kind(), io::ErrorKind::InvalidInput); |
| 359 | 70 | /// # } |
| 360 | 71 | /// ``` |
| 72 | #[rustc_allow_incoherent_impl] | |
| 361 | 73 | #[stable(feature = "rust1", since = "1.0.0")] |
| 362 | 74 | #[must_use] |
| 363 | 75 | #[inline] |
| 364 | 76 | pub fn from_raw_os_error(code: RawOsError) -> Error { |
| 365 | Error { repr: Repr::new_os(code) } | |
| 366 | } | |
| 77 | const FUNCTIONS: &'static OsFunctions = &OsFunctions { | |
| 78 | format_os_error: |code, fmt| fmt.write_str(&error_string(code)), | |
| 79 | decode_error_kind, | |
| 80 | is_interrupted, | |
| 81 | }; | |
| 367 | 82 | |
| 368 | /// Returns the OS error that this error represents (if any). | |
| 369 | /// | |
| 370 | /// If this [`Error`] was constructed via [`last_os_error`] or | |
| 371 | /// [`from_raw_os_error`], then this function will return [`Some`], otherwise | |
| 372 | /// it will return [`None`]. | |
| 373 | /// | |
| 374 | /// [`last_os_error`]: Error::last_os_error | |
| 375 | /// [`from_raw_os_error`]: Error::from_raw_os_error | |
| 376 | /// | |
| 377 | /// # Examples | |
| 378 | /// | |
| 379 | /// ``` | |
| 380 | /// use std::io::{Error, ErrorKind}; | |
| 381 | /// | |
| 382 | /// fn print_os_error(err: &Error) { | |
| 383 | /// if let Some(raw_os_err) = err.raw_os_error() { | |
| 384 | /// println!("raw OS error: {raw_os_err:?}"); | |
| 385 | /// } else { | |
| 386 | /// println!("Not an OS error"); | |
| 387 | /// } | |
| 388 | /// } | |
| 389 | /// | |
| 390 | /// fn main() { | |
| 391 | /// // Will print "raw OS error: ...". | |
| 392 | /// print_os_error(&Error::last_os_error()); | |
| 393 | /// // Will print "Not an OS error". | |
| 394 | /// print_os_error(&Error::new(ErrorKind::Other, "oh no!")); | |
| 395 | /// } | |
| 396 | /// ``` | |
| 397 | #[stable(feature = "rust1", since = "1.0.0")] | |
| 398 | #[must_use] | |
| 399 | #[inline] | |
| 400 | pub fn raw_os_error(&self) -> Option<RawOsError> { | |
| 401 | match self.repr.data() { | |
| 402 | ErrorData::Os(i) => Some(i), | |
| 403 | ErrorData::Custom(..) => None, | |
| 404 | ErrorData::Simple(..) => None, | |
| 405 | ErrorData::SimpleMessage(..) => None, | |
| 406 | } | |
| 83 | // SAFETY: `FUNCTIONS` is a constant and not created at runtime. | |
| 84 | unsafe { Error::from_raw_os_error_with_functions(code, FUNCTIONS) } | |
| 407 | 85 | } |
| 408 | ||
| 409 | /// Returns a reference to the inner error wrapped by this error (if any). | |
| 410 | /// | |
| 411 | /// If this [`Error`] was constructed via [`new`] then this function will | |
| 412 | /// return [`Some`], otherwise it will return [`None`]. | |
| 413 | /// | |
| 414 | /// [`new`]: Error::new | |
| 415 | /// | |
| 416 | /// # Examples | |
| 417 | /// | |
| 418 | /// ``` | |
| 419 | /// use std::io::{Error, ErrorKind}; | |
| 420 | /// | |
| 421 | /// fn print_error(err: &Error) { | |
| 422 | /// if let Some(inner_err) = err.get_ref() { | |
| 423 | /// println!("Inner error: {inner_err:?}"); | |
| 424 | /// } else { | |
| 425 | /// println!("No inner error"); | |
| 426 | /// } | |
| 427 | /// } | |
| 428 | /// | |
| 429 | /// fn main() { | |
| 430 | /// // Will print "No inner error". | |
| 431 | /// print_error(&Error::last_os_error()); | |
| 432 | /// // Will print "Inner error: ...". | |
| 433 | /// print_error(&Error::new(ErrorKind::Other, "oh no!")); | |
| 434 | /// } | |
| 435 | /// ``` | |
| 436 | #[stable(feature = "io_error_inner", since = "1.3.0")] | |
| 437 | #[must_use] | |
| 438 | #[inline] | |
| 439 | pub fn get_ref(&self) -> Option<&(dyn error::Error + Send + Sync + 'static)> { | |
| 440 | match self.repr.data() { | |
| 441 | ErrorData::Os(..) => None, | |
| 442 | ErrorData::Simple(..) => None, | |
| 443 | ErrorData::SimpleMessage(..) => None, | |
| 444 | ErrorData::Custom(c) => Some(&*c.error), | |
| 445 | } | |
| 446 | } | |
| 447 | ||
| 448 | /// Returns a mutable reference to the inner error wrapped by this error | |
| 449 | /// (if any). | |
| 450 | /// | |
| 451 | /// If this [`Error`] was constructed via [`new`] then this function will | |
| 452 | /// return [`Some`], otherwise it will return [`None`]. | |
| 453 | /// | |
| 454 | /// [`new`]: Error::new | |
| 455 | /// | |
| 456 | /// # Examples | |
| 457 | /// | |
| 458 | /// ``` | |
| 459 | /// use std::io::{Error, ErrorKind}; | |
| 460 | /// use std::{error, fmt}; | |
| 461 | /// use std::fmt::Display; | |
| 462 | /// | |
| 463 | /// #[derive(Debug)] | |
| 464 | /// struct MyError { | |
| 465 | /// v: String, | |
| 466 | /// } | |
| 467 | /// | |
| 468 | /// impl MyError { | |
| 469 | /// fn new() -> MyError { | |
| 470 | /// MyError { | |
| 471 | /// v: "oh no!".to_string() | |
| 472 | /// } | |
| 473 | /// } | |
| 474 | /// | |
| 475 | /// fn change_message(&mut self, new_message: &str) { | |
| 476 | /// self.v = new_message.to_string(); | |
| 477 | /// } | |
| 478 | /// } | |
| 479 | /// | |
| 480 | /// impl error::Error for MyError {} | |
| 481 | /// | |
| 482 | /// impl Display for MyError { | |
| 483 | /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
| 484 | /// write!(f, "MyError: {}", self.v) | |
| 485 | /// } | |
| 486 | /// } | |
| 487 | /// | |
| 488 | /// fn change_error(mut err: Error) -> Error { | |
| 489 | /// if let Some(inner_err) = err.get_mut() { | |
| 490 | /// inner_err.downcast_mut::<MyError>().unwrap().change_message("I've been changed!"); | |
| 491 | /// } | |
| 492 | /// err | |
| 493 | /// } | |
| 494 | /// | |
| 495 | /// fn print_error(err: &Error) { | |
| 496 | /// if let Some(inner_err) = err.get_ref() { | |
| 497 | /// println!("Inner error: {inner_err}"); | |
| 498 | /// } else { | |
| 499 | /// println!("No inner error"); | |
| 500 | /// } | |
| 501 | /// } | |
| 502 | /// | |
| 503 | /// fn main() { | |
| 504 | /// // Will print "No inner error". | |
| 505 | /// print_error(&change_error(Error::last_os_error())); | |
| 506 | /// // Will print "Inner error: ...". | |
| 507 | /// print_error(&change_error(Error::new(ErrorKind::Other, MyError::new()))); | |
| 508 | /// } | |
| 509 | /// ``` | |
| 510 | #[stable(feature = "io_error_inner", since = "1.3.0")] | |
| 511 | #[must_use] | |
| 512 | #[inline] | |
| 513 | pub fn get_mut(&mut self) -> Option<&mut (dyn error::Error + Send + Sync + 'static)> { | |
| 514 | match self.repr.data_mut() { | |
| 515 | ErrorData::Os(..) => None, | |
| 516 | ErrorData::Simple(..) => None, | |
| 517 | ErrorData::SimpleMessage(..) => None, | |
| 518 | ErrorData::Custom(c) => Some(&mut *c.error), | |
| 519 | } | |
| 520 | } | |
| 521 | ||
| 522 | /// Consumes the `Error`, returning its inner error (if any). | |
| 523 | /// | |
| 524 | /// If this [`Error`] was constructed via [`new`] or [`other`], | |
| 525 | /// then this function will return [`Some`], | |
| 526 | /// otherwise it will return [`None`]. | |
| 527 | /// | |
| 528 | /// [`new`]: Error::new | |
| 529 | /// [`other`]: Error::other | |
| 530 | /// | |
| 531 | /// # Examples | |
| 532 | /// | |
| 533 | /// ``` | |
| 534 | /// use std::io::{Error, ErrorKind}; | |
| 535 | /// | |
| 536 | /// fn print_error(err: Error) { | |
| 537 | /// if let Some(inner_err) = err.into_inner() { | |
| 538 | /// println!("Inner error: {inner_err}"); | |
| 539 | /// } else { | |
| 540 | /// println!("No inner error"); | |
| 541 | /// } | |
| 542 | /// } | |
| 543 | /// | |
| 544 | /// fn main() { | |
| 545 | /// // Will print "No inner error". | |
| 546 | /// print_error(Error::last_os_error()); | |
| 547 | /// // Will print "Inner error: ...". | |
| 548 | /// print_error(Error::new(ErrorKind::Other, "oh no!")); | |
| 549 | /// } | |
| 550 | /// ``` | |
| 551 | #[stable(feature = "io_error_inner", since = "1.3.0")] | |
| 552 | #[must_use = "`self` will be dropped if the result is not used"] | |
| 553 | #[inline] | |
| 554 | pub fn into_inner(self) -> Option<Box<dyn error::Error + Send + Sync>> { | |
| 555 | match self.repr.into_data() { | |
| 556 | ErrorData::Os(..) => None, | |
| 557 | ErrorData::Simple(..) => None, | |
| 558 | ErrorData::SimpleMessage(..) => None, | |
| 559 | ErrorData::Custom(c) => Some(c.error), | |
| 560 | } | |
| 561 | } | |
| 562 | ||
| 563 | /// Attempts to downcast the custom boxed error to `E`. | |
| 564 | /// | |
| 565 | /// If this [`Error`] contains a custom boxed error, | |
| 566 | /// then it would attempt downcasting on the boxed error, | |
| 567 | /// otherwise it will return [`Err`]. | |
| 568 | /// | |
| 569 | /// If the custom boxed error has the same type as `E`, it will return [`Ok`], | |
| 570 | /// otherwise it will also return [`Err`]. | |
| 571 | /// | |
| 572 | /// This method is meant to be a convenience routine for calling | |
| 573 | /// `Box<dyn Error + Sync + Send>::downcast` on the custom boxed error, returned by | |
| 574 | /// [`Error::into_inner`]. | |
| 575 | /// | |
| 576 | /// | |
| 577 | /// # Examples | |
| 578 | /// | |
| 579 | /// ``` | |
| 580 | /// use std::fmt; | |
| 581 | /// use std::io; | |
| 582 | /// use std::error::Error; | |
| 583 | /// | |
| 584 | /// #[derive(Debug)] | |
| 585 | /// enum E { | |
| 586 | /// Io(io::Error), | |
| 587 | /// SomeOtherVariant, | |
| 588 | /// } | |
| 589 | /// | |
| 590 | /// impl fmt::Display for E { | |
| 591 | /// // ... | |
| 592 | /// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
| 593 | /// # todo!() | |
| 594 | /// # } | |
| 595 | /// } | |
| 596 | /// impl Error for E {} | |
| 597 | /// | |
| 598 | /// impl From<io::Error> for E { | |
| 599 | /// fn from(err: io::Error) -> E { | |
| 600 | /// err.downcast::<E>() | |
| 601 | /// .unwrap_or_else(E::Io) | |
| 602 | /// } | |
| 603 | /// } | |
| 604 | /// | |
| 605 | /// impl From<E> for io::Error { | |
| 606 | /// fn from(err: E) -> io::Error { | |
| 607 | /// match err { | |
| 608 | /// E::Io(io_error) => io_error, | |
| 609 | /// e => io::Error::new(io::ErrorKind::Other, e), | |
| 610 | /// } | |
| 611 | /// } | |
| 612 | /// } | |
| 613 | /// | |
| 614 | /// # fn main() { | |
| 615 | /// let e = E::SomeOtherVariant; | |
| 616 | /// // Convert it to an io::Error | |
| 617 | /// let io_error = io::Error::from(e); | |
| 618 | /// // Cast it back to the original variant | |
| 619 | /// let e = E::from(io_error); | |
| 620 | /// assert!(matches!(e, E::SomeOtherVariant)); | |
| 621 | /// | |
| 622 | /// let io_error = io::Error::from(io::ErrorKind::AlreadyExists); | |
| 623 | /// // Convert it to E | |
| 624 | /// let e = E::from(io_error); | |
| 625 | /// // Cast it back to the original variant | |
| 626 | /// let io_error = io::Error::from(e); | |
| 627 | /// assert_eq!(io_error.kind(), io::ErrorKind::AlreadyExists); | |
| 628 | /// assert!(io_error.get_ref().is_none()); | |
| 629 | /// assert!(io_error.raw_os_error().is_none()); | |
| 630 | /// # } | |
| 631 | /// ``` | |
| 632 | #[stable(feature = "io_error_downcast", since = "1.79.0")] | |
| 633 | pub fn downcast<E>(self) -> result::Result<E, Self> | |
| 634 | where | |
| 635 | E: error::Error + Send + Sync + 'static, | |
| 636 | { | |
| 637 | if let ErrorData::Custom(c) = self.repr.data() | |
| 638 | && c.error.is::<E>() | |
| 639 | { | |
| 640 | if let ErrorData::Custom(b) = self.repr.into_data() | |
| 641 | && let Ok(err) = b.error.downcast::<E>() | |
| 642 | { | |
| 643 | Ok(*err) | |
| 644 | } else { | |
| 645 | // Safety: We have just checked that the condition is true | |
| 646 | unsafe { crate::hint::unreachable_unchecked() } | |
| 647 | } | |
| 648 | } else { | |
| 649 | Err(self) | |
| 650 | } | |
| 651 | } | |
| 652 | ||
| 653 | /// Returns the corresponding [`ErrorKind`] for this error. | |
| 654 | /// | |
| 655 | /// This may be a value set by Rust code constructing custom `io::Error`s, | |
| 656 | /// or if this `io::Error` was sourced from the operating system, | |
| 657 | /// it will be a value inferred from the system's error encoding. | |
| 658 | /// See [`last_os_error`] for more details. | |
| 659 | /// | |
| 660 | /// [`last_os_error`]: Error::last_os_error | |
| 661 | /// | |
| 662 | /// # Examples | |
| 663 | /// | |
| 664 | /// ``` | |
| 665 | /// use std::io::{Error, ErrorKind}; | |
| 666 | /// | |
| 667 | /// fn print_error(err: Error) { | |
| 668 | /// println!("{:?}", err.kind()); | |
| 669 | /// } | |
| 670 | /// | |
| 671 | /// fn main() { | |
| 672 | /// // As no error has (visibly) occurred, this may print anything! | |
| 673 | /// // It likely prints a placeholder for unidentified (non-)errors. | |
| 674 | /// print_error(Error::last_os_error()); | |
| 675 | /// // Will print "AddrInUse". | |
| 676 | /// print_error(Error::new(ErrorKind::AddrInUse, "oh no!")); | |
| 677 | /// } | |
| 678 | /// ``` | |
| 679 | #[stable(feature = "rust1", since = "1.0.0")] | |
| 680 | #[must_use] | |
| 681 | #[inline] | |
| 682 | pub fn kind(&self) -> ErrorKind { | |
| 683 | match self.repr.data() { | |
| 684 | ErrorData::Os(code) => sys::io::decode_error_kind(code), | |
| 685 | ErrorData::Custom(c) => c.kind, | |
| 686 | ErrorData::Simple(kind) => kind, | |
| 687 | ErrorData::SimpleMessage(m) => m.kind, | |
| 688 | } | |
| 689 | } | |
| 690 | ||
| 691 | #[inline] | |
| 692 | pub(crate) fn is_interrupted(&self) -> bool { | |
| 693 | match self.repr.data() { | |
| 694 | ErrorData::Os(code) => sys::io::is_interrupted(code), | |
| 695 | ErrorData::Custom(c) => c.kind == ErrorKind::Interrupted, | |
| 696 | ErrorData::Simple(kind) => kind == ErrorKind::Interrupted, | |
| 697 | ErrorData::SimpleMessage(m) => m.kind == ErrorKind::Interrupted, | |
| 698 | } | |
| 699 | } | |
| 700 | } | |
| 701 | ||
| 702 | impl fmt::Debug for Repr { | |
| 703 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { | |
| 704 | match self.data() { | |
| 705 | ErrorData::Os(code) => fmt | |
| 706 | .debug_struct("Os") | |
| 707 | .field("code", &code) | |
| 708 | .field("kind", &sys::io::decode_error_kind(code)) | |
| 709 | .field("message", &sys::io::error_string(code)) | |
| 710 | .finish(), | |
| 711 | ErrorData::Custom(c) => fmt::Debug::fmt(&c, fmt), | |
| 712 | ErrorData::Simple(kind) => fmt.debug_tuple("Kind").field(&kind).finish(), | |
| 713 | ErrorData::SimpleMessage(msg) => fmt | |
| 714 | .debug_struct("Error") | |
| 715 | .field("kind", &msg.kind) | |
| 716 | .field("message", &msg.message) | |
| 717 | .finish(), | |
| 718 | } | |
| 719 | } | |
| 720 | } | |
| 721 | ||
| 722 | #[stable(feature = "rust1", since = "1.0.0")] | |
| 723 | impl fmt::Display for Error { | |
| 724 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { | |
| 725 | match self.repr.data() { | |
| 726 | ErrorData::Os(code) => { | |
| 727 | let detail = sys::io::error_string(code); | |
| 728 | write!(fmt, "{detail} (os error {code})") | |
| 729 | } | |
| 730 | ErrorData::Custom(ref c) => c.error.fmt(fmt), | |
| 731 | ErrorData::Simple(kind) => kind.fmt(fmt), | |
| 732 | ErrorData::SimpleMessage(msg) => msg.message.fmt(fmt), | |
| 733 | } | |
| 734 | } | |
| 735 | } | |
| 736 | ||
| 737 | #[stable(feature = "rust1", since = "1.0.0")] | |
| 738 | impl error::Error for Error { | |
| 739 | #[allow(deprecated)] | |
| 740 | fn cause(&self) -> Option<&dyn error::Error> { | |
| 741 | match self.repr.data() { | |
| 742 | ErrorData::Os(..) => None, | |
| 743 | ErrorData::Simple(..) => None, | |
| 744 | ErrorData::SimpleMessage(..) => None, | |
| 745 | ErrorData::Custom(c) => c.error.cause(), | |
| 746 | } | |
| 747 | } | |
| 748 | ||
| 749 | fn source(&self) -> Option<&(dyn error::Error + 'static)> { | |
| 750 | match self.repr.data() { | |
| 751 | ErrorData::Os(..) => None, | |
| 752 | ErrorData::Simple(..) => None, | |
| 753 | ErrorData::SimpleMessage(..) => None, | |
| 754 | ErrorData::Custom(c) => c.error.source(), | |
| 755 | } | |
| 756 | } | |
| 757 | } | |
| 758 | ||
| 759 | fn _assert_error_is_sync_send() { | |
| 760 | fn _is_sync_send<T: Sync + Send>() {} | |
| 761 | _is_sync_send::<Error>(); | |
| 762 | 86 | } |
library/std/src/io/error/repr_bitpacked.rs deleted-348| ... | ... | @@ -1,348 +0,0 @@ |
| 1 | //! This is a densely packed error representation which is used on targets with | |
| 2 | //! 64-bit pointers. | |
| 3 | //! | |
| 4 | //! (Note that `bitpacked` vs `unpacked` here has no relationship to | |
| 5 | //! `#[repr(packed)]`, it just refers to attempting to use any available bits in | |
| 6 | //! a more clever manner than `rustc`'s default layout algorithm would). | |
| 7 | //! | |
| 8 | //! Conceptually, it stores the same data as the "unpacked" equivalent we use on | |
| 9 | //! other targets. Specifically, you can imagine it as an optimized version of | |
| 10 | //! the following enum (which is roughly equivalent to what's stored by | |
| 11 | //! `repr_unpacked::Repr`, e.g. `super::ErrorData<Box<Custom>>`): | |
| 12 | //! | |
| 13 | //! ```ignore (exposition-only) | |
| 14 | //! enum ErrorData { | |
| 15 | //! Os(i32), | |
| 16 | //! Simple(ErrorKind), | |
| 17 | //! SimpleMessage(&'static SimpleMessage), | |
| 18 | //! Custom(Box<Custom>), | |
| 19 | //! } | |
| 20 | //! ``` | |
| 21 | //! | |
| 22 | //! However, it packs this data into a 64bit non-zero value. | |
| 23 | //! | |
| 24 | //! This optimization not only allows `io::Error` to occupy a single pointer, | |
| 25 | //! but improves `io::Result` as well, especially for situations like | |
| 26 | //! `io::Result<()>` (which is now 64 bits) or `io::Result<u64>` (which is now | |
| 27 | //! 128 bits), which are quite common. | |
| 28 | //! | |
| 29 | //! # Layout | |
| 30 | //! Tagged values are 64 bits, with the 2 least significant bits used for the | |
| 31 | //! tag. This means there are 4 "variants": | |
| 32 | //! | |
| 33 | //! - **Tag 0b00**: The first variant is equivalent to | |
| 34 | //! `ErrorData::SimpleMessage`, and holds a `&'static SimpleMessage` directly. | |
| 35 | //! | |
| 36 | //! `SimpleMessage` has an alignment >= 4 (which is requested with | |
| 37 | //! `#[repr(align)]` and checked statically at the bottom of this file), which | |
| 38 | //! means every `&'static SimpleMessage` should have the both tag bits as 0, | |
| 39 | //! meaning its tagged and untagged representation are equivalent. | |
| 40 | //! | |
| 41 | //! This means we can skip tagging it, which is necessary as this variant can | |
| 42 | //! be constructed from a `const fn`, which probably cannot tag pointers (or | |
| 43 | //! at least it would be difficult). | |
| 44 | //! | |
| 45 | //! - **Tag 0b01**: The other pointer variant holds the data for | |
| 46 | //! `ErrorData::Custom` and the remaining 62 bits are used to store a | |
| 47 | //! `Box<Custom>`. `Custom` also has alignment >= 4, so the bottom two bits | |
| 48 | //! are free to use for the tag. | |
| 49 | //! | |
| 50 | //! The only important thing to note is that `ptr::wrapping_add` and | |
| 51 | //! `ptr::wrapping_sub` are used to tag the pointer, rather than bitwise | |
| 52 | //! operations. This should preserve the pointer's provenance, which would | |
| 53 | //! otherwise be lost. | |
| 54 | //! | |
| 55 | //! - **Tag 0b10**: Holds the data for `ErrorData::Os(i32)`. We store the `i32` | |
| 56 | //! in the pointer's most significant 32 bits, and don't use the bits `2..32` | |
| 57 | //! for anything. Using the top 32 bits is just to let us easily recover the | |
| 58 | //! `i32` code with the correct sign. | |
| 59 | //! | |
| 60 | //! - **Tag 0b11**: Holds the data for `ErrorData::Simple(ErrorKind)`. This | |
| 61 | //! stores the `ErrorKind` in the top 32 bits as well, although it doesn't | |
| 62 | //! occupy nearly that many. Most of the bits are unused here, but it's not | |
| 63 | //! like we need them for anything else yet. | |
| 64 | //! | |
| 65 | //! # Use of `NonNull<()>` | |
| 66 | //! | |
| 67 | //! Everything is stored in a `NonNull<()>`, which is odd, but actually serves a | |
| 68 | //! purpose. | |
| 69 | //! | |
| 70 | //! Conceptually you might think of this more like: | |
| 71 | //! | |
| 72 | //! ```ignore (exposition-only) | |
| 73 | //! union Repr { | |
| 74 | //! // holds integer (Simple/Os) variants, and | |
| 75 | //! // provides access to the tag bits. | |
| 76 | //! bits: NonZero<u64>, | |
| 77 | //! // Tag is 0, so this is stored untagged. | |
| 78 | //! msg: &'static SimpleMessage, | |
| 79 | //! // Tagged (offset) `Box<Custom>` pointer. | |
| 80 | //! tagged_custom: NonNull<()>, | |
| 81 | //! } | |
| 82 | //! ``` | |
| 83 | //! | |
| 84 | //! But there are a few problems with this: | |
| 85 | //! | |
| 86 | //! 1. Union access is equivalent to a transmute, so this representation would | |
| 87 | //! require we transmute between integers and pointers in at least one | |
| 88 | //! direction, which may be UB (and even if not, it is likely harder for a | |
| 89 | //! compiler to reason about than explicit ptr->int operations). | |
| 90 | //! | |
| 91 | //! 2. Even if all fields of a union have a niche, the union itself doesn't, | |
| 92 | //! although this may change in the future. This would make things like | |
| 93 | //! `io::Result<()>` and `io::Result<usize>` larger, which defeats part of | |
| 94 | //! the motivation of this bitpacking. | |
| 95 | //! | |
| 96 | //! Storing everything in a `NonZero<usize>` (or some other integer) would be a | |
| 97 | //! bit more traditional for pointer tagging, but it would lose provenance | |
| 98 | //! information, couldn't be constructed from a `const fn`, and would probably | |
| 99 | //! run into other issues as well. | |
| 100 | //! | |
| 101 | //! The `NonNull<()>` seems like the only alternative, even if it's fairly odd | |
| 102 | //! to use a pointer type to store something that may hold an integer, some of | |
| 103 | //! the time. | |
| 104 | ||
| 105 | use core::marker::PhantomData; | |
| 106 | use core::num::NonZeroUsize; | |
| 107 | use core::ptr::NonNull; | |
| 108 | ||
| 109 | use super::{Custom, ErrorData, ErrorKind, RawOsError, SimpleMessage}; | |
| 110 | ||
| 111 | // The 2 least-significant bits are used as tag. | |
| 112 | const TAG_MASK: usize = 0b11; | |
| 113 | const TAG_SIMPLE_MESSAGE: usize = 0b00; | |
| 114 | const TAG_CUSTOM: usize = 0b01; | |
| 115 | const TAG_OS: usize = 0b10; | |
| 116 | const TAG_SIMPLE: usize = 0b11; | |
| 117 | ||
| 118 | /// The internal representation. | |
| 119 | /// | |
| 120 | /// See the module docs for more, this is just a way to hack in a check that we | |
| 121 | /// indeed are not unwind-safe. | |
| 122 | /// | |
| 123 | /// ```compile_fail,E0277 | |
| 124 | /// fn is_unwind_safe<T: core::panic::UnwindSafe>() {} | |
| 125 | /// is_unwind_safe::<std::io::Error>(); | |
| 126 | /// ``` | |
| 127 | #[repr(transparent)] | |
| 128 | #[rustc_insignificant_dtor] | |
| 129 | pub(super) struct Repr(NonNull<()>, PhantomData<ErrorData<Box<Custom>>>); | |
| 130 | ||
| 131 | // All the types `Repr` stores internally are Send + Sync, and so is it. | |
| 132 | unsafe impl Send for Repr {} | |
| 133 | unsafe impl Sync for Repr {} | |
| 134 | ||
| 135 | impl Repr { | |
| 136 | pub(super) fn new_custom(b: Box<Custom>) -> Self { | |
| 137 | let p = Box::into_raw(b).cast::<u8>(); | |
| 138 | // Should only be possible if an allocator handed out a pointer with | |
| 139 | // wrong alignment. | |
| 140 | debug_assert_eq!(p.addr() & TAG_MASK, 0); | |
| 141 | // Note: We know `TAG_CUSTOM <= size_of::<Custom>()` (static_assert at | |
| 142 | // end of file), and both the start and end of the expression must be | |
| 143 | // valid without address space wraparound due to `Box`'s semantics. | |
| 144 | // | |
| 145 | // This means it would be correct to implement this using `ptr::add` | |
| 146 | // (rather than `ptr::wrapping_add`), but it's unclear this would give | |
| 147 | // any benefit, so we just use `wrapping_add` instead. | |
| 148 | let tagged = p.wrapping_add(TAG_CUSTOM).cast::<()>(); | |
| 149 | // Safety: `TAG_CUSTOM + p` is the same as `TAG_CUSTOM | p`, | |
| 150 | // because `p`'s alignment means it isn't allowed to have any of the | |
| 151 | // `TAG_BITS` set (you can verify that addition and bitwise-or are the | |
| 152 | // same when the operands have no bits in common using a truth table). | |
| 153 | // | |
| 154 | // Then, `TAG_CUSTOM | p` is not zero, as that would require | |
| 155 | // `TAG_CUSTOM` and `p` both be zero, and neither is (as `p` came from a | |
| 156 | // box, and `TAG_CUSTOM` just... isn't zero -- it's `0b01`). Therefore, | |
| 157 | // `TAG_CUSTOM + p` isn't zero and so `tagged` can't be, and the | |
| 158 | // `new_unchecked` is safe. | |
| 159 | let res = Self(unsafe { NonNull::new_unchecked(tagged) }, PhantomData); | |
| 160 | // quickly smoke-check we encoded the right thing (This generally will | |
| 161 | // only run in std's tests, unless the user uses -Zbuild-std) | |
| 162 | debug_assert!(matches!(res.data(), ErrorData::Custom(_)), "repr(custom) encoding failed"); | |
| 163 | res | |
| 164 | } | |
| 165 | ||
| 166 | #[inline] | |
| 167 | pub(super) fn new_os(code: RawOsError) -> Self { | |
| 168 | let utagged = ((code as usize) << 32) | TAG_OS; | |
| 169 | // Safety: `TAG_OS` is not zero, so the result of the `|` is not 0. | |
| 170 | let res = Self( | |
| 171 | NonNull::without_provenance(unsafe { NonZeroUsize::new_unchecked(utagged) }), | |
| 172 | PhantomData, | |
| 173 | ); | |
| 174 | // quickly smoke-check we encoded the right thing (This generally will | |
| 175 | // only run in std's tests, unless the user uses -Zbuild-std) | |
| 176 | debug_assert!( | |
| 177 | matches!(res.data(), ErrorData::Os(c) if c == code), | |
| 178 | "repr(os) encoding failed for {code}" | |
| 179 | ); | |
| 180 | res | |
| 181 | } | |
| 182 | ||
| 183 | #[inline] | |
| 184 | pub(super) fn new_simple(kind: ErrorKind) -> Self { | |
| 185 | let utagged = ((kind as usize) << 32) | TAG_SIMPLE; | |
| 186 | // Safety: `TAG_SIMPLE` is not zero, so the result of the `|` is not 0. | |
| 187 | let res = Self( | |
| 188 | NonNull::without_provenance(unsafe { NonZeroUsize::new_unchecked(utagged) }), | |
| 189 | PhantomData, | |
| 190 | ); | |
| 191 | // quickly smoke-check we encoded the right thing (This generally will | |
| 192 | // only run in std's tests, unless the user uses -Zbuild-std) | |
| 193 | debug_assert!( | |
| 194 | matches!(res.data(), ErrorData::Simple(k) if k == kind), | |
| 195 | "repr(simple) encoding failed {:?}", | |
| 196 | kind, | |
| 197 | ); | |
| 198 | res | |
| 199 | } | |
| 200 | ||
| 201 | #[inline] | |
| 202 | pub(super) const fn new_simple_message(m: &'static SimpleMessage) -> Self { | |
| 203 | // Safety: References are never null. | |
| 204 | Self(unsafe { NonNull::new_unchecked(m as *const _ as *mut ()) }, PhantomData) | |
| 205 | } | |
| 206 | ||
| 207 | #[inline] | |
| 208 | pub(super) fn data(&self) -> ErrorData<&Custom> { | |
| 209 | // Safety: We're a Repr, decode_repr is fine. | |
| 210 | unsafe { decode_repr(self.0, |c| &*c) } | |
| 211 | } | |
| 212 | ||
| 213 | #[inline] | |
| 214 | pub(super) fn data_mut(&mut self) -> ErrorData<&mut Custom> { | |
| 215 | // Safety: We're a Repr, decode_repr is fine. | |
| 216 | unsafe { decode_repr(self.0, |c| &mut *c) } | |
| 217 | } | |
| 218 | ||
| 219 | #[inline] | |
| 220 | pub(super) fn into_data(self) -> ErrorData<Box<Custom>> { | |
| 221 | let this = core::mem::ManuallyDrop::new(self); | |
| 222 | // Safety: We're a Repr, decode_repr is fine. The `Box::from_raw` is | |
| 223 | // safe because we prevent double-drop using `ManuallyDrop`. | |
| 224 | unsafe { decode_repr(this.0, |p| Box::from_raw(p)) } | |
| 225 | } | |
| 226 | } | |
| 227 | ||
| 228 | impl Drop for Repr { | |
| 229 | #[inline] | |
| 230 | fn drop(&mut self) { | |
| 231 | // Safety: We're a Repr, decode_repr is fine. The `Box::from_raw` is | |
| 232 | // safe because we're being dropped. | |
| 233 | unsafe { | |
| 234 | let _ = decode_repr(self.0, |p| Box::<Custom>::from_raw(p)); | |
| 235 | } | |
| 236 | } | |
| 237 | } | |
| 238 | ||
| 239 | // Shared helper to decode a `Repr`'s internal pointer into an ErrorData. | |
| 240 | // | |
| 241 | // Safety: `ptr`'s bits should be encoded as described in the document at the | |
| 242 | // top (it should `some_repr.0`) | |
| 243 | #[inline] | |
| 244 | unsafe fn decode_repr<C, F>(ptr: NonNull<()>, make_custom: F) -> ErrorData<C> | |
| 245 | where | |
| 246 | F: FnOnce(*mut Custom) -> C, | |
| 247 | { | |
| 248 | let bits = ptr.as_ptr().addr(); | |
| 249 | match bits & TAG_MASK { | |
| 250 | TAG_OS => { | |
| 251 | let code = ((bits as i64) >> 32) as RawOsError; | |
| 252 | ErrorData::Os(code) | |
| 253 | } | |
| 254 | TAG_SIMPLE => { | |
| 255 | let kind_bits = (bits >> 32) as u32; | |
| 256 | let kind = ErrorKind::from_prim(kind_bits).unwrap_or_else(|| { | |
| 257 | debug_assert!(false, "Invalid io::error::Repr bits: `Repr({:#018x})`", bits); | |
| 258 | // This means the `ptr` passed in was not valid, which violates | |
| 259 | // the unsafe contract of `decode_repr`. | |
| 260 | // | |
| 261 | // Using this rather than unwrap meaningfully improves the code | |
| 262 | // for callers which only care about one variant (usually | |
| 263 | // `Custom`) | |
| 264 | unsafe { core::hint::unreachable_unchecked() }; | |
| 265 | }); | |
| 266 | ErrorData::Simple(kind) | |
| 267 | } | |
| 268 | TAG_SIMPLE_MESSAGE => { | |
| 269 | // SAFETY: per tag | |
| 270 | unsafe { ErrorData::SimpleMessage(&*ptr.cast::<SimpleMessage>().as_ptr()) } | |
| 271 | } | |
| 272 | TAG_CUSTOM => { | |
| 273 | // It would be correct for us to use `ptr::byte_sub` here (see the | |
| 274 | // comment above the `wrapping_add` call in `new_custom` for why), | |
| 275 | // but it isn't clear that it makes a difference, so we don't. | |
| 276 | let custom = ptr.as_ptr().wrapping_byte_sub(TAG_CUSTOM).cast::<Custom>(); | |
| 277 | ErrorData::Custom(make_custom(custom)) | |
| 278 | } | |
| 279 | _ => { | |
| 280 | // Can't happen, and compiler can tell | |
| 281 | unreachable!(); | |
| 282 | } | |
| 283 | } | |
| 284 | } | |
| 285 | ||
| 286 | // Some static checking to alert us if a change breaks any of the assumptions | |
| 287 | // that our encoding relies on for correctness and soundness. (Some of these are | |
| 288 | // a bit overly thorough/cautious, admittedly) | |
| 289 | // | |
| 290 | // If any of these are hit on a platform that std supports, we should likely | |
| 291 | // just use `repr_unpacked.rs` there instead (unless the fix is easy). | |
| 292 | macro_rules! static_assert { | |
| 293 | ($condition:expr) => { | |
| 294 | const _: () = assert!($condition); | |
| 295 | }; | |
| 296 | (@usize_eq: $lhs:expr, $rhs:expr) => { | |
| 297 | const _: [(); $lhs] = [(); $rhs]; | |
| 298 | }; | |
| 299 | } | |
| 300 | ||
| 301 | // The bitpacking we use requires pointers be exactly 64 bits. | |
| 302 | static_assert!(@usize_eq: size_of::<NonNull<()>>(), 8); | |
| 303 | ||
| 304 | // We also require pointers and usize be the same size. | |
| 305 | static_assert!(@usize_eq: size_of::<NonNull<()>>(), size_of::<usize>()); | |
| 306 | ||
| 307 | // `Custom` and `SimpleMessage` need to be thin pointers. | |
| 308 | static_assert!(@usize_eq: size_of::<&'static SimpleMessage>(), 8); | |
| 309 | static_assert!(@usize_eq: size_of::<Box<Custom>>(), 8); | |
| 310 | ||
| 311 | static_assert!((TAG_MASK + 1).is_power_of_two()); | |
| 312 | // And they must have sufficient alignment. | |
| 313 | static_assert!(align_of::<SimpleMessage>() >= TAG_MASK + 1); | |
| 314 | static_assert!(align_of::<Custom>() >= TAG_MASK + 1); | |
| 315 | ||
| 316 | static_assert!(@usize_eq: TAG_MASK & TAG_SIMPLE_MESSAGE, TAG_SIMPLE_MESSAGE); | |
| 317 | static_assert!(@usize_eq: TAG_MASK & TAG_CUSTOM, TAG_CUSTOM); | |
| 318 | static_assert!(@usize_eq: TAG_MASK & TAG_OS, TAG_OS); | |
| 319 | static_assert!(@usize_eq: TAG_MASK & TAG_SIMPLE, TAG_SIMPLE); | |
| 320 | ||
| 321 | // This is obviously true (`TAG_CUSTOM` is `0b01`), but in `Repr::new_custom` we | |
| 322 | // offset a pointer by this value, and expect it to both be within the same | |
| 323 | // object, and to not wrap around the address space. See the comment in that | |
| 324 | // function for further details. | |
| 325 | // | |
| 326 | // Actually, at the moment we use `ptr::wrapping_add`, not `ptr::add`, so this | |
| 327 | // check isn't needed for that one, although the assertion that we don't | |
| 328 | // actually wrap around in that wrapping_add does simplify the safety reasoning | |
| 329 | // elsewhere considerably. | |
| 330 | static_assert!(size_of::<Custom>() >= TAG_CUSTOM); | |
| 331 | ||
| 332 | // These two store a payload which is allowed to be zero, so they must be | |
| 333 | // non-zero to preserve the `NonNull`'s range invariant. | |
| 334 | static_assert!(TAG_OS != 0); | |
| 335 | static_assert!(TAG_SIMPLE != 0); | |
| 336 | // We can't tag `SimpleMessage`s, the tag must be 0. | |
| 337 | static_assert!(@usize_eq: TAG_SIMPLE_MESSAGE, 0); | |
| 338 | ||
| 339 | // Check that the point of all of this still holds. | |
| 340 | // | |
| 341 | // We'd check against `io::Error`, but *technically* it's allowed to vary, | |
| 342 | // as it's not `#[repr(transparent)]`/`#[repr(C)]`. We could add that, but | |
| 343 | // the `#[repr()]` would show up in rustdoc, which might be seen as a stable | |
| 344 | // commitment. | |
| 345 | static_assert!(@usize_eq: size_of::<Repr>(), 8); | |
| 346 | static_assert!(@usize_eq: size_of::<Option<Repr>>(), 8); | |
| 347 | static_assert!(@usize_eq: size_of::<Result<(), Repr>>(), 8); | |
| 348 | static_assert!(@usize_eq: size_of::<Result<usize, Repr>>(), 16); |
library/std/src/io/error/repr_unpacked.rs deleted-50| ... | ... | @@ -1,50 +0,0 @@ |
| 1 | //! This is a fairly simple unpacked error representation that's used on | |
| 2 | //! non-64bit targets, where the packed 64 bit representation wouldn't work, and | |
| 3 | //! would have no benefit. | |
| 4 | ||
| 5 | use super::{Custom, ErrorData, ErrorKind, RawOsError, SimpleMessage}; | |
| 6 | ||
| 7 | type Inner = ErrorData<Box<Custom>>; | |
| 8 | ||
| 9 | pub(super) struct Repr(Inner); | |
| 10 | ||
| 11 | impl Repr { | |
| 12 | #[inline] | |
| 13 | pub(super) fn new_custom(b: Box<Custom>) -> Self { | |
| 14 | Self(Inner::Custom(b)) | |
| 15 | } | |
| 16 | #[inline] | |
| 17 | pub(super) fn new_os(code: RawOsError) -> Self { | |
| 18 | Self(Inner::Os(code)) | |
| 19 | } | |
| 20 | #[inline] | |
| 21 | pub(super) fn new_simple(kind: ErrorKind) -> Self { | |
| 22 | Self(Inner::Simple(kind)) | |
| 23 | } | |
| 24 | #[inline] | |
| 25 | pub(super) const fn new_simple_message(m: &'static SimpleMessage) -> Self { | |
| 26 | Self(Inner::SimpleMessage(m)) | |
| 27 | } | |
| 28 | #[inline] | |
| 29 | pub(super) fn into_data(self) -> ErrorData<Box<Custom>> { | |
| 30 | self.0 | |
| 31 | } | |
| 32 | #[inline] | |
| 33 | pub(super) fn data(&self) -> ErrorData<&Custom> { | |
| 34 | match &self.0 { | |
| 35 | Inner::Os(c) => ErrorData::Os(*c), | |
| 36 | Inner::Simple(k) => ErrorData::Simple(*k), | |
| 37 | Inner::SimpleMessage(m) => ErrorData::SimpleMessage(*m), | |
| 38 | Inner::Custom(m) => ErrorData::Custom(&*m), | |
| 39 | } | |
| 40 | } | |
| 41 | #[inline] | |
| 42 | pub(super) fn data_mut(&mut self) -> ErrorData<&mut Custom> { | |
| 43 | match &mut self.0 { | |
| 44 | Inner::Os(c) => ErrorData::Os(*c), | |
| 45 | Inner::Simple(k) => ErrorData::Simple(*k), | |
| 46 | Inner::SimpleMessage(m) => ErrorData::SimpleMessage(*m), | |
| 47 | Inner::Custom(m) => ErrorData::Custom(&mut *m), | |
| 48 | } | |
| 49 | } | |
| 50 | } |
library/std/src/io/error/tests.rs+11-34| ... | ... | @@ -1,4 +1,4 @@ |
| 1 | use super::{Custom, Error, ErrorData, ErrorKind, Repr, SimpleMessage, const_error}; | |
| 1 | use crate::io::{Error, ErrorKind, const_error}; | |
| 2 | 2 | use crate::sys::io::{decode_error_kind, error_string}; |
| 3 | 3 | use crate::{assert_matches, error, fmt}; |
| 4 | 4 | |
| ... | ... | @@ -12,12 +12,7 @@ fn test_debug_error() { |
| 12 | 12 | let code = 6; |
| 13 | 13 | let msg = error_string(code); |
| 14 | 14 | let kind = decode_error_kind(code); |
| 15 | let err = Error { | |
| 16 | repr: Repr::new_custom(Box::new(Custom { | |
| 17 | kind: ErrorKind::InvalidInput, | |
| 18 | error: Box::new(Error { repr: super::Repr::new_os(code) }), | |
| 19 | })), | |
| 20 | }; | |
| 15 | let err = Error::new(ErrorKind::InvalidInput, Error::from_raw_os_error(code)); | |
| 21 | 16 | let expected = format!( |
| 22 | 17 | "Custom {{ \ |
| 23 | 18 | kind: InvalidInput, \ |
| ... | ... | @@ -70,10 +65,6 @@ fn test_os_packing() { |
| 70 | 65 | for code in -20..20 { |
| 71 | 66 | let e = Error::from_raw_os_error(code); |
| 72 | 67 | assert_eq!(e.raw_os_error(), Some(code)); |
| 73 | assert_matches!( | |
| 74 | e.repr.data(), | |
| 75 | ErrorData::Os(c) if c == code, | |
| 76 | ); | |
| 77 | 68 | } |
| 78 | 69 | } |
| 79 | 70 | |
| ... | ... | @@ -82,28 +73,17 @@ fn test_errorkind_packing() { |
| 82 | 73 | assert_eq!(Error::from(ErrorKind::NotFound).kind(), ErrorKind::NotFound); |
| 83 | 74 | assert_eq!(Error::from(ErrorKind::PermissionDenied).kind(), ErrorKind::PermissionDenied); |
| 84 | 75 | assert_eq!(Error::from(ErrorKind::Uncategorized).kind(), ErrorKind::Uncategorized); |
| 85 | // Check that the innards look like what we want. | |
| 86 | assert_matches!( | |
| 87 | Error::from(ErrorKind::OutOfMemory).repr.data(), | |
| 88 | ErrorData::Simple(ErrorKind::OutOfMemory), | |
| 89 | ); | |
| 90 | 76 | } |
| 91 | 77 | |
| 92 | 78 | #[test] |
| 93 | 79 | fn test_simple_message_packing() { |
| 94 | use super::ErrorKind::*; | |
| 95 | use super::SimpleMessage; | |
| 80 | use ErrorKind::*; | |
| 96 | 81 | macro_rules! check_simple_msg { |
| 97 | 82 | ($err:expr, $kind:ident, $msg:literal) => {{ |
| 98 | 83 | let e = &$err; |
| 99 | 84 | // Check that the public api is right. |
| 100 | 85 | assert_eq!(e.kind(), $kind); |
| 101 | 86 | assert!(format!("{e:?}").contains($msg)); |
| 102 | // and we got what we expected | |
| 103 | assert_matches!( | |
| 104 | e.repr.data(), | |
| 105 | ErrorData::SimpleMessage(SimpleMessage { kind: $kind, message: $msg }) | |
| 106 | ); | |
| 107 | 87 | }}; |
| 108 | 88 | } |
| 109 | 89 | |
| ... | ... | @@ -128,14 +108,11 @@ impl fmt::Display for Bojji { |
| 128 | 108 | |
| 129 | 109 | #[test] |
| 130 | 110 | fn test_custom_error_packing() { |
| 131 | use super::Custom; | |
| 132 | 111 | let test = Error::new(ErrorKind::Uncategorized, Bojji(true)); |
| 112 | assert_eq!(test.kind(), ErrorKind::Uncategorized); | |
| 133 | 113 | assert_matches!( |
| 134 | test.repr.data(), | |
| 135 | ErrorData::Custom(Custom { | |
| 136 | kind: ErrorKind::Uncategorized, | |
| 137 | error, | |
| 138 | }) if error.downcast_ref::<Bojji>().as_deref() == Some(&Bojji(true)), | |
| 114 | test.get_ref(), | |
| 115 | Some(error) if error.downcast_ref::<Bojji>().as_deref() == Some(&Bojji(true)), | |
| 139 | 116 | ); |
| 140 | 117 | } |
| 141 | 118 | |
| ... | ... | @@ -181,11 +158,11 @@ fn test_std_io_error_downcast() { |
| 181 | 158 | assert_eq!(kind, io_error.kind()); |
| 182 | 159 | |
| 183 | 160 | // Case 5: simple message |
| 184 | const SIMPLE_MESSAGE: SimpleMessage = | |
| 185 | SimpleMessage { kind: ErrorKind::Other, message: "simple message error test" }; | |
| 186 | let io_error = Error::from_static_message(&SIMPLE_MESSAGE); | |
| 161 | const KIND: ErrorKind = ErrorKind::Other; | |
| 162 | const MESSAGE: &str = "simple message error test"; | |
| 163 | let io_error = const_error!(KIND, MESSAGE); | |
| 187 | 164 | let io_error = io_error.downcast::<E>().unwrap_err(); |
| 188 | 165 | |
| 189 | assert_eq!(SIMPLE_MESSAGE.kind, io_error.kind()); | |
| 190 | assert_eq!(SIMPLE_MESSAGE.message, format!("{io_error}")); | |
| 166 | assert_eq!(KIND, io_error.kind()); | |
| 167 | assert_eq!(MESSAGE, format!("{io_error}")); | |
| 191 | 168 | } |
library/std/src/io/mod.rs+15-12| ... | ... | @@ -297,23 +297,27 @@ |
| 297 | 297 | #[cfg(test)] |
| 298 | 298 | mod tests; |
| 299 | 299 | |
| 300 | #[unstable(feature = "read_buf", issue = "78485")] | |
| 301 | pub use core::io::{BorrowedBuf, BorrowedCursor}; | |
| 302 | #[stable(feature = "rust1", since = "1.0.0")] | |
| 303 | pub use core::io::{Chain, Empty, Repeat, Sink, Take, empty, repeat, sink}; | |
| 304 | #[stable(feature = "iovec", since = "1.36.0")] | |
| 305 | pub use core::io::{IoSlice, IoSliceMut}; | |
| 306 | 300 | use core::slice::memchr; |
| 307 | 301 | |
| 308 | #[stable(feature = "bufwriter_into_parts", since = "1.56.0")] | |
| 309 | pub use self::buffered::WriterPanicked; | |
| 302 | use alloc_crate::io::OsFunctions; | |
| 310 | 303 | #[unstable(feature = "raw_os_error_ty", issue = "107792")] |
| 311 | pub use self::error::RawOsError; | |
| 304 | pub use alloc_crate::io::RawOsError; | |
| 312 | 305 | #[doc(hidden)] |
| 313 | 306 | #[unstable(feature = "io_const_error_internals", issue = "none")] |
| 314 | pub use self::error::SimpleMessage; | |
| 307 | pub use alloc_crate::io::SimpleMessage; | |
| 315 | 308 | #[unstable(feature = "io_const_error", issue = "133448")] |
| 316 | pub use self::error::const_error; | |
| 309 | pub use alloc_crate::io::const_error; | |
| 310 | #[unstable(feature = "read_buf", issue = "78485")] | |
| 311 | pub use alloc_crate::io::{BorrowedBuf, BorrowedCursor}; | |
| 312 | #[stable(feature = "rust1", since = "1.0.0")] | |
| 313 | pub use alloc_crate::io::{ | |
| 314 | Chain, Empty, Error, ErrorKind, Repeat, Result, Sink, Take, empty, repeat, sink, | |
| 315 | }; | |
| 316 | #[stable(feature = "iovec", since = "1.36.0")] | |
| 317 | pub use alloc_crate::io::{IoSlice, IoSliceMut}; | |
| 318 | ||
| 319 | #[stable(feature = "bufwriter_into_parts", since = "1.56.0")] | |
| 320 | pub use self::buffered::WriterPanicked; | |
| 317 | 321 | #[stable(feature = "anonymous_pipe", since = "1.87.0")] |
| 318 | 322 | pub use self::pipe::{PipeReader, PipeWriter, pipe}; |
| 319 | 323 | #[stable(feature = "is_terminal", since = "1.70.0")] |
| ... | ... | @@ -330,7 +334,6 @@ pub use self::{ |
| 330 | 334 | buffered::{BufReader, BufWriter, IntoInnerError, LineWriter}, |
| 331 | 335 | copy::copy, |
| 332 | 336 | cursor::Cursor, |
| 333 | error::{Error, ErrorKind, Result}, | |
| 334 | 337 | stdio::{Stderr, StderrLock, Stdin, StdinLock, Stdout, StdoutLock, stderr, stdin, stdout}, |
| 335 | 338 | }; |
| 336 | 339 | use crate::mem::MaybeUninit; |
library/std/src/lib.rs+1| ... | ... | @@ -390,6 +390,7 @@ |
| 390 | 390 | // |
| 391 | 391 | // Library features (alloc): |
| 392 | 392 | // tidy-alphabetical-start |
| 393 | #![feature(alloc_io)] | |
| 393 | 394 | #![feature(allocator_api)] |
| 394 | 395 | #![feature(clone_from_ref)] |
| 395 | 396 | #![feature(get_mut_unchecked)] |
library/std/src/os/unix/process.rs+2-2| ... | ... | @@ -102,8 +102,8 @@ pub impl(self) trait CommandExt { |
| 102 | 102 | /// [POSIX fork() specification]: |
| 103 | 103 | /// https://pubs.opengroup.org/onlinepubs/9699919799/functions/fork.html |
| 104 | 104 | /// [`std::env`]: mod@crate::env |
| 105 | /// [`Error::new`]: crate::io::Error::new | |
| 106 | /// [`Error::other`]: crate::io::Error::other | |
| 105 | /// [`Error::new`]: ../../../io/struct.Error.html#method.new | |
| 106 | /// [`Error::other`]: ../../../io/struct.Error.html#method.other | |
| 107 | 107 | #[stable(feature = "process_pre_exec", since = "1.34.0")] |
| 108 | 108 | unsafe fn pre_exec<F>(&mut self, f: F) -> &mut process::Command |
| 109 | 109 | where |
src/tools/linkchecker/main.rs+16| ... | ... | @@ -92,6 +92,22 @@ const LINKCHECK_EXCEPTIONS: &[(&str, &[&str])] = &[ |
| 92 | 92 | "core\\io\\slice::sort_by_key", |
| 93 | 93 | "#method.sort_by_cached_key" |
| 94 | 94 | ]), |
| 95 | ("alloc/io/struct.IoSlice.html", &[ | |
| 96 | "#method.to_ascii_uppercase", | |
| 97 | "#method.to_ascii_lowercase", | |
| 98 | "alloc/io/slice::sort_by_key", | |
| 99 | "alloc\\io\\slice::sort_by_key", | |
| 100 | "#method.sort_by_key", | |
| 101 | "#method.sort_by_cached_key" | |
| 102 | ]), | |
| 103 | ("alloc/io/struct.IoSliceMut.html", &[ | |
| 104 | "#method.to_ascii_uppercase", | |
| 105 | "#method.to_ascii_lowercase", | |
| 106 | "alloc/io/slice::sort_by_key", | |
| 107 | "alloc\\io\\slice::sort_by_key", | |
| 108 | "#method.sort_by_key", | |
| 109 | "#method.sort_by_cached_key" | |
| 110 | ]), | |
| 95 | 111 | ]; |
| 96 | 112 | |
| 97 | 113 | #[rustfmt::skip] |
tests/run-make/wasm-panic-small/rmake.rs+1-1| ... | ... | @@ -24,5 +24,5 @@ fn test(cfg: &str) { |
| 24 | 24 | |
| 25 | 25 | let bytes = rfs::read("foo.wasm"); |
| 26 | 26 | println!("{}", bytes.len()); |
| 27 | assert!(bytes.len() < 40_000, "bytes len was: {}", bytes.len()); | |
| 27 | assert!(bytes.len() < 45_000, "bytes len was: {}", bytes.len()); | |
| 28 | 28 | } |
tests/ui/binop/binary-op-not-allowed-issue-125631.stderr+3-3| ... | ... | @@ -12,7 +12,7 @@ note: an implementation of `PartialEq` might be missing for `T1` |
| 12 | 12 | LL | struct T1; |
| 13 | 13 | | ^^^^^^^^^ must implement `PartialEq` |
| 14 | 14 | note: `std::io::Error` does not implement `PartialEq` |
| 15 | --> $SRC_DIR/std/src/io/error.rs:LL:COL | |
| 15 | --> $SRC_DIR/core/src/io/error.rs:LL:COL | |
| 16 | 16 | | |
| 17 | 17 | = note: `std::io::Error` is defined in another crate |
| 18 | 18 | help: consider annotating `T1` with `#[derive(PartialEq)]` |
| ... | ... | @@ -34,7 +34,7 @@ note: `Thread` does not implement `PartialEq` |
| 34 | 34 | | |
| 35 | 35 | = note: `Thread` is defined in another crate |
| 36 | 36 | note: `std::io::Error` does not implement `PartialEq` |
| 37 | --> $SRC_DIR/std/src/io/error.rs:LL:COL | |
| 37 | --> $SRC_DIR/core/src/io/error.rs:LL:COL | |
| 38 | 38 | | |
| 39 | 39 | = note: `std::io::Error` is defined in another crate |
| 40 | 40 | |
| ... | ... | @@ -58,7 +58,7 @@ note: `Thread` does not implement `PartialEq` |
| 58 | 58 | | |
| 59 | 59 | = note: `Thread` is defined in another crate |
| 60 | 60 | note: `std::io::Error` does not implement `PartialEq` |
| 61 | --> $SRC_DIR/std/src/io/error.rs:LL:COL | |
| 61 | --> $SRC_DIR/core/src/io/error.rs:LL:COL | |
| 62 | 62 | | |
| 63 | 63 | = note: `std::io::Error` is defined in another crate |
| 64 | 64 | help: consider annotating `T1` with `#[derive(PartialEq)]` |