Skip to content

Commit 96864eb

Browse files
committed
WIP: Smear std::io::Error across core and alloc
1 parent 7653e5e commit 96864eb

17 files changed

Lines changed: 1160 additions & 785 deletions

File tree

library/alloc/src/io/error.rs

Lines changed: 271 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,271 @@
1+
#[unstable(feature = "raw_os_error_ty", issue = "107792")]
2+
pub use core::io::RawOsError;
3+
#[unstable(feature = "io_const_error_internals", issue = "none")]
4+
pub use core::io::SimpleMessage;
5+
#[unstable(feature = "io_const_error", issue = "133448")]
6+
pub use core::io::const_error;
7+
#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
8+
pub use core::io::{Custom, CustomOwner, OsFunctions};
9+
#[unstable(feature = "alloc_io", issue = "154046")]
10+
pub use core::io::{Error, ErrorKind, Result};
11+
use core::{error, result};
12+
13+
use crate::boxed::Box;
14+
15+
impl Error {
16+
/// Creates a new I/O error from a known kind of error as well as an
17+
/// arbitrary error payload.
18+
///
19+
/// This function is used to generically create I/O errors which do not
20+
/// originate from the OS itself. The `error` argument is an arbitrary
21+
/// payload which will be contained in this [`Error`].
22+
///
23+
/// Note that this function allocates memory on the heap.
24+
/// If no extra payload is required, use the `From` conversion from
25+
/// `ErrorKind`.
26+
///
27+
/// # Examples
28+
///
29+
/// ```
30+
/// use std::io::{Error, ErrorKind};
31+
///
32+
/// // errors can be created from strings
33+
/// let custom_error = Error::new(ErrorKind::Other, "oh no!");
34+
///
35+
/// // errors can also be created from other errors
36+
/// let custom_error2 = Error::new(ErrorKind::Interrupted, custom_error);
37+
///
38+
/// // creating an error without payload (and without memory allocation)
39+
/// let eof_error = Error::from(ErrorKind::UnexpectedEof);
40+
/// ```
41+
#[stable(feature = "rust1", since = "1.0.0")]
42+
#[cfg_attr(not(test), rustc_diagnostic_item = "io_error_new")]
43+
#[inline(never)]
44+
#[rustc_allow_incoherent_impl]
45+
pub fn new<E>(kind: ErrorKind, error: E) -> Error
46+
where
47+
E: Into<Box<dyn error::Error + Send + Sync>>,
48+
{
49+
error_from_box(kind, error.into())
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+
#[stable(feature = "io_error_other", since = "1.74.0")]
72+
#[rustc_allow_incoherent_impl]
73+
pub fn other<E>(error: E) -> Error
74+
where
75+
E: Into<Box<dyn error::Error + Send + Sync>>,
76+
{
77+
error_from_box(ErrorKind::Other, error.into())
78+
}
79+
80+
/// Consumes the `Error`, returning its inner error (if any).
81+
///
82+
/// If this [`Error`] was constructed via [`new`][new] or [`other`][other],
83+
/// then this function will return [`Some`],
84+
/// otherwise it will return [`None`].
85+
///
86+
/// [new]: struct.Error.html#method.new
87+
/// [other]: struct.Error.html#method.other
88+
///
89+
/// # Examples
90+
///
91+
/// ```
92+
/// use std::io::{Error, ErrorKind};
93+
///
94+
/// fn print_error(err: Error) {
95+
/// if let Some(inner_err) = err.into_inner() {
96+
/// println!("Inner error: {inner_err}");
97+
/// } else {
98+
/// println!("No inner error");
99+
/// }
100+
/// }
101+
///
102+
/// fn main() {
103+
/// // Will print "No inner error".
104+
/// print_error(Error::last_os_error());
105+
/// // Will print "Inner error: ...".
106+
/// print_error(Error::new(ErrorKind::Other, "oh no!"));
107+
/// }
108+
/// ```
109+
#[stable(feature = "io_error_inner", since = "1.3.0")]
110+
#[must_use = "`self` will be dropped if the result is not used"]
111+
#[inline]
112+
#[rustc_allow_incoherent_impl]
113+
pub fn into_inner(self) -> Option<Box<dyn error::Error + Send + Sync>> {
114+
let custom_owner = self.into_custom_owner().ok()?;
115+
116+
let ptr = custom_owner.into_raw().as_ptr();
117+
118+
// SAFETY:
119+
// `Error` can only contain a `CustomOwner` if it was constructed using `Box::into_raw`.
120+
let custom = unsafe { Box::<Custom>::from_raw(ptr) };
121+
122+
let ptr = custom.into_raw().as_ptr();
123+
124+
// SAFETY:
125+
// Any `CustomOwner` from an `Error` was constructed by the `alloc` crate
126+
// to contain a `Custom` which itself was constructed with `Box::into_raw`.
127+
Some(unsafe { Box::from_raw(ptr) })
128+
}
129+
130+
/// Attempts to downcast the custom boxed error to `E`.
131+
///
132+
/// If this [`Error`] contains a custom boxed error,
133+
/// then it would attempt downcasting on the boxed error,
134+
/// otherwise it will return [`Err`].
135+
///
136+
/// If the custom boxed error has the same type as `E`, it will return [`Ok`],
137+
/// otherwise it will also return [`Err`].
138+
///
139+
/// This method is meant to be a convenience routine for calling
140+
/// `Box<dyn Error + Sync + Send>::downcast` on the custom boxed error, returned by
141+
/// [`Error::into_inner`][into_inner].
142+
///
143+
/// [into_inner]: struct.Error.html#method.into_inner
144+
///
145+
/// # Examples
146+
///
147+
/// ```
148+
/// use std::fmt;
149+
/// use std::io;
150+
/// use std::error::Error;
151+
///
152+
/// #[derive(Debug)]
153+
/// enum E {
154+
/// Io(io::Error),
155+
/// SomeOtherVariant,
156+
/// }
157+
///
158+
/// impl fmt::Display for E {
159+
/// // ...
160+
/// # fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
161+
/// # todo!()
162+
/// # }
163+
/// }
164+
/// impl Error for E {}
165+
///
166+
/// impl From<io::Error> for E {
167+
/// fn from(err: io::Error) -> E {
168+
/// err.downcast::<E>()
169+
/// .unwrap_or_else(E::Io)
170+
/// }
171+
/// }
172+
///
173+
/// impl From<E> for io::Error {
174+
/// fn from(err: E) -> io::Error {
175+
/// match err {
176+
/// E::Io(io_error) => io_error,
177+
/// e => io::Error::new(io::ErrorKind::Other, e),
178+
/// }
179+
/// }
180+
/// }
181+
///
182+
/// # fn main() {
183+
/// let e = E::SomeOtherVariant;
184+
/// // Convert it to an io::Error
185+
/// let io_error = io::Error::from(e);
186+
/// // Cast it back to the original variant
187+
/// let e = E::from(io_error);
188+
/// assert!(matches!(e, E::SomeOtherVariant));
189+
///
190+
/// let io_error = io::Error::from(io::ErrorKind::AlreadyExists);
191+
/// // Convert it to E
192+
/// let e = E::from(io_error);
193+
/// // Cast it back to the original variant
194+
/// let io_error = io::Error::from(e);
195+
/// assert_eq!(io_error.kind(), io::ErrorKind::AlreadyExists);
196+
/// assert!(io_error.get_ref().is_none());
197+
/// assert!(io_error.raw_os_error().is_none());
198+
/// # }
199+
/// ```
200+
#[stable(feature = "io_error_downcast", since = "1.79.0")]
201+
#[rustc_allow_incoherent_impl]
202+
pub fn downcast<E>(self) -> result::Result<E, Self>
203+
where
204+
E: error::Error + Send + Sync + 'static,
205+
{
206+
if let Some(e) = self.get_ref()
207+
&& e.is::<E>()
208+
{
209+
if let Some(b) = self.into_inner()
210+
&& let Ok(err) = b.downcast::<E>()
211+
{
212+
Ok(*err)
213+
} else {
214+
// Safety: We have just checked that the condition is true
215+
unsafe { core::hint::unreachable_unchecked() }
216+
}
217+
} else {
218+
Err(self)
219+
}
220+
}
221+
}
222+
223+
#[stable(feature = "rust1", since = "1.0.0")]
224+
impl From<crate::ffi::NulError> for Error {
225+
/// Converts a [`crate::ffi::NulError`] into a [`Error`].
226+
fn from(_: crate::ffi::NulError) -> Error {
227+
const_error!(ErrorKind::InvalidInput, "data provided contains a nul byte")
228+
}
229+
}
230+
231+
#[stable(feature = "io_error_from_try_reserve", since = "1.78.0")]
232+
impl From<crate::collections::TryReserveError> for Error {
233+
/// Converts `TryReserveError` to an error with [`ErrorKind::OutOfMemory`].
234+
///
235+
/// `TryReserveError` won't be available as the error `source()`,
236+
/// but this may change in the future.
237+
fn from(_: crate::collections::TryReserveError) -> Error {
238+
// ErrorData::Custom allocates, which isn't great for handling OOM errors.
239+
ErrorKind::OutOfMemory.into()
240+
}
241+
}
242+
243+
fn error_from_box(kind: ErrorKind, error: Box<dyn error::Error + Send + Sync>) -> Error {
244+
/// # Safety
245+
///
246+
/// `ptr` must be valid to pass into `Box::from_raw`.
247+
unsafe fn drop_box_raw<T: ?Sized>(ptr: *mut T) {
248+
// SAFETY
249+
// Caller ensures `ptr` is valid to pass into `Box::from_raw`.
250+
drop(unsafe { Box::from_raw(ptr) })
251+
}
252+
253+
// SAFETY: the pointer returned by Box::into_raw is non-null.
254+
let error = unsafe { core::ptr::NonNull::new_unchecked(Box::into_raw(error)) };
255+
256+
// SAFETY:
257+
// * `error` is valid up to a static lifetime, and owns its pointee.
258+
// * `drop_box_raw` is safe to call for the pointer `error` exactly once.
259+
// * `drop_box_raw` is safe to call on a pointer to this instance of `Custom`,
260+
// and will be stored in a `CustomOwner`.
261+
let custom = unsafe { Custom::from_raw(kind, error, drop_box_raw, drop_box_raw) };
262+
263+
// SAFETY: the pointer returned by Box::into_raw is non-null.
264+
let custom = unsafe { core::ptr::NonNull::new_unchecked(Box::into_raw(Box::new(custom))) };
265+
266+
// SAFETY: the `outer_drop` provided to `custom` is valid for itself.
267+
let custom_owner = unsafe { CustomOwner::from_raw(custom) };
268+
269+
// SAFETY: `custom_owner` has bee constructed from a `Box` from the `alloc` crate.
270+
unsafe { Error::from_custom_owner(custom_owner) }
271+
}

library/alloc/src/io/mod.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//! Traits, helpers, and type definitions for core I/O functionality.
2+
3+
mod error;
4+
5+
#[unstable(feature = "core_io_borrowed_buf", issue = "117693")]
6+
pub use core::io::{BorrowedBuf, BorrowedCursor};
7+
8+
#[unstable(feature = "raw_os_error_ty", issue = "107792")]
9+
pub use self::error::RawOsError;
10+
#[unstable(feature = "io_const_error_internals", issue = "none")]
11+
pub use self::error::SimpleMessage;
12+
#[unstable(feature = "io_const_error", issue = "133448")]
13+
pub use self::error::const_error;
14+
#[unstable(feature = "core_io_internals", reason = "exposed only for libstd", issue = "none")]
15+
pub use self::error::{Custom, CustomOwner, OsFunctions};
16+
#[unstable(feature = "alloc_io", issue = "154046")]
17+
pub use self::error::{Error, ErrorKind, Result};

library/alloc/src/lib.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,9 @@
111111
#![feature(const_try)]
112112
#![feature(copied_into_inner)]
113113
#![feature(core_intrinsics)]
114+
#![feature(core_io)]
115+
#![feature(core_io_borrowed_buf)]
116+
#![feature(core_io_internals)]
114117
#![feature(deprecated_suggestion)]
115118
#![feature(deref_pure_trait)]
116119
#![feature(diagnostic_on_move)]
@@ -128,6 +131,8 @@
128131
#![feature(generic_atomic)]
129132
#![feature(hasher_prefixfree_extras)]
130133
#![feature(inplace_iteration)]
134+
#![feature(io_const_error)]
135+
#![feature(io_const_error_internals)]
131136
#![feature(iter_advance_by)]
132137
#![feature(iter_next_chunk)]
133138
#![feature(layout_for_ptr)]
@@ -141,6 +146,7 @@
141146
#![feature(ptr_alignment_type)]
142147
#![feature(ptr_internals)]
143148
#![feature(ptr_metadata)]
149+
#![feature(raw_os_error_ty)]
144150
#![feature(rev_into_inner)]
145151
#![feature(set_ptr_value)]
146152
#![feature(sized_type_properties)]
@@ -228,6 +234,8 @@ pub mod collections;
228234
pub mod ffi;
229235
pub mod fmt;
230236
pub mod intrinsics;
237+
#[unstable(feature = "alloc_io", issue = "154046")]
238+
pub mod io;
231239
#[cfg(not(no_rc))]
232240
pub mod rc;
233241
pub mod slice;

0 commit comments

Comments
 (0)