Skip to content

Commit 98976c4

Browse files
committed
Move io::Error to alloc
1 parent 59fd4ef commit 98976c4

11 files changed

Lines changed: 479 additions & 177 deletions

File tree

Lines changed: 104 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
#[cfg(test)]
2-
mod tests;
1+
use core::{error, fmt, result};
2+
3+
use crate::boxed::Box;
34

45
// On 64-bit platforms, `io::Error` may use a bit-packed representation to
56
// reduce size. However, this representation assumes that error codes are
@@ -8,17 +9,72 @@ mod tests;
89
// This assumption is invalid on 64-bit UEFI, where error codes are 64-bit.
910
// Therefore, the packed representation is explicitly disabled for UEFI
1011
// targets, and the unpacked representation must be used instead.
11-
#[cfg(all(target_pointer_width = "64", not(target_os = "uefi")))]
12-
mod repr_bitpacked;
13-
#[cfg(all(target_pointer_width = "64", not(target_os = "uefi")))]
14-
use repr_bitpacked::Repr;
1512

16-
#[cfg(any(not(target_pointer_width = "64"), target_os = "uefi"))]
17-
mod repr_unpacked;
18-
#[cfg(any(not(target_pointer_width = "64"), target_os = "uefi"))]
19-
use repr_unpacked::Repr;
13+
cfg_select! {
14+
all(target_pointer_width = "64", not(target_os = "uefi")) => {
15+
use repr_bitpacked::Repr;
16+
mod repr_bitpacked;
17+
}
18+
_ => {
19+
mod repr_unpacked;
20+
use repr_unpacked::Repr;
21+
}
22+
}
23+
24+
pub(super) mod os {
25+
//! OS-dependent functions
26+
//!
27+
//! `Error` needs OS functionnalities to work interpret raw OS errors, but
28+
//! we can't link to anythink here in `alloc`. Therefore, we restrict
29+
//! creation of `Error` from raw OS errors in `std`, and require providing
30+
//! a vtable of operations when creating one.
31+
32+
// FIXME: replace this with externally implementable items once they are more stable
33+
34+
use core::sync::atomic;
35+
36+
use crate::io::{ErrorKind, RawOsError};
37+
use crate::string::String;
38+
39+
#[doc(hidden)]
40+
#[derive(Debug)]
41+
pub struct OsFunctions {
42+
pub error_string: fn(_: RawOsError) -> String,
43+
pub decode_error_kind: fn(_: RawOsError) -> ErrorKind,
44+
pub is_interrupted: fn(_: RawOsError) -> bool,
45+
}
46+
47+
const DEFAULT_FUNCTIONS: &'static OsFunctions = &OsFunctions {
48+
error_string: |_| String::from("success"),
49+
decode_error_kind: |_| ErrorKind::Uncategorized,
50+
is_interrupted: |_| false,
51+
};
52+
static OS_FUNCTIONS: atomic::AtomicPtr<OsFunctions> =
53+
atomic::AtomicPtr::new(DEFAULT_FUNCTIONS as *const _ as *mut _);
54+
55+
#[inline]
56+
pub(super) fn set_functions(f: &'static OsFunctions) {
57+
OS_FUNCTIONS.store(f as *const _ as *mut _, atomic::Ordering::Relaxed);
58+
}
59+
60+
#[inline]
61+
pub(super) fn error_string(errno: RawOsError) -> String {
62+
let f = unsafe { &*OS_FUNCTIONS.load(atomic::Ordering::Relaxed) };
63+
(f.error_string)(errno)
64+
}
65+
66+
#[inline]
67+
pub(super) fn decode_error_kind(errno: RawOsError) -> ErrorKind {
68+
let f = unsafe { &*OS_FUNCTIONS.load(atomic::Ordering::Relaxed) };
69+
(f.decode_error_kind)(errno)
70+
}
2071

21-
use crate::{error, fmt, result, sys};
72+
#[inline]
73+
pub(super) fn is_interrupted(errno: RawOsError) -> bool {
74+
let f = unsafe { &*OS_FUNCTIONS.load(atomic::Ordering::Relaxed) };
75+
(f.is_interrupted)(errno)
76+
}
77+
}
2278

2379
/// A specialized [`Result`] type for I/O operations.
2480
///
@@ -69,6 +125,7 @@ pub type Result<T> = result::Result<T, Error>;
69125
/// [`Write`]: crate::io::Write
70126
/// [`Seek`]: crate::io::Seek
71127
#[stable(feature = "rust1", since = "1.0.0")]
128+
#[rustc_has_incoherent_inherent_impls]
72129
pub struct Error {
73130
repr: Repr,
74131
}
@@ -81,47 +138,48 @@ impl fmt::Debug for Error {
81138
}
82139

83140
/// Common errors constants for use in std
84-
#[allow(dead_code)]
141+
#[doc(hidden)]
142+
#[unstable(feature = "io_error_internals", issue = "none")]
85143
impl Error {
86-
pub(crate) const INVALID_UTF8: Self =
144+
pub const INVALID_UTF8: Self =
87145
const_error!(ErrorKind::InvalidData, "stream did not contain valid UTF-8");
88146

89-
pub(crate) const READ_EXACT_EOF: Self =
147+
pub const READ_EXACT_EOF: Self =
90148
const_error!(ErrorKind::UnexpectedEof, "failed to fill whole buffer");
91149

92-
pub(crate) const UNKNOWN_THREAD_COUNT: Self = const_error!(
150+
pub const UNKNOWN_THREAD_COUNT: Self = const_error!(
93151
ErrorKind::NotFound,
94152
"the number of hardware threads is not known for the target platform",
95153
);
96154

97-
pub(crate) const UNSUPPORTED_PLATFORM: Self =
155+
pub const UNSUPPORTED_PLATFORM: Self =
98156
const_error!(ErrorKind::Unsupported, "operation not supported on this platform");
99157

100-
pub(crate) const WRITE_ALL_EOF: Self =
158+
pub const WRITE_ALL_EOF: Self =
101159
const_error!(ErrorKind::WriteZero, "failed to write whole buffer");
102160

103-
pub(crate) const ZERO_TIMEOUT: Self =
161+
pub const ZERO_TIMEOUT: Self =
104162
const_error!(ErrorKind::InvalidInput, "cannot set a 0 duration timeout");
105163

106-
pub(crate) const NO_ADDRESSES: Self =
164+
pub const NO_ADDRESSES: Self =
107165
const_error!(ErrorKind::InvalidInput, "could not resolve to any addresses");
108166
}
109167

110168
#[stable(feature = "rust1", since = "1.0.0")]
111-
impl From<alloc::ffi::NulError> for Error {
112-
/// Converts a [`alloc::ffi::NulError`] into a [`Error`].
113-
fn from(_: alloc::ffi::NulError) -> Error {
169+
impl From<crate::ffi::NulError> for Error {
170+
/// Converts a [`crate::ffi::NulError`] into a [`Error`].
171+
fn from(_: crate::ffi::NulError) -> Error {
114172
const_error!(ErrorKind::InvalidInput, "data provided contains a nul byte")
115173
}
116174
}
117175

118176
#[stable(feature = "io_error_from_try_reserve", since = "1.78.0")]
119-
impl From<alloc::collections::TryReserveError> for Error {
177+
impl From<crate::collections::TryReserveError> for Error {
120178
/// Converts `TryReserveError` to an error with [`ErrorKind::OutOfMemory`].
121179
///
122180
/// `TryReserveError` won't be available as the error `source()`,
123181
/// but this may change in the future.
124-
fn from(_: alloc::collections::TryReserveError) -> Error {
182+
fn from(_: crate::collections::TryReserveError) -> Error {
125183
// ErrorData::Custom allocates, which isn't great for handling OOM errors.
126184
ErrorKind::OutOfMemory.into()
127185
}
@@ -145,8 +203,10 @@ enum ErrorData<C> {
145203
/// portability.
146204
///
147205
/// [`into`]: Into::into
148-
#[unstable(feature = "raw_os_error_ty", issue = "107792")]
149-
pub type RawOsError = sys::io::RawOsError;
206+
pub type RawOsError = cfg_select! {
207+
target_os = "uefi" => usize,
208+
_ => i32,
209+
};
150210

151211
// `#[repr(align(4))]` is probably redundant, it should have that value or
152212
// higher already. We include it just because repr_bitpacked.rs's encoding
@@ -189,9 +249,9 @@ pub struct SimpleMessage {
189249
/// ```
190250
#[rustc_macro_transparency = "semiopaque"]
191251
#[unstable(feature = "io_const_error", issue = "133448")]
192-
#[allow_internal_unstable(hint_must_use, io_const_error_internals)]
252+
#[allow_internal_unstable(alloc_io, hint_must_use, io_const_error_internals, liballoc_internals)]
193253
pub macro const_error($kind:expr, $message:expr $(,)?) {
194-
$crate::hint::must_use($crate::io::Error::from_static_message(
254+
$crate::__export::must_use($crate::io::Error::from_static_message(
195255
const { &$crate::io::SimpleMessage { kind: $kind, message: $message } },
196256
))
197257
}
@@ -628,99 +688,20 @@ impl Error {
628688
Self { repr: Repr::new_simple_message(msg) }
629689
}
630690

631-
/// Returns an error representing the last OS error which occurred.
632-
///
633-
/// This function reads the value of `errno` for the target platform (e.g.
634-
/// `GetLastError` on Windows) and will return a corresponding instance of
635-
/// [`Error`] for the error code.
636-
///
637-
/// This should be called immediately after a call to a platform function,
638-
/// otherwise the state of the error value is indeterminate. In particular,
639-
/// other standard library functions may call platform functions that may
640-
/// (or may not) reset the error value even if they succeed.
641-
///
642-
/// # Examples
643-
///
644-
/// ```
645-
/// use std::io::Error;
646-
///
647-
/// let os_error = Error::last_os_error();
648-
/// println!("last OS error: {os_error:?}");
649-
/// ```
650-
#[stable(feature = "rust1", since = "1.0.0")]
651-
#[doc(alias = "GetLastError")]
652-
#[doc(alias = "errno")]
653-
#[must_use]
691+
#[unstable(feature = "io_error_internals", issue = "none")]
654692
#[inline]
655-
pub fn last_os_error() -> Error {
656-
Error::from_raw_os_error(sys::io::errno())
657-
}
658-
659-
/// Creates a new instance of an [`Error`] from a particular OS error code.
660-
///
661-
/// # Examples
662-
///
663-
/// On Linux:
664-
///
665-
/// ```
666-
/// # if cfg!(target_os = "linux") {
667-
/// use std::io;
668-
///
669-
/// let error = io::Error::from_raw_os_error(22);
670-
/// assert_eq!(error.kind(), io::ErrorKind::InvalidInput);
671-
/// # }
672-
/// ```
673-
///
674-
/// On Windows:
675-
///
676-
/// ```
677-
/// # if cfg!(windows) {
678-
/// use std::io;
679-
///
680-
/// let error = io::Error::from_raw_os_error(10022);
681-
/// assert_eq!(error.kind(), io::ErrorKind::InvalidInput);
682-
/// # }
683-
/// ```
684-
#[stable(feature = "rust1", since = "1.0.0")]
685693
#[must_use]
686-
#[inline]
687-
pub fn from_raw_os_error(code: RawOsError) -> Error {
694+
#[doc(hidden)]
695+
pub fn _from_raw_os_error(code: RawOsError, os: &'static os::OsFunctions) -> Error {
696+
os::set_functions(os);
688697
Error { repr: Repr::new_os(code) }
689698
}
690699

691-
/// Returns the OS error that this error represents (if any).
692-
///
693-
/// If this [`Error`] was constructed via [`last_os_error`] or
694-
/// [`from_raw_os_error`], then this function will return [`Some`], otherwise
695-
/// it will return [`None`].
696-
///
697-
/// [`last_os_error`]: Error::last_os_error
698-
/// [`from_raw_os_error`]: Error::from_raw_os_error
699-
///
700-
/// # Examples
701-
///
702-
/// ```
703-
/// use std::io::{Error, ErrorKind};
704-
///
705-
/// fn print_os_error(err: &Error) {
706-
/// if let Some(raw_os_err) = err.raw_os_error() {
707-
/// println!("raw OS error: {raw_os_err:?}");
708-
/// } else {
709-
/// println!("Not an OS error");
710-
/// }
711-
/// }
712-
///
713-
/// fn main() {
714-
/// // Will print "raw OS error: ...".
715-
/// print_os_error(&Error::last_os_error());
716-
/// // Will print "Not an OS error".
717-
/// print_os_error(&Error::new(ErrorKind::Other, "oh no!"));
718-
/// }
719-
/// ```
720-
#[stable(feature = "rust1", since = "1.0.0")]
700+
#[unstable(feature = "io_error_internals", issue = "none")]
721701
#[must_use]
722702
#[inline]
723-
pub fn raw_os_error(&self) -> Option<RawOsError> {
703+
#[doc(hidden)]
704+
pub fn _raw_os_error(&self) -> Option<RawOsError> {
724705
match self.repr.data() {
725706
ErrorData::Os(i) => Some(i),
726707
ErrorData::Custom(..) => None,
@@ -966,7 +947,7 @@ impl Error {
966947
Ok(*err)
967948
} else {
968949
// Safety: We have just checked that the condition is true
969-
unsafe { crate::hint::unreachable_unchecked() }
950+
unsafe { core::hint::unreachable_unchecked() }
970951
}
971952
} else {
972953
Err(self)
@@ -1004,17 +985,19 @@ impl Error {
1004985
#[inline]
1005986
pub fn kind(&self) -> ErrorKind {
1006987
match self.repr.data() {
1007-
ErrorData::Os(code) => sys::io::decode_error_kind(code),
988+
ErrorData::Os(code) => os::decode_error_kind(code),
1008989
ErrorData::Custom(c) => c.kind,
1009990
ErrorData::Simple(kind) => kind,
1010991
ErrorData::SimpleMessage(m) => m.kind,
1011992
}
1012993
}
1013994

995+
#[unstable(feature = "io_error_internals", issue = "none")]
996+
#[doc(hidden)]
1014997
#[inline]
1015-
pub(crate) fn is_interrupted(&self) -> bool {
998+
pub fn is_interrupted(&self) -> bool {
1016999
match self.repr.data() {
1017-
ErrorData::Os(code) => sys::io::is_interrupted(code),
1000+
ErrorData::Os(code) => os::is_interrupted(code),
10181001
ErrorData::Custom(c) => c.kind == ErrorKind::Interrupted,
10191002
ErrorData::Simple(kind) => kind == ErrorKind::Interrupted,
10201003
ErrorData::SimpleMessage(m) => m.kind == ErrorKind::Interrupted,
@@ -1028,8 +1011,8 @@ impl fmt::Debug for Repr {
10281011
ErrorData::Os(code) => fmt
10291012
.debug_struct("Os")
10301013
.field("code", &code)
1031-
.field("kind", &sys::io::decode_error_kind(code))
1032-
.field("message", &sys::io::error_string(code))
1014+
.field("kind", &os::decode_error_kind(code))
1015+
.field("message", &os::error_string(code))
10331016
.finish(),
10341017
ErrorData::Custom(c) => fmt::Debug::fmt(&c, fmt),
10351018
ErrorData::Simple(kind) => fmt.debug_tuple("Kind").field(&kind).finish(),
@@ -1047,7 +1030,7 @@ impl fmt::Display for Error {
10471030
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
10481031
match self.repr.data() {
10491032
ErrorData::Os(code) => {
1050-
let detail = sys::io::error_string(code);
1033+
let detail = os::error_string(code);
10511034
write!(fmt, "{detail} (os error {code})")
10521035
}
10531036
ErrorData::Custom(ref c) => c.error.fmt(fmt),

library/std/src/io/error/repr_bitpacked.rs renamed to library/alloc/src/io/error/repr_bitpacked.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ use core::num::NonZeroUsize;
107107
use core::ptr::NonNull;
108108

109109
use super::{Custom, ErrorData, ErrorKind, RawOsError, SimpleMessage};
110+
use crate::boxed::Box;
110111

111112
// The 2 least-significant bits are used as tag.
112113
const TAG_MASK: usize = 0b11;

library/std/src/io/error/repr_unpacked.rs renamed to library/alloc/src/io/error/repr_unpacked.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
//! would have no benefit.
44
55
use super::{Custom, ErrorData, ErrorKind, RawOsError, SimpleMessage};
6+
use crate::boxed::Box;
67

78
type Inner = ErrorData<Box<Custom>>;
89

0 commit comments

Comments
 (0)