Skip to content

Commit a2430ef

Browse files
move std::io::Error to core
1 parent 130ff8c commit a2430ef

File tree

30 files changed

+2088
-577
lines changed

30 files changed

+2088
-577
lines changed

library/alloc/src/io/error.rs

+201
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
use crate::{alloc::Global, boxed::Box, string::String};
2+
use core::io::{
3+
const_io_error,
4+
error_internals::{AllocVTable, Custom, ErrorBox, ErrorString},
5+
Error, ErrorKind,
6+
};
7+
use core::{alloc::Allocator, error, ptr, result};
8+
9+
unsafe fn set_alloc_vtable() {
10+
static ALLOC_VTABLE: AllocVTable =
11+
AllocVTable { deallocate: |ptr, layout| unsafe { Global.deallocate(ptr, layout) } };
12+
unsafe {
13+
ALLOC_VTABLE.install();
14+
}
15+
}
16+
17+
fn into_error_box<T: ?Sized>(value: Box<T>) -> ErrorBox<T> {
18+
unsafe {
19+
set_alloc_vtable();
20+
ErrorBox::from_raw(Box::into_raw(value))
21+
}
22+
}
23+
24+
fn into_box<T: ?Sized>(v: ErrorBox<T>) -> Box<T> {
25+
unsafe { Box::from_raw(v.into_raw()) }
26+
}
27+
28+
impl From<String> for ErrorString {
29+
fn from(value: String) -> Self {
30+
unsafe {
31+
set_alloc_vtable();
32+
let (buf, length, capacity) = value.into_raw_parts();
33+
ErrorString::from_raw_parts(
34+
ErrorBox::from_raw(ptr::slice_from_raw_parts_mut(buf.cast(), capacity)).into(),
35+
length,
36+
)
37+
}
38+
}
39+
}
40+
41+
#[stable(feature = "rust1", since = "1.0.0")]
42+
impl From<crate::ffi::NulError> for Error {
43+
/// Converts a [`crate::ffi::NulError`] into a [`Error`].
44+
fn from(_: crate::ffi::NulError) -> Error {
45+
const_io_error!(ErrorKind::InvalidInput, "data provided contains a nul byte")
46+
}
47+
}
48+
49+
impl Error {
50+
/// Creates a new I/O error from a known kind of error as well as an
51+
/// arbitrary error payload.
52+
///
53+
/// This function is used to generically create I/O errors which do not
54+
/// originate from the OS itself. The `error` argument is an arbitrary
55+
/// payload which will be contained in this [`Error`].
56+
///
57+
/// Note that this function allocates memory on the heap.
58+
/// If no extra payload is required, use the `From` conversion from
59+
/// `ErrorKind`.
60+
///
61+
/// # Examples
62+
///
63+
/// ```
64+
/// use std::io::{Error, ErrorKind};
65+
///
66+
/// // errors can be created from strings
67+
/// let custom_error = Error::new(ErrorKind::Other, "oh no!");
68+
///
69+
/// // errors can also be created from other errors
70+
/// let custom_error2 = Error::new(ErrorKind::Interrupted, custom_error);
71+
///
72+
/// // creating an error without payload (and without memory allocation)
73+
/// let eof_error = Error::from(ErrorKind::UnexpectedEof);
74+
/// ```
75+
#[stable(feature = "rust1", since = "1.0.0")]
76+
#[rustc_allow_incoherent_impl]
77+
#[inline(never)]
78+
pub fn new<E>(kind: ErrorKind, error: E) -> Error
79+
where
80+
E: Into<Box<dyn error::Error + Send + Sync>>,
81+
{
82+
Self::_new(kind, error.into())
83+
}
84+
85+
/// Creates a new I/O error from an arbitrary error payload.
86+
///
87+
/// This function is used to generically create I/O errors which do not
88+
/// originate from the OS itself. It is a shortcut for [`Error::new`]
89+
/// with [`ErrorKind::Other`].
90+
///
91+
/// # Examples
92+
///
93+
/// ```
94+
/// use std::io::Error;
95+
///
96+
/// // errors can be created from strings
97+
/// let custom_error = Error::other("oh no!");
98+
///
99+
/// // errors can also be created from other errors
100+
/// let custom_error2 = Error::other(custom_error);
101+
/// ```
102+
#[stable(feature = "io_error_other", since = "CURRENT_RUSTC_VERSION")]
103+
#[rustc_allow_incoherent_impl]
104+
pub fn other<E>(error: E) -> Error
105+
where
106+
E: Into<Box<dyn error::Error + Send + Sync>>,
107+
{
108+
Self::_new(ErrorKind::Other, error.into())
109+
}
110+
111+
#[rustc_allow_incoherent_impl]
112+
fn _new(kind: ErrorKind, error: Box<dyn error::Error + Send + Sync>) -> Error {
113+
Error::_new_custom(into_error_box(Box::new(Custom { kind, error: into_error_box(error) })))
114+
}
115+
116+
/// Consumes the `Error`, returning its inner error (if any).
117+
///
118+
/// If this [`Error`] was constructed via [`new`] then this function will
119+
/// return [`Some`], otherwise it will return [`None`].
120+
///
121+
/// [`new`]: Error::new
122+
///
123+
/// # Examples
124+
///
125+
/// ```
126+
/// use std::io::{Error, ErrorKind};
127+
///
128+
/// fn print_error(err: Error) {
129+
/// if let Some(inner_err) = err.into_inner() {
130+
/// println!("Inner error: {inner_err}");
131+
/// } else {
132+
/// println!("No inner error");
133+
/// }
134+
/// }
135+
///
136+
/// fn main() {
137+
/// // Will print "No inner error".
138+
/// print_error(Error::last_os_error());
139+
/// // Will print "Inner error: ...".
140+
/// print_error(Error::new(ErrorKind::Other, "oh no!"));
141+
/// }
142+
/// ```
143+
#[stable(feature = "io_error_inner", since = "1.3.0")]
144+
#[must_use = "`self` will be dropped if the result is not used"]
145+
#[inline]
146+
#[rustc_allow_incoherent_impl]
147+
pub fn into_inner(self) -> Option<Box<dyn error::Error + Send + Sync>> {
148+
self.into_inner_impl().map(into_box)
149+
}
150+
151+
/// Attempt to downgrade the inner error to `E` if any.
152+
///
153+
/// If this [`Error`] was constructed via [`new`] then this function will
154+
/// attempt to perform downgrade on it, otherwise it will return [`Err`].
155+
///
156+
/// If downgrade succeeds, it will return [`Ok`], otherwise it will also
157+
/// return [`Err`].
158+
///
159+
/// [`new`]: Error::new
160+
///
161+
/// # Examples
162+
///
163+
/// ```
164+
/// # #![allow(dead_code)]
165+
/// #![feature(io_error_downcast)]
166+
///
167+
/// use std::fmt;
168+
/// use std::io;
169+
/// use std::error::Error;
170+
///
171+
/// #[derive(Debug)]
172+
/// enum E {
173+
/// Io(io::Error),
174+
/// SomeOtherVariant,
175+
/// }
176+
///
177+
/// impl fmt::Display for E {
178+
/// // ...
179+
/// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
180+
/// # todo!()
181+
/// # }
182+
/// }
183+
/// impl Error for E {}
184+
///
185+
/// impl From<io::Error> for E {
186+
/// fn from(err: io::Error) -> E {
187+
/// err.downcast::<E>()
188+
/// .map(|b| *b)
189+
/// .unwrap_or_else(E::Io)
190+
/// }
191+
/// }
192+
/// ```
193+
#[unstable(feature = "io_error_downcast", issue = "99262")]
194+
#[rustc_allow_incoherent_impl]
195+
pub fn downcast<E>(self) -> result::Result<Box<E>, Self>
196+
where
197+
E: error::Error + Send + Sync + 'static,
198+
{
199+
self.downcast_impl::<E>().map(|p| unsafe { Box::from_raw(p) })
200+
}
201+
}

library/alloc/src/io/mod.rs

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
//! Traits, helpers, and type definitions for core I/O functionality.
2+
3+
#![unstable(feature = "alloc_io", issue = "none")]
4+
5+
pub use core::io::*;
6+
7+
#[cfg(target_has_atomic_load_store = "ptr")]
8+
mod error;

library/alloc/src/lib.rs

+4
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,8 @@
121121
#![feature(const_size_of_val)]
122122
#![feature(const_waker)]
123123
#![feature(core_intrinsics)]
124+
#![feature(core_io)]
125+
#![feature(core_io_error_internals)]
124126
#![feature(core_panic)]
125127
#![feature(deprecated_suggestion)]
126128
#![feature(dispatch_from_dyn)]
@@ -177,6 +179,7 @@
177179
#![feature(associated_type_bounds)]
178180
#![feature(c_unwind)]
179181
#![feature(cfg_sanitize)]
182+
#![feature(cfg_target_has_atomic)]
180183
#![feature(const_mut_refs)]
181184
#![feature(const_precise_live_drops)]
182185
#![feature(const_ptr_write)]
@@ -246,6 +249,7 @@ pub mod collections;
246249
#[cfg(all(not(no_rc), not(no_sync), not(no_global_oom_handling)))]
247250
pub mod ffi;
248251
pub mod fmt;
252+
pub mod io;
249253
#[cfg(not(no_rc))]
250254
pub mod rc;
251255
pub mod slice;

library/alloc/tests/io.rs

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
mod error;

library/alloc/tests/io/tests.rs

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
use core::error;
2+
use core::fmt;
3+
use core::io::{Error, ErrorKind};
4+
5+
#[test]
6+
fn test_downcasting() {
7+
#[derive(Debug)]
8+
struct TestError;
9+
10+
impl fmt::Display for TestError {
11+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
12+
f.write_str("asdf")
13+
}
14+
}
15+
16+
impl error::Error for TestError {}
17+
18+
// we have to call all of these UFCS style right now since method
19+
// resolution won't implicitly drop the Send+Sync bounds
20+
let mut err = Error::new(ErrorKind::Other, TestError);
21+
assert!(err.get_ref().unwrap().is::<TestError>());
22+
assert_eq!("asdf", err.get_ref().unwrap().to_string());
23+
assert!(err.get_mut().unwrap().is::<TestError>());
24+
let extracted = err.into_inner().unwrap();
25+
extracted.downcast::<TestError>().unwrap();
26+
}

0 commit comments

Comments
 (0)