Skip to content

Commit d4ba730

Browse files
authored
Allow Error::raw_os_error to return non-i32 codes (rust-random#569)
This allows us to remove some UEFI-specific exceptions from the code. This PR only partially resolves rust-random#568 since we still use `NonZeroU32` on UEFI targets, but it should be sufficient to future-proof ourselves for the v0.3 release.
1 parent 3d53866 commit d4ba730

2 files changed

Lines changed: 28 additions & 18 deletions

File tree

src/error.rs

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,16 @@ extern crate std;
33

44
use core::{fmt, num::NonZeroU32};
55

6+
// This private alias mirrors `std::io::RawOsError`:
7+
// https://doc.rust-lang.org/std/io/type.RawOsError.html)
8+
cfg_if::cfg_if!(
9+
if #[cfg(target_os = "uefi")] {
10+
type RawOsError = usize;
11+
} else {
12+
type RawOsError = i32;
13+
}
14+
);
15+
616
/// A small and `no_std` compatible error type
717
///
818
/// The [`Error::raw_os_error()`] will indicate if the error is from the OS, and
@@ -57,20 +67,25 @@ impl Error {
5767
/// Extract the raw OS error code (if this error came from the OS)
5868
///
5969
/// This method is identical to [`std::io::Error::raw_os_error()`][1], except
60-
/// that it works in `no_std` contexts. If this method returns `None`, the
61-
/// error value can still be formatted via the `Display` implementation.
70+
/// that it works in `no_std` contexts. On most targets this method returns
71+
/// `Option<i32>`, but some platforms (e.g. UEFI) may use a different primitive
72+
/// type like `usize`. Consult with the [`RawOsError`] docs for more information.
73+
///
74+
/// If this method returns `None`, the error value can still be formatted via
75+
/// the `Display` implementation.
6276
///
6377
/// [1]: https://doc.rust-lang.org/std/io/struct.Error.html#method.raw_os_error
78+
/// [`RawOsError`]: https://doc.rust-lang.org/std/io/type.RawOsError.html
6479
#[inline]
65-
pub fn raw_os_error(self) -> Option<i32> {
66-
i32::try_from(self.0.get()).ok().map(|errno| {
67-
// On SOLID, negate the error code again to obtain the original error code.
68-
if cfg!(target_os = "solid_asp3") {
69-
-errno
70-
} else {
71-
errno
72-
}
73-
})
80+
pub fn raw_os_error(self) -> Option<RawOsError> {
81+
let code = self.0.get();
82+
if code >= Self::INTERNAL_START {
83+
return None;
84+
}
85+
let errno = RawOsError::try_from(code).ok()?;
86+
#[cfg(target_os = "solid_asp3")]
87+
let errno = -errno;
88+
Some(errno)
7489
}
7590

7691
/// Creates a new instance of an `Error` from a particular custom error code.
@@ -134,7 +149,7 @@ impl fmt::Debug for Error {
134149
let mut dbg = f.debug_struct("Error");
135150
if let Some(errno) = self.raw_os_error() {
136151
dbg.field("os_error", &errno);
137-
#[cfg(all(feature = "std", not(target_os = "uefi")))]
152+
#[cfg(feature = "std")]
138153
dbg.field("description", &std::io::Error::from_raw_os_error(errno));
139154
} else if let Some(desc) = self.internal_desc() {
140155
dbg.field("internal_code", &self.0.get());
@@ -150,7 +165,7 @@ impl fmt::Display for Error {
150165
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
151166
if let Some(errno) = self.raw_os_error() {
152167
cfg_if! {
153-
if #[cfg(all(feature = "std", not(target_os = "uefi")))] {
168+
if #[cfg(feature = "std")] {
154169
std::io::Error::from_raw_os_error(errno).fmt(f)
155170
} else {
156171
write!(f, "OS Error: {}", errno)

src/error_std_impls.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,10 @@ use std::io;
55

66
impl From<Error> for io::Error {
77
fn from(err: Error) -> Self {
8-
#[cfg(not(target_os = "uefi"))]
98
match err.raw_os_error() {
109
Some(errno) => io::Error::from_raw_os_error(errno),
1110
None => io::Error::new(io::ErrorKind::Other, err),
1211
}
13-
#[cfg(target_os = "uefi")]
14-
{
15-
io::Error::new(io::ErrorKind::Other, err)
16-
}
1712
}
1813
}
1914

0 commit comments

Comments
 (0)