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]
72129pub 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" ) ]
85143impl 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 ) ]
193253pub 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) ,
0 commit comments